【问题标题】:SQL query with distinct and group by snowflake具有不同和按雪花分组的 SQL 查询
【发布时间】:2020-08-11 16:01:44
【问题描述】:

我想要完成的是获取给定 MPN 的所有记录,但是,我只想要来自 shpm 的最新 DeliveryDate,但考虑到 MAX 函数需要在group by 子句,它没有得到最新的记录,它因为不同的DeliveryDate 而得到了所有的记录,它得到了两条记录而不是一条,我怎么能做到这一点?这是在雪花中。

这是我的 SQL 代码

SELECT
    MD.MPN,
    MD.LOTCODE,
    MD.DATECODE,
    SHIP.ITEMCODE AS SYSTEMPARTNUMBER, 
    SHIP.SERIALNUMBER AS SYSTEMSERIALNUMBER, 
    SHIP.CUSTOMERNAME, 
    SHIP.SHIPTOADDRESS AS ADDRESS,
    SUM(IFNULL(SHIP.QUANTITY,0)) AS QUANTITY,
    SHIP.DELIVERYDATE
FROM cunits UNITS
   JOIN unc UC ON UC.CHILDUNITID = UNITS.ID
   JOIN shpm SHIP ON SHIP.SERIALNUMBER = UC.SYSSN
   JOIN tsern SN ON SN.UNITID = UNITS.ID
   JOIN machined MD ON MD.SERIALNUMBER = SN.SERIALNUMBER     
WHERE --SYSTEMSERIALNUMBER = '001801055469' and 
MPN = 'XC0402A105KP5CNN-S'
GROUP BY MD.MPN,MD.LOTCODE,MD.DATECODE,SHIP.ITEMCODE,SHIP.SERIALNUMBER,SHIP.CUSTOMERNAME,SHIP.SHIPTOADDRESS

