Есть ли функция для простого создания суррогатного ключа в Snowflake?

#sql #join #snowflake-cloud-data-platform #surrogate-key

#sql #Присоединиться #snowflake-cloud-data-platform #суррогатный ключ

Вопрос:

Есть ли простой / эффективный способ создания суррогатных ключей в Snowflake?

введите описание изображения здесь

Представьте, что этот набор данных будет выбран в таблице, во время вставки добавляется столбец battery_id, который представляет собой столбец battery_uuid, сопоставленный с суррогатным ключом. В данном случае конкретный случай, который может стать, например, [1,1,2,1,1,2,3] . Последовательности в Snowflake не имеют такой функциональности, потому что это становится, например, [1,2,3,4,5,6,7] . Предпочтительнее, если это сопоставление выполняется во время вставки, однако при необходимости это также можно сделать после вставки. Как контекст: этот столбец добавлен, потому что соединения в UUID не являются производительными.

Комментарии:

1. Любая причина, по которой вы не хотите, чтобы он был уникальным, потому что по определению суррогатный ключ — это уникальное сгенерированное значение. Если вы хотите, вы можете сохранить этот serival_number в другой таблице и сохранить там уникальный идентификатор.

Ответ №1:

Если ваша цель — превратить строку в число для повышения производительности соединения, я рекомендую использовать HASH функцию. В вашем случае вы могли бы просто создать новый столбец и обновить значения HASH(battery_uuid) , чтобы создать суррогатный ключ. А затем используйте этот новый столбец для своих объединений. Если ваш естественный ключ содержит более 2 столбцов, это все равно будет работать для вас, поскольку HASH функция позволяет использовать более одного столбца.

https://docs.snowflake.com/en/sql-reference/functions/hash.html

Комментарии:

1. Это действительно может быть отличным решением!

Ответ №2:

Вот как вы можете это сделать

 CREATE TABLE thetable (event_id string, batt_id string, serial_number string, batt_key number);
INSERT INTO thetable VALUES('1','bat1','1',0);
INSERT INTO thetable VALUES('2','bat1','1',0);
 

итак, с таблицей в базовой форме, которую вы хотите, с некоторыми фиктивными строками, чтобы показать «уже существующие данные, которые мы хотим использовать существующий ключ на основе battery_id. Я сократил имена столбцов по причинам ввода и использовал числовую строку вместо UUID, но точка все еще сохраняется.

 CREATE OR REPLACE SEQUENCE batt_key_seq;

WITH new_data(event_id, batt_id, serial_number) AS (
    SELECT * FROM VALUES 
        ('11','bat1', '10'),
        ('12','bat1', '10'),
        ('13','bat2', '11'),
        ('14','bat1', '10'),
        ('15','bat1', '10'),
        ('16','bat2', '11'),
        ('17','bat3', '12')
), new_data_with_keys AS (
    SELECT d.batt_id
        ,COALESCE(t.batt_key, batt_key_seq.nextval) AS batt_key
    FROM (
        SELECT DISTINCT batt_id 
        FROM new_data
    ) AS d
    LEFT JOIN thetable AS t 
        ON d.batt_id = t.batt_id
    QUALIFY row_number() OVER (PARTITION BY d.batt_id ORDER BY event_id) = 1
)
SELECT n.*, k.batt_key
FROM new_data AS n
JOIN new_data_with_keys AS k 
    ON n.batt_id = k.batt_id
;
 

таким образом, часть ROW_NUMBER() состоит в том, чтобы захватить только одну из существующих строк (таким образом, двойная вставка данных в существующие данные в начале), я чувствую, что это может быть более чистым каким-то другим способом, но он выполняет свою работу.

Но на самом деле вы получаете свои ключи, находите существующие ключи и даете новые ключи к новым данным, а затем можете вставить данные в эту обогащенную форму.

что я замечаю при тестировании, так это то, что мой ключ прыгает на 4 при каждом запуске и меняется на

 ,IFF(t.batt_key is not null, t.batt_key, batt_key_seq.nextval) AS batt_key
 

я этого не исправил.

Таким образом, разделяя ключевые части поиска, такие как

 WITH new_data(event_id, batt_id, serial_number) AS (
    SELECT * FROM VALUES 
        ('11','bat1', '10'),
        ('12','bat1', '10'),
        ('13','bat2', '11'),
        ('14','bat1', '10'),
        ('15','bat1', '10'),
        ('16','bat2', '11'),
        ('17','bat3', '12')
), missing_keys AS (
    SELECT d.batt_id
        ,batt_key_seq.nextval AS batt_key
    FROM (
        SELECT DISTINCT batt_id 
        FROM new_data
    ) AS d
    LEFT JOIN thetable AS t 
        ON d.batt_id = t.batt_id
    WHERE t.batt_id IS NULL
), old_keys AS (
    SELECT distinct d.batt_id
        ,t.batt_key
    FROM (
        SELECT DISTINCT batt_id 
        FROM new_data
    ) AS d
    LEFT JOIN thetable AS t 
        ON d.batt_id = t.batt_id
    WHERE t.batt_id IS NOT NULL
), new_data_with_keys AS (
    SELECT * FROM missing_keys
    UNION ALL
    SELECT * FROM old_keys
)
SELECT n.*, k.batt_key
FROM new_data AS n
JOIN new_data_with_keys AS k 
    ON n.batt_id = k.batt_id
;
 

теперь новые ключи не пропущены / потрачены впустую.

Разница в производительности при потере пространства клавиш стиха с двойным соединением — это то, что вам может понадобиться для тестирования и / или понимания того, сколько новых или существующих данных вы увидите и, следовательно, сколько потерь произойдет. Если производительность второго сильно отличается, вы всегда можете повторно ввести данные позже, хотя в этих ключах используются вне таблицы, в которой может быть много данных для последующего обновления.