在重写此查询时需要指导

Posted

技术标签:

【中文标题】在重写此查询时需要指导【英文标题】:Need guidance in re-writing this query 【发布时间】:2019-05-20 08:10:14 【问题描述】:

我们有这个查询,我们运行它来生成日历周数据 此查询两次命中相同的视图。由于缺少连接 ON 子句,可能会创建笛卡尔积。

有没有办法以最佳方式重写这个查询。

SELECT cal_date,
       regexp_replace(cal_date, '-', '') AS PC_cal_date,
       year_num*100+week_num AS year_week_num,
       CASE
           WHEN year_num*100+pd_num IN (min_year_pd_num, max_year_pd_num) THEN 'A'
           ELSE 'B'
       END AS yr_pd_ind,
       year_num*100+pd_num AS yr_pd_num,
       dense_rank() OVER (ORDER BY year_num*100+week_num DESC) AS wk_index,
                         dense_rank() OVER (ORDER BY year_num*100+pd_num DESC) AS pd_index
FROM mstr_v.local_cal_date t1,

  (SELECT max(year_num*100+pd_num) max_year_pd_num,
          min(year_num*100+pd_num) min_year_pd_num
   FROM mstr_v.local_cal_date
   WHERE cal_date IN (date(date_sub(CURRENT_DATE, cast(date_format(CURRENT_DATE, 'u') AS int)+105*7+1)),
                      date(date_sub(CURRENT_DATE, cast(date_format(CURRENT_DATE, 'u') AS int)))) ) t2
WHERE cal_date BETWEEN date(date_sub(CURRENT_DATE, cast(date_format(CURRENT_DATE, 'u') AS int)+105*7)) 
AND date(date_sub(CURRENT_DATE, cast(date_format(CURRENT_DATE, 'u') AS int)+1))

【问题讨论】:

【参考方案1】:

如果将当前位于 t2 内的 where 子句移动到 case 语句中并使用 over() 计算 min 和 max,则无需第二次表扫描(在同一子查询中)即可计算在 t2 子查询中计算的列:

SELECT cal_date,
       regexp_replace(cal_date, '-', '') AS PC_cal_date,
       year_num*100+week_num AS year_week_num,
       CASE
           WHEN year_num*100+pd_num IN (min_year_pd_num, max_year_pd_num) THEN 'A'
           ELSE 'B'
       END AS yr_pd_ind,
       year_num*100+pd_num AS yr_pd_num,
       dense_rank() OVER (ORDER BY year_num*100+week_num DESC) AS wk_index,
                         dense_rank() OVER (ORDER BY year_num*100+pd_num DESC) AS pd_index
FROM (select t1.*,            
             max(case when cal_date IN (date(date_sub(CURRENT_DATE, cast(date_format(CURRENT_DATE, 'u') AS int)+105*7+1)),
                                        date(date_sub(CURRENT_DATE, cast(date_format(CURRENT_DATE, 'u') AS int))))        
                      then  year_num*100+pd_num end) over() as max_year_pd_num,
             min(case when cal_date IN (date(date_sub(CURRENT_DATE, cast(date_format(CURRENT_DATE, 'u') AS int)+105*7+1)),
                                        date(date_sub(CURRENT_DATE, cast(date_format(CURRENT_DATE, 'u') AS int)))) 
                      then year_num*100+pd_num end) over() as min_year_pd_num
      from mstr_v.local_cal_date t1
)t1
WHERE cal_date BETWEEN date(date_sub(CURRENT_DATE, cast(date_format(CURRENT_DATE, 'u') AS int)+105*7)) 
AND date(date_sub(CURRENT_DATE, cast(date_format(CURRENT_DATE, 'u') AS int)+1))

【讨论】:

以上是关于在重写此查询时需要指导的主要内容,如果未能解决你的问题,请参考以下文章

需要指导以简化此查询

在重写使用光标的查询时需要帮助

在 Ruby on Rails 4 中使用 Active Record 或 Squeel Gem 重写 SQL 查询

java 中 一般打印对象不都是需要重写toString()方法吗?

将旧版 SQL 查询转换为标准 SQL

301 Htaccess 重写规则查询字符串