【问题标题】:Is there a function to easily create a surrogate key in Snowflake?是否有在 Snowflake 中轻松创建代理键的功能?
【发布时间】:2021-03-20 13:24:05
【问题描述】:

是否有一种简单/有效的方法可以在 Snowflake 中创建代理键?

想象一下这个数据集将被选入一个表中, 在插入过程中,添加了一个 battery_id 列,它是映射到代理键的 battery_uuid 列。 在这种情况下,具体情况可能会变成例如[1,1,2,1,1,2,3]。 Snowflake 中的序列没有这个功能,因为它变成了例如[1,2,3,4,5,6,7]。 最好在插入期间完成此映射,但是,如果需要,也可以在插入后完成。 作为上下文:添加此列是因为 UUID 上的连接不高效。

【问题讨论】:

  • 您不希望它唯一的任何原因,因为根据定义,代理键是唯一的生成值。如果您愿意,您可以将该 serival_number 存储在不同的表中,并在其中存储一个唯一的 id。

标签: sql join snowflake-cloud-data-platform surrogate-key


【解决方案1】:

如果您的目标是将字符串转换为数字以提高连接性能,我建议使用HASH 函数。在您的情况下,您可以简单地创建一个新列并将值更新为 HASH(battery_uuid) 以创建代理键。然后利用该新列进行连接。如果您的自然键超过 2 列,这仍然适用于您,因为 HASH 函数允许使用多个列。

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

【讨论】:

  • 这确实是一个很好的解决方案!
【解决方案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
;

现在新密钥不会跳过/浪费。

双连接与键空间浪费的性能差异是您可能需要测试和/或了解您将看到多少新诗与现有数据以及因此发生多少浪费的东西。如果第二个的性能差异很大,您可以随时重新键入数据,尽管这些键在表之外使用,可能会在以后更新大量数据。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-09
    • 1970-01-01
    • 2023-03-07
    • 2014-10-02
    • 2016-04-21
    • 1970-01-01
    相关资源
    最近更新 更多