SQL(分析)查询以检索分组依据的每个值的第一行和第二行
SQL (analytical) query to retrieve first and second rows for each value of a group by
我有一个情况想在 SQL 中使用尽可能少的内部联接来解决,所以我正在考虑使用 window 函数。
我正在使用 Snowflake,但我也很高兴在其他数据库引擎中看到答案。
Table 销售额有 sale_id 和 seller_id,还有 sale_datetime,金额...
Table 卖家有 seller_id
我想获得每个卖家的第一次和第二次销售,最好是列(这样我就可以加减,例如金额总和)。如果只有一个销售,理想情况下我不会检索它。
我正在尝试使用这样的东西:
select se.seller_id,sa.*, first_value(sale_datetime) over (ORDER BY
sale_datetime ), LAG(sale_datetime) OVER (ORDER BY sale_datetime)
from seller se inner join sales sa on sa.seller_id = se.seller_id
order by se.seller_id;
但我需要添加一个分组依据,因为 window 功能需要在卖家级别应用,而不是 table 的总和。无论是在查询末尾还是在 window 中添加它,我都会得到一个错误。
我在没有 windows 的情况下执行此操作的另一种方法是使用两个 with...as 子句分别检索每个卖家的第一次和第二次销售以及它们之间的连接,但我正在尝试出于性能原因避免这种情况。
谢谢!
ROW_NUMBER 和 QUALIFY 可以使用:
select se.seller_id,sa.*
from seller se
join sales sa
on sa.seller_id = se.seller_id
qualify row_number() over(partition by sa.seller_id order by sale_datetime) <= 2
order by se.seller_id;
你的答案已经基本存在了。您只需要使用 LAG 并使用 ROW_NUMBER/QUALIFY
数据的 CTE:
with sales(sale_id, seller_id, sale_datetime, amount) as (
select * from values
(4, 10, '2022-04-24'::date, 100),
(3, 10, '2022-04-23'::date, 200),
(2, 10, '2022-04-22'::date, 400),
(1, 11, '2022-04-22'::date, 300)
)
工作SQL:
select sa.*,
LAG(sale_datetime) OVER (partition by sa.seller_id ORDER BY sa.sale_datetime) as prior_sale_date,
LAG(amount) OVER (partition by sa.seller_id ORDER BY sa.sale_datetime) as prior_amount
FROM sales AS sa
qualify row_number() over(partition by sa.seller_id order by sale_datetime) = 2
order by sa.seller_id;
给出:
SALE_ID
SELLER_ID
SALE_DATETIME
AMOUNT
PRIOR_SALE_DATE
PRIOR_AMOUNT
2
10
2022-04-23
200
2022-04-22
400
这是可行的,因为每一行都通过两个 LAG 获得先验值,但我们只保留第二行。
我还删除了 seller se
table 因为它对流程没有任何价值,因为它只是一个过滤器..,但可以通过以下方式存在:
更复杂的数据 CTE:
select * from values
(4, 10, '2022-04-24'::date, 100),
(3, 10, '2022-04-23'::date, 200),
(2, 10, '2022-04-22'::date, 400),
(1, 11, '2022-04-22'::date, 300)
), seller(seller_id) as (
select * from values (10),(11),(12),(13)
)
与 JOIN 一起工作 SQL。
select sa.*,
LAG(sale_datetime) OVER (partition by sa.seller_id ORDER BY sa.sale_datetime) as prior_sale_date,
LAG(amount) OVER (partition by sa.seller_id ORDER BY sa.sale_datetime) as prior_amount
FROM seller as se
JOIN sales AS sa
ON se.seller_id = sa.seller_id
qualify row_number() over(partition by sa.seller_id order by sale_datetime) = 2
order by sa.seller_id;
给出:
SALE_ID
SELLER_ID
SALE_DATETIME
AMOUNT
PRIOR_SALE_DATE
PRIOR_AMOUNT
3
10
2022-04-23
200
2022-04-22
400
我有一个情况想在 SQL 中使用尽可能少的内部联接来解决,所以我正在考虑使用 window 函数。
我正在使用 Snowflake,但我也很高兴在其他数据库引擎中看到答案。
Table 销售额有 sale_id 和 seller_id,还有 sale_datetime,金额... Table 卖家有 seller_id
我想获得每个卖家的第一次和第二次销售,最好是列(这样我就可以加减,例如金额总和)。如果只有一个销售,理想情况下我不会检索它。
我正在尝试使用这样的东西:
select se.seller_id,sa.*, first_value(sale_datetime) over (ORDER BY
sale_datetime ), LAG(sale_datetime) OVER (ORDER BY sale_datetime)
from seller se inner join sales sa on sa.seller_id = se.seller_id
order by se.seller_id;
但我需要添加一个分组依据,因为 window 功能需要在卖家级别应用,而不是 table 的总和。无论是在查询末尾还是在 window 中添加它,我都会得到一个错误。
我在没有 windows 的情况下执行此操作的另一种方法是使用两个 with...as 子句分别检索每个卖家的第一次和第二次销售以及它们之间的连接,但我正在尝试出于性能原因避免这种情况。
谢谢!
ROW_NUMBER 和 QUALIFY 可以使用:
select se.seller_id,sa.*
from seller se
join sales sa
on sa.seller_id = se.seller_id
qualify row_number() over(partition by sa.seller_id order by sale_datetime) <= 2
order by se.seller_id;
你的答案已经基本存在了。您只需要使用 LAG 并使用 ROW_NUMBER/QUALIFY
数据的 CTE:
with sales(sale_id, seller_id, sale_datetime, amount) as (
select * from values
(4, 10, '2022-04-24'::date, 100),
(3, 10, '2022-04-23'::date, 200),
(2, 10, '2022-04-22'::date, 400),
(1, 11, '2022-04-22'::date, 300)
)
工作SQL:
select sa.*,
LAG(sale_datetime) OVER (partition by sa.seller_id ORDER BY sa.sale_datetime) as prior_sale_date,
LAG(amount) OVER (partition by sa.seller_id ORDER BY sa.sale_datetime) as prior_amount
FROM sales AS sa
qualify row_number() over(partition by sa.seller_id order by sale_datetime) = 2
order by sa.seller_id;
给出:
SALE_ID | SELLER_ID | SALE_DATETIME | AMOUNT | PRIOR_SALE_DATE | PRIOR_AMOUNT |
---|---|---|---|---|---|
2 | 10 | 2022-04-23 | 200 | 2022-04-22 | 400 |
这是可行的,因为每一行都通过两个 LAG 获得先验值,但我们只保留第二行。
我还删除了 seller se
table 因为它对流程没有任何价值,因为它只是一个过滤器..,但可以通过以下方式存在:
更复杂的数据 CTE:
select * from values
(4, 10, '2022-04-24'::date, 100),
(3, 10, '2022-04-23'::date, 200),
(2, 10, '2022-04-22'::date, 400),
(1, 11, '2022-04-22'::date, 300)
), seller(seller_id) as (
select * from values (10),(11),(12),(13)
)
与 JOIN 一起工作 SQL。
select sa.*,
LAG(sale_datetime) OVER (partition by sa.seller_id ORDER BY sa.sale_datetime) as prior_sale_date,
LAG(amount) OVER (partition by sa.seller_id ORDER BY sa.sale_datetime) as prior_amount
FROM seller as se
JOIN sales AS sa
ON se.seller_id = sa.seller_id
qualify row_number() over(partition by sa.seller_id order by sale_datetime) = 2
order by sa.seller_id;
给出:
SALE_ID | SELLER_ID | SALE_DATETIME | AMOUNT | PRIOR_SALE_DATE | PRIOR_AMOUNT |
---|---|---|---|---|---|
3 | 10 | 2022-04-23 | 200 | 2022-04-22 | 400 |