【问题标题】:Equivalent for Keep in Snowflake等同于 Keep in Snowflake
【发布时间】:2021-05-13 11:23:49
【问题描述】:

我正在尝试将 oracle 代码转换为雪花,

在甲骨文中:

MIN(salary) KEEP (DENSE_RANK FIRST ORDER BY commission_pct) "Worst",

什么是对应的东西,因为我们在 oracle 中没有“保留”

【问题讨论】:

    标签: sql snowflake-cloud-data-platform snowflake-schema


    【解决方案1】:

    Snowflake 没有等效的“第一”聚合函数。一种方法是使用条件聚合:

    select min(case when seqnum = 1 then salary end) as worst
    from (select t.*,
                 row_number() over (partition by ? order by commission_pct) as seqnum
          from t
         ) t
    group by . . .
    

    ? 是用于聚合的列

    【讨论】:

    • 您也可以使用 Snowflake 的 QUALIFY 功能,而不是使用子选择。
    • @MikeWalton 。 . .整个查询显然是一个聚合查询,可能还有很多其他的事情在发生。出于这个原因,我特别没有使用qualify
    • @MikeWalton 你可以使用 QUALIFY 并重写嵌套查询吗?
    【解决方案2】:

    所以使用这个 CTE 作为示例数据:

    WITH data AS (  
        SELECT * FROM VALUES 
            ('a', 2300, 10.1), 
            ('a',4000, 28.7), 
            ('b', 3000, 90.0) 
        AS v(dept, salary, commission_pct)  
    )
    

    并应用 Gordon 的代码:

    SELECT dept
        ,MIN(CASE WHEN seqnum = 1 THEN salary end) AS worst
    FROM (SELECT t.*,
                 ROW_NUMBER() OVER (PARTITION BY dept ORDER BY commission_pct) AS seqnum
          FROM data AS t
    ) 
    GROUP BY 1 ORDER BY 1; 
    

    我们根据commission_pct从每个部门(dept)得到第一项,然后我们取这些值的MIN。

    2300
    

    如果我们去掉 Min 从而有

    WITH data AS (  
        SELECT * FROM values 
            ('a', 2300, 10.1), 
            ('a',4000, 28.7), 
            ('b', 3000, 90.0) 
        AS v(dept, salary, commission_pct)  
    )
    SELECT 
        CASE WHEN seqnum = 1 THEN salary END AS worst
    FROM (SELECT t.*,
                 ROW_NUMBER() OVER (PARTITION BY dept ORDER BY commission_pct) as seqnum
          FROM data AS t
    ) ;
    

    我们得到

    WORST
    2300
    NULL
    3000
    

    所以区别在于 QUALIFY 的情况下,非第一行实际上并没有返回。因此其他操作无法访问。

    WITH data AS (  
        SELECT * FROM VALUES 
            ('a', 2300, 10.1), 
            ('a',4000, 28.7), 
            ('b', 3000, 90.0) 
        AS v(dept, salary, commission_pct)  
    )
    SELECT 
        salary AS worst
    FROM data 
    QUALIFY rOW_NUMBER() OVER (PARTITION BY dept ORDER BY commission_pct) = 1
    ;
    

    只是给出:

    WORST
    2300
    3000
    

    但是 Snowflake 确实有 FIRST_VALUE,因此有 KEEP 的效果

    WITH data AS (  
        SELECT * FROM VALUES 
            ('a', 2300, 10.1), 
            ('a',4000, 28.7), 
            ('b', 3000, 90.0) 
        AS v(dept, salary, commission_pct)  
    )
    SELECT t.*
        ,first_value(salary) OVER (PARTITION BY dept ORDER BY commission_pct) as same_as_keep
    FROM data AS t
    ;
    

    给予:

    DEPT    SALARY    COMMISSION_PCT  SAME_AS_KEEP
    a       2300      10.1            2300
    a       4000      28.7            2300
    b       3000      90.0            3000
    

    因此您(需要一些子选择来消除双窗口功能的歧义)

    WITH data AS (  
        SELECT * FROM VALUES 
            ('a', 2300, 10.1), 
            ('a',4000, 28.7), 
            ('b', 3000, 90.0) 
        AS v(dept, salary, commission_pct)  
    )
    SELECT q.*,
        min(same_as_keep) over (partition by true) as worst
    FROM (
        SELECT t.*
            ,first_value(salary) OVER (PARTITION BY dept ORDER BY commission_pct) as same_as_keep
        FROM data AS t
      ) AS q
    ;
    

    给予:

    DEPT    SALARY    COMMISSION_PCT    SAME_AS_KEEP    WORST
    a       2300      10.1              2300            2300
    a       4000      28.7              2300            2300
    b       3000      90.0              3000            2300
    

    但就像很多事情一样,这一切都取决于您如何使用 KEEP 以及您想要的行为方面。

    例如,我不知道你是否将 MIN 换成 COUNT,如果 KEEP 对于这个示例数据会给你 2,这就像 Gordon 的 CASE 版本,或者如果它给你 3,这意味着它的行为就像 FIRST VALUE。

    【讨论】:

      【解决方案3】:

      您仍然可以使用聚合函数,而无需创建子查询/诉诸窗口函数。

      想法是使用支持排序的聚合函数,如ARRAY_AGG 并访问第一个元素:

      SELECT sth,
           MIN(salary) KEEP (DENSE_RANK FIRST ORDER BY commission_pct) "Worst"
      FROM tab
      GROUP BY sth;
      

      应该是:

      SELECT sth,
          (ARRAY_AGG(salary) WITHIN GROUP(ORDER BY commission_pct DESC, salary))[0]
      FROM tab
      GROUP BY sth;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-09-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-04-17
        • 1970-01-01
        • 2022-12-28
        • 1970-01-01
        相关资源
        最近更新 更多