【问题讨论】:

    标签: sql group-by distinct snowflake-cloud-data-platform


    【解决方案1】:

    使用ROW_NUMBER()QUALIFY

    SELECT MD.MPN, MD.LOTCODE, MD.DATECODE,
           SHIP.ITEMCODE AS SYSTEMPARTNUMBER, SHIP.SERIALNUMBER AS SYSTEMSERIALNUMBER, 
           SHIP.CUSTOMERNAME, SHIP.SHIPTOADDRESS AS ADDRESS,
           SUM(COALESCE(SHIP.QUANTITY, 0)) AS QUANTITY,
           SHIP.DELIVERYDATE
    FROM cunits UNITS JOIN
         unc UC
         ON UC.CHILDUNITID = UNITS.ID JOIN
         shpm SHIP
         ON SHIP.SERIALNUMBER = UC.SYSSN JOIN
         tsern SN
         ON SN.UNITID = UNITS.ID JOIN
         machined MD
         ON MD.SERIALNUMBER = SN.SERIALNUMBER     
    WHERE '001801055469' and MPN = 'XC0402A105KP5CNN-S'
    GROUP BY MD.MPN, MD.LOTCODE, MD.DATECODE, SHIP.ITEMCODE, SHIP.SERIALNUMBER, SHIP.CUSTOMERNAME, SHIP.SHIPTOADDRESS
    QUALIFY ROW_NUMBER() OVER (PARTITION BY MD.MPN, SHIP.SERIALNUMBER ORDER BY SHIP.SHIPDATE DESC) = 1;
    

    这将返回每个MPN 的行,这就是我解释您的问题的方式。您可能还需要PARTITION BY 中的其他列。

    【讨论】:

    • 我相信我没有解释得很好。关系是这样的:一个MPN 附有多个序列号,但serialnumber 只有一个deliverydate(或者应该)然而,有时新记录会以相同的方式出现,除了交货日期这比MPNSerialNumber 以前拥有的最后一个要大,我只需要最新的一个。我希望这是有道理的,或者如果我因为这是您发布的内容而变得多余,请告诉我
    • @DiegoDuarte 。 . .听起来你也想在PARTITION BY 中使用SHIP.SERIALNUMBER
    • @MikeWalton 别名是SHIP
    • @DiegoDuarte 。 . .这不是你想要的吗?当您接受答案时,我假设它是正确的,qualify 似乎是最简单的解决方案。
    • 它做到了,这是正确的答案,但其他答案的表现更好。就是这样。这是最简单的解决方案,我只关心数据库性能,因为加工表中有超过 6.5 亿条记录
    【解决方案2】:

    所以猜测一些数据来匹配 SQL

    WITH cunits AS (
        SELECT * from values (1) v(id)
    ), unc AS (
        SELECT * FROM VALUES (1,'123') v(CHILDUNITID,SYSSN)
    ), shpm AS (
        SELECT * FROM VALUES ('a', '123', 10, '2020-02-01'),
           ('a', '123', 20, '2020-01-01') 
       v(ITEMCODE, SERIALNUMBER, QUANTITY, DELIVERYDATE)
    ), tsern AS (
        SELECT * FROM VALUES (1,'zxc') v(UNITID,SERIALNUMBER)
    ), machined as (
        SELECT * FROM VALUES ('zxc', 'XC0402A105KP5CNN-S') v(SERIALNUMBER, MPN)
    )
    

    并从示例中删除一些无关紧要的列

    SELECT
        MD.MPN,
        SHIP.ITEMCODE AS SYSTEMPARTNUMBER, 
        SHIP.SERIALNUMBER AS SYSTEMSERIALNUMBER, 
        SUM(IFNULL(SHIP.QUANTITY,0)) AS QUANTITY,
        SHIP.DELIVERYDATE
    FROM cunits UNITS
       JOIN unc UC ON UC.CHILDUNITID = UNITS.ID
       JOIN shpm SHIP ON SHIP.SERIALNUMBER = UC.SYSSN
       JOIN tsern SN ON SN.UNITID = UNITS.ID
       JOIN machined MD ON MD.SERIALNUMBER = SN.SERIALNUMBER     
    WHERE 
    MPN = 'XC0402A105KP5CNN-S'
    GROUP BY MD.MPN,SHIP.ITEMCODE,SHIP.SERIALNUMBER;
    

    现在必须将 SHIP.DELIVERYDATE 添加到 group by 子句中,否则此代码将永远不会运行,甚至会忽略您不想看到 2020-01-01 数据的愿望

    添加后,您会得到两行不想要的行。

    MPN SYSTEMPARTNUMBER    SYSTEMSERIALNUMBER  QUANTITY    DELIVERYDATE
    XC0402A105KP5CNN-S  a   123 10  2020-02-01
    XC0402A105KP5CNN-S  a   123 20  2020-01-01
    

    Gordon 的解决方案,添加一个 QUALIFY

    QUALIFY ROW_NUMBER() OVER (PARTITION BY MD.MPN, SHIP.SERIALNUMBER ORDER BY SHIP.DELIVERYDATE DESC) = 1;
    

    正确地给出了答案,但是计算所有结果并修剪那些不需要的结果。根据您的数据集大小和shpm 表中有多少行,预过滤的 CTE 可能会更好..

    WITH cunits AS (
        SELECT * from values (1) v(id)
    ), unc AS (
        SELECT * FROM VALUES (1,'123') v(CHILDUNITID,SYSSN)
    ), shpm AS (
        SELECT * FROM VALUES ('a', '123', 10, '2020-02-01'),
           ('a', '123', 20, '2020-01-01') 
       v(ITEMCODE, SERIALNUMBER, QUANTITY, DELIVERYDATE)
    ), tsern AS (
        SELECT * FROM VALUES (1,'zxc') v(UNITID,SERIALNUMBER)
    ), machined as (
        SELECT * FROM VALUES ('zxc', 'XC0402A105KP5CNN-S') v(SERIALNUMBER, MPN)
    ), pre_filtered_shpm AS (
        select * from shpm
        QUALIFY ROW_NUMBER() OVER (PARTITION BY SERIALNUMBER ORDER BY DELIVERYDATE DESC) = 1
    )
    SELECT
        MD.MPN,
        SHIP.ITEMCODE AS SYSTEMPARTNUMBER, 
        SHIP.SERIALNUMBER AS SYSTEMSERIALNUMBER, 
        SUM(IFNULL(SHIP.QUANTITY,0)) AS QUANTITY,
        SHIP.DELIVERYDATE
    FROM cunits UNITS
       JOIN unc UC ON UC.CHILDUNITID = UNITS.ID
       JOIN pre_filtered_shpm SHIP ON SHIP.SERIALNUMBER = UC.SYSSN
       JOIN tsern SN ON SN.UNITID = UNITS.ID
       JOIN machined MD ON MD.SERIALNUMBER = SN.SERIALNUMBER     
    WHERE 
    MPN = 'XC0402A105KP5CNN-S'
    GROUP BY MD.MPN,SHIP.ITEMCODE,SHIP.SERIALNUMBER,SHIP.DELIVERYDATE;
    

    【讨论】:

    • 无论是在 CTE 中还是作为子选择完成,在所有连接之前运行 QUALIFY 肯定更有效。这实际上比纯粹根据性能选择正确的答案更好。
    • 虽然第一个答案绝对正确,但这个答案大大提高了性能。非常感谢您的精心回复
    • @MikeWalton 。 . .如果你能找出重复的来源,那就是真的。我认为问题中没有足够的信息来弄清楚这一点,这是一个碰巧有效的猜测 - 仍然是一个很好的解决方案,但对问题中未解释的数据模型做出假设。
    • OP 实际上提到了重复发生的位置。这不是猜测。
    • 我在想,在 Gordon 看来,这是相当“可能”令人担忧的优化,因为链接表的数量可能是“dups 的来源”,这实际上意味着编写 SQL 的人真的需要知道数据.. 它几乎更“担心数据是好的,除了有时它被“损坏”让我们在报告中过滤它”无论如何我展示了一种提高性能的方法,但了解数据的性质/形状相当重要,得到正确的结果。
    猜你喜欢
    • 2023-02-09
    • 1970-01-01
    • 2020-03-17
    • 1970-01-01
    • 2022-07-07
    • 2020-09-12
    • 2022-01-04
    • 2020-11-05
    • 2021-09-21
    相关资源
    最近更新 更多