Sql 相关子查询的红移替代方案
我正在使用红移,需要一个相关子查询的替代方法。我得到的相关子查询不支持错误。但是,对于尝试识别同一客户在发起交易后的给定小时内完成的所有销售交易的这一特定练习,我不确定传统的左联接是否也能起作用。即,查询取决于父选择的上下文或当前值。我也尝试过使用row_number()window函数进行类似的操作,但还是需要一种方法来在日期范围内进行窗口/分区,而不仅仅是客户id 总体目标是查找给定客户id的第一笔销售交易,然后查找第一笔交易后60分钟内完成的所有后续交易。对于同一客户(最终是数据库中的所有客户)的其余事务,此逻辑将继续。也就是说,一旦从第一次交易开始建立了最初的60分钟窗口,第二个60分钟窗口将在第一个60分钟窗口结束时开始,第二个窗口内的所有交易也将被识别和组合,然后在剩余的交易中重复 输出将列出启动60分钟窗口的第一个事务id,然后列出在60分钟窗口内创建的其他后续事务id。第二行将显示同一客户在下一个60分钟窗口中进行的第一笔交易id(同样,第一个60分钟窗口后的第一笔交易将是第二个60分钟窗口的开始),然后在第二个60分钟窗口内进行后续交易 最基本形式的查询示例如下所示:Sql 相关子查询的红移替代方案,sql,amazon-redshift,correlated-subquery,Sql,Amazon Redshift,Correlated Subquery,我正在使用红移,需要一个相关子查询的替代方法。我得到的相关子查询不支持错误。但是,对于尝试识别同一客户在发起交易后的给定小时内完成的所有销售交易的这一特定练习,我不确定传统的左联接是否也能起作用。即,查询取决于父选择的上下文或当前值。我也尝试过使用row_number()window函数进行类似的操作,但还是需要一种方法来在日期范围内进行窗口/分区,而不仅仅是客户id 总体目标是查找给定客户id的第一笔销售交易,然后查找第一笔交易后60分钟内完成的所有后续交易。对于同一客户(最终是数据库中的所有
select
s1.customer_id,
s1.transaction_id,
s1.order_time,
(
select
s2.transaction_id
from
sales s2
where
s2.order_time > s1.order_time and
s2.order_time <= dateadd(m,60,s1.order_time) and
s2.customer_id = s1.customer_id
order by
s2.order_time asc
limit 1
) as sales_transaction_id_1,
(
select
s3.transaction_id
from
sales s3
where
s3.order_time > s1.order_time and
s3.order_time <= dateadd(m,60,s1.order_time) and
s3.customer_id = s1.customer_id
order by
s3.order_time asc
limit 1 offset 1
) as sales_transaction_id_2,
(
select
s3.transaction_id
from
sales s4
where
s4.order_time > s1.order_time and
s4.order_time <= dateadd(m,60,s1.order_time) and
s4.customer_id = s1.customer_id
order by
s4.order_time asc
limit 1 offset 1
) as sales_transaction_id_3
from
(
select
sales.customer_id,
sales.transaction_id,
sales.order_time
from
sales
order by
sales.order_time desc
) s1;
预期产出如下:
customer_id transaction_id sales_transaction_id_1 sales_transaction_id_2 sales_transaction_id_3
1234 33453 88472 88477 NULL
1234 99321 99345 NULL NULL
此外,红移似乎不支持横向连接,这似乎进一步限制了我可以使用的选项。任何帮助都将不胜感激 根据您的描述,您只需要
分组依据
和某种日期差异。我不确定您希望如何组合这些行,但以下是基本想法:
select s.customer_id,
min(order_time) as first_order_in_hour,
max(order_time) as last_order_in_hour,
count(*) as num_orders
from (select s.*,
min(order_time) over (partition by customer_id) as min_ot
from sales s
) s
group by customer_id, floor(datediff(second, min_ot, order_time) / (60 * 60));
这个公式(或类似的公式,因为Postgres没有
datediff()
)在Postgres中也会快得多。根据您的描述,您只需要按分组和某种日期差异。我不确定您希望如何组合这些行,但以下是基本想法:
select s.customer_id,
min(order_time) as first_order_in_hour,
max(order_time) as last_order_in_hour,
count(*) as num_orders
from (select s.*,
min(order_time) over (partition by customer_id) as min_ot
from sales s
) s
group by customer_id, floor(datediff(second, min_ot, order_time) / (60 * 60));
这种公式(或类似的公式,因为Postgres没有datediff()
)在Postgres中也会快得多。您可以使用窗口函数获取每个事务的后续事务。窗口将为客户/小时,您可以对记录进行排名,以获得第一个“锚定”交易,并获得您需要的所有后续交易:
with
transaction_chains as (
select
customer_id
,transaction_id
,order_time
-- rank transactions within window to find the first "anchor" transaction
,row_number() over (partition by customer_id,date_trunc('minute',order_time) order by order_time)
-- 1st next order
,lead(transaction_id,1) over (partition by customer_id,date_trunc('minute',order_time) order by order_time) as transaction_id_1
,lead(order_time,1) over (partition by customer_id,date_trunc('minute',order_time) order by order_time) as order_time_1
-- 2nd next order
,lead(transaction_id,2) over (partition by customer_id,date_trunc('minute',order_time) order by order_time) as transaction_id_2
,lead(order_time,2) over (partition by customer_id,date_trunc('minute',order_time) order by order_time) as order_time_2
-- 2nd next order
,lead(transaction_id,3) over (partition by customer_id,date_trunc('minute',order_time) order by order_time) as transaction_id_3
,lead(order_time,3) over (partition by customer_id,date_trunc('minute',order_time) order by order_time) as order_time_3
from sales
)
select
customer_id
,transaction_id
,transaction_id_1
,transaction_id_2
,transaction_id_3
from transaction_chains
where row_number=1;
您可以使用窗口函数获取每个事务的后续事务。窗口将为客户/小时,您可以对记录进行排名,以获得第一个“锚定”交易,并获得您需要的所有后续交易:
with
transaction_chains as (
select
customer_id
,transaction_id
,order_time
-- rank transactions within window to find the first "anchor" transaction
,row_number() over (partition by customer_id,date_trunc('minute',order_time) order by order_time)
-- 1st next order
,lead(transaction_id,1) over (partition by customer_id,date_trunc('minute',order_time) order by order_time) as transaction_id_1
,lead(order_time,1) over (partition by customer_id,date_trunc('minute',order_time) order by order_time) as order_time_1
-- 2nd next order
,lead(transaction_id,2) over (partition by customer_id,date_trunc('minute',order_time) order by order_time) as transaction_id_2
,lead(order_time,2) over (partition by customer_id,date_trunc('minute',order_time) order by order_time) as order_time_2
-- 2nd next order
,lead(transaction_id,3) over (partition by customer_id,date_trunc('minute',order_time) order by order_time) as transaction_id_3
,lead(order_time,3) over (partition by customer_id,date_trunc('minute',order_time) order by order_time) as order_time_3
from sales
)
select
customer_id
,transaction_id
,transaction_id_1
,transaction_id_2
,transaction_id_3
from transaction_chains
where row_number=1;
编辑您的问题并提供示例数据和所需结果。以及逻辑应该做什么的解释。它们支持窗口功能吗?CTEs?顺便说一句:您只是从s1
中进行选择,因此查询的其他两个分支可以替换为EXISTS(…)
(也摆脱了难看的限制1)合并的\u事务\u id\u 1被用作别名和列,这很混乱,正如@GordonLinoff所说的,请提供示例数据以及您到底想做什么。对不起,SQL现在已经被澄清了。谢谢提醒。哦,这是一个标量子查询。。。只需将子查询中的两个表连接起来,并将不存在(…)添加到`条件上的两个。编辑您的问题并提供示例数据和所需结果。以及逻辑应该做什么的解释。它们支持窗口功能吗?CTEs?顺便说一句:您只是从s1
中进行选择,因此查询的其他两个分支可以替换为EXISTS(…)
(也摆脱了难看的限制1)合并的\u事务\u id\u 1被用作别名和列,这很混乱,正如@GordonLinoff所说的,请提供示例数据以及您到底想做什么。对不起,SQL现在已经被澄清了。谢谢提醒。哦,这是一个标量子查询。。。只需将子查询中的两个表连接起来,并将NOT EXISTS(…)添加到`条件上的两个。这是正确的做法,但是,需要明确列出各个事务ID。也就是说,属于特定60分钟窗口的事务ID需要保留,而不是通过group by立即聚合。@user3701000。然后按
删除分组,并执行所需操作。这正是您所需要的想法。无论是否有group by,这都将包括所有事务。相反,将识别第一个事务,列出该特定60分钟窗口内的所有后续事务ID,然后跳到下一个60分钟窗口并执行相同的操作-即,列出第二个60分钟窗口的所有事务(不列出前一个窗口中的事务),依此类推。但是,这是正确的,需要明确列出各个事务ID。也就是说,属于特定60分钟窗口的事务ID需要保留,而不是通过group by立即聚合。@user3701000。然后按
删除分组,并执行所需操作。这正是您所需要的想法。无论是否有group by,这都将包括所有事务。相反,第一个事务将被识别,列出该特定60分钟窗口内的所有后续事务ID,然后跳到下一个60分钟窗口并执行相同的操作,即列出第二个窗口的所有事务(不列出前一个窗口中的事务)