【发布时间】: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
我正在尝试将 oracle 代码转换为雪花,
在甲骨文中:
MIN(salary) KEEP (DENSE_RANK FIRST ORDER BY commission_pct) "Worst",
什么是对应的东西,因为我们在 oracle 中没有“保留”
【问题讨论】:
标签: sql snowflake-cloud-data-platform snowflake-schema
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 . . .
? 是用于聚合的列
【讨论】:
QUALIFY 功能,而不是使用子选择。
qualify。
所以使用这个 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。
【讨论】:
您仍然可以使用聚合函数,而无需创建子查询/诉诸窗口函数。
想法是使用支持排序的聚合函数,如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;
【讨论】: