将此 SQL 查询转换为使用 window 函数,或任何其他更有效的方法
Converting this SQL query to use a window function, or any other more efficient method
我有一个巨大的 table,其中包含有关所有客户的详细信息,例如他们的 phone 电话号码和电子邮件地址。 table 每个客户可以有多行,表示他们在某个时候更改了他们的 phone 电话号码、电子邮件地址或其他个人资料信息。每行都有一个日期列,表示个人资料更改发生的日期(即当天他们的个人资料状态)。
我想提取每个客户曾经在其个人资料中拥有的每个 phone 号码和电子邮件地址,并添加一个布尔标志(称为 'live')以指示哪个 phone号码和电子邮件当前与他们的个人资料相关联(即我们在 table 中为该客户提供的最新记录)。
这是我当前的查询:
SELECT DISTINCT
customer_id,
phone_number,
email AS email_address,
CASE
WHEN day = (
SELECT
MAX(temp.day)
FROM
customer AS temp
WHERE
customer.customer_id = temp.customer_id
)
THEN true
ELSE false
END AS live
FROM
customer
我认为这是非常低效的,因为数百万不同的客户有数十亿行。我怎样才能改进这个查询来实现我想要的(可能是 window 函数?),或者 soem 会以完全不同的方式更好地实现我想要的吗?
您可以使用row_number()
设置标志:
SELECT
customer_id,
phone_number,
email AS email_address,
(ROW_NUMBER() over(partition by customer_id ORDER BY day DESC) = 1) as is_live
FROM customer
我不确定 Presto 是否将条件理解为布尔值 - 如果不是,您可以这样做:
CASE WHEN ROW_NUMBER() over(partition by customer_id ORDER BY day DESC) = 1
THEN true
ELSE false
END as is_live
如果记录是唯一的,您可以使用:
SELECT customer_id, phone_number, email AS email_address,
(CASE WHEN RANK() OVER (PARTITION BY customer_id ORDER BY day DESC) = 1
THEN true ELSE false
END) as is_live
FROM customer c;
Presto 支持布尔值,因此您不需要 CASE
表达式。但我保留了它,因为你的代码中有它。
这是您最初的关联子查询,已转换为 Group Max,结果与 RANK 版本相同:
CASE
WHEN day = MAX(temp.day) over (partition by customer_id)
THEN true
ELSE false
END AS live
显示每个phone每个客户的个人资料中的每个phone号码和电子邮件地址,意思是这两个资源的每个组合仅一次 使用以下查询。
这里是样本日期
create table tab as
select 1 customer_id, 'A' phone_number, '1@1' email, DATE'2020-01-01' day from dual union all
select 1 customer_id, 'B' phone_number, '1@1' email, DATE'2020-02-01' day from dual union all
select 1 customer_id, 'A' phone_number, '1@1' email, DATE'2020-03-01' day from dual union all
select 2 customer_id, 'C' phone_number, '1@1' email, DATE'2020-01-01' day from dual union all
select 2 customer_id, 'C' phone_number, '1@1' email, DATE'2020-04-01' day from dual
;
查询
with live as (
select CUSTOMER_ID, PHONE_NUMBER, EMAIL, DAY ,
case when row_number() over (partition by CUSTOMER_ID order by day DESC) = 1 then 1 else 0 end is_live
from tab)
select CUSTOMER_ID, PHONE_NUMBER, EMAIL,
case when max(is_live) = 1 then 'true' else 'false' end is_life
from live
group by CUSTOMER_ID, PHONE_NUMBER, EMAIL
产生
CUSTOMER_ID P EMA IS_LI
----------- - --- -----
1 B 1@x false
1 A 1@x true
2 C 2@x true
子查询标识最后一个(实时)记录,GROUP BY
查询仅生成资源的唯一组合(与您的解决方案中的 SELECT DISTINCT
类似,但更好 - 如果相同则失败资源在实时和非实时行中)。
我有一个巨大的 table,其中包含有关所有客户的详细信息,例如他们的 phone 电话号码和电子邮件地址。 table 每个客户可以有多行,表示他们在某个时候更改了他们的 phone 电话号码、电子邮件地址或其他个人资料信息。每行都有一个日期列,表示个人资料更改发生的日期(即当天他们的个人资料状态)。
我想提取每个客户曾经在其个人资料中拥有的每个 phone 号码和电子邮件地址,并添加一个布尔标志(称为 'live')以指示哪个 phone号码和电子邮件当前与他们的个人资料相关联(即我们在 table 中为该客户提供的最新记录)。
这是我当前的查询:
SELECT DISTINCT
customer_id,
phone_number,
email AS email_address,
CASE
WHEN day = (
SELECT
MAX(temp.day)
FROM
customer AS temp
WHERE
customer.customer_id = temp.customer_id
)
THEN true
ELSE false
END AS live
FROM
customer
我认为这是非常低效的,因为数百万不同的客户有数十亿行。我怎样才能改进这个查询来实现我想要的(可能是 window 函数?),或者 soem 会以完全不同的方式更好地实现我想要的吗?
您可以使用row_number()
设置标志:
SELECT
customer_id,
phone_number,
email AS email_address,
(ROW_NUMBER() over(partition by customer_id ORDER BY day DESC) = 1) as is_live
FROM customer
我不确定 Presto 是否将条件理解为布尔值 - 如果不是,您可以这样做:
CASE WHEN ROW_NUMBER() over(partition by customer_id ORDER BY day DESC) = 1
THEN true
ELSE false
END as is_live
如果记录是唯一的,您可以使用:
SELECT customer_id, phone_number, email AS email_address,
(CASE WHEN RANK() OVER (PARTITION BY customer_id ORDER BY day DESC) = 1
THEN true ELSE false
END) as is_live
FROM customer c;
Presto 支持布尔值,因此您不需要 CASE
表达式。但我保留了它,因为你的代码中有它。
这是您最初的关联子查询,已转换为 Group Max,结果与 RANK 版本相同:
CASE
WHEN day = MAX(temp.day) over (partition by customer_id)
THEN true
ELSE false
END AS live
显示每个phone每个客户的个人资料中的每个phone号码和电子邮件地址,意思是这两个资源的每个组合仅一次 使用以下查询。
这里是样本日期
create table tab as
select 1 customer_id, 'A' phone_number, '1@1' email, DATE'2020-01-01' day from dual union all
select 1 customer_id, 'B' phone_number, '1@1' email, DATE'2020-02-01' day from dual union all
select 1 customer_id, 'A' phone_number, '1@1' email, DATE'2020-03-01' day from dual union all
select 2 customer_id, 'C' phone_number, '1@1' email, DATE'2020-01-01' day from dual union all
select 2 customer_id, 'C' phone_number, '1@1' email, DATE'2020-04-01' day from dual
;
查询
with live as (
select CUSTOMER_ID, PHONE_NUMBER, EMAIL, DAY ,
case when row_number() over (partition by CUSTOMER_ID order by day DESC) = 1 then 1 else 0 end is_live
from tab)
select CUSTOMER_ID, PHONE_NUMBER, EMAIL,
case when max(is_live) = 1 then 'true' else 'false' end is_life
from live
group by CUSTOMER_ID, PHONE_NUMBER, EMAIL
产生
CUSTOMER_ID P EMA IS_LI
----------- - --- -----
1 B 1@x false
1 A 1@x true
2 C 2@x true
子查询标识最后一个(实时)记录,GROUP BY
查询仅生成资源的唯一组合(与您的解决方案中的 SELECT DISTINCT
类似,但更好 - 如果相同则失败资源在实时和非实时行中)。