在SELECT子句中重写相关子查询的最高效方法是什么?

时间:2017-11-17 19:21:55

标签: sql database-performance netezza correlated-subquery

我正在尝试计算用户是否在三个时间范围内访问过某个网站:

  • 过去30天
  • 31至60天
  • 61至90天

我使用的是Netezza,它不支持SELECT子句中的相关子查询。有关成功查询的信息,请参阅Rextester,该查询必须重写为不使用相关子查询:http://rextester.com/JGR62033

示例数据:

| user_id | last_visit | num_days_since_2017117 |
|---------|------------|------------------------|
| 1234    | 2017-11-02 | 15.6                   |
| 1234    | 2017-09-30 | 48.6                   |
| 1234    | 2017-09-03 | 75.0                   |
| 1234    | 2017-08-21 | 88.0                   |
| 9876    | 2017-10-03 | 45.0                   |
| 9876    | 2017-07-20 | 120.0                  |
| 5545    | 2017-09-15 | 63.0                   |

期望输出:

| user_id | last_30 | btwn_31_60 | btwn_61_90 |
|---------|---------|------------|------------|
| 1234    | 1       | 1          | 1          |
| 5545    | 0       | 0          | 1          |
| 9876    | 0       | 1          | 0          |

2 个答案:

答案 0 :(得分:2)

我不知道您正在使用的特定DBMS,但如果它支持CASE或等效的,您不需要相关的子查询;您可以将SUM()CASE组合使用。

当然,在您的DBMS中未经测试,但它应该为您提供一个起点:

SELECT 
  user_id, 
  SUM(CASE WHEN num_days <= 30 then 1 else 0 end) as last_30, 
  SUM(CASE WHEN num_days > 30 AND numdays < 61 then 1 else 0 end) as btwn_31_60,
  SUM(CASE WHEN num_days >= 61 then 1 else 0 end) as btwn_61_90
FROM 
  YourTableName  -- You didn't provide a tablename
GROUP BY 
  user_id 

由于您的值是浮点而不是整数,因此您可能需要调整用于日期范围的值以符合您的特定要求。

答案 1 :(得分:2)

以下是条件聚合的一种方法,Rextester

select 
    user_id
    ,MAX(case when '2017-11-17'-visit_date <=30
          then 1
          else 0
     end) as last_30
    ,MAX(case when '2017-11-17'-visit_date >=31
               and '2017-11-17'-visit_date <=60
          then 1
          else 0
     end) as between_31_60
    ,MAX(case when '2017-11-17'-visit_date >=61
              and '2017-11-17'-visit_date <=90
          then 1
          else 0
     end) as between_61_90
from 
    visits
group by user_id
order by user_id