SQL只选择缺少的月份

问题描述 投票:0回答:1

注意输出中缺少2017-04-01、2018-02-01、2018-07-01和2019-01-01这几个月。我想只显示缺少的那几个月。有谁知道该如何去做?

查询。

SELECT TO_DATE("Month", 'mon''yy') as dates FROM sample_sheet
group by dates
order by dates asc;

输出。

2017-01-01
2017-02-01
2017-03-01
2017-05-01
2017-06-01
2017-07-01
2017-08-01
2017-09-01
2017-10-01
2017-11-01
2017-12-01
2018-01-01
2018-03-01
2018-04-01
2018-05-01
2018-06-01
2018-08-01
2018-09-01
2018-10-01
2018-11-01
2018-12-01
2019-02-01
2019-03-01
2019-04-01
sql vertica
1个回答
0
投票

我不懂Vertica,所以我在Microsoft SQL Server中写了一个工作概念证明,并试图根据在线文档将其转换为Vertica语法。

它看起来应该是这样的。

with 
months as (
   select 2017 as date_year, 1 as date_month, to_date('2017-01-01', 'YYYY-MM-DD') as first_date, to_date('2017-01-31', 'yyyy-mm-dd') as last_date
   union all
   select
      year(add_months(first_date, 1)) as date_year,
      month(add_months(first_date, 1)) as date_month, 
      add_months(first_date, 1) as first_date, 
      last_day(add_months(first_date, 1)) as last_date 
   from months
   where first_date < current_date
),
sample_dates (a_date) as (
   select to_date('2017-01-15', 'YYYY-MM-DD') union all
   select to_date('2017-01-22', 'YYYY-MM-DD') union all
   select to_date('2017-02-01', 'YYYY-MM-DD') union all
   select to_date('2017-04-15', 'YYYY-MM-DD') union all
   select to_date('2017-06-15', 'YYYY-MM-DD') 
)
select * 
from sample_dates right join months on sample_dates.a_date between first_date and last_date
where sample_dates.a_date is null

是一个递归的动态表,存放2017-01以来的所有月份,每月的第一天和最后一天。样本日期 只是一个测试逻辑的日期列表--你应该用你自己的表来代替它。

一旦你建立了月历表,你需要做的就是使用一个外部查询来检查你的日期,看看有哪些日期不在任何一个时期之间。首日最后日期 列。


0
投票

你可以将第一个输入日期和最后一个输入日期之间的所有日期建立一个TIMESERIES(TIMESERIES的最高粒度是天。),并从中只过滤出月份的首日;然后将该建立的月份首日序列与你的输入进行左联接,找出联接失败的地方,从联接的输入分支中检查是否有NULLS。

WITH
-- your input
input(mth1st) AS (
          SELECT DATE '2017-01-01'
UNION ALL SELECT DATE '2017-02-01'
UNION ALL SELECT DATE '2017-03-01'
UNION ALL SELECT DATE '2017-05-01'
UNION ALL SELECT DATE '2017-06-01'
UNION ALL SELECT DATE '2017-07-01'
UNION ALL SELECT DATE '2017-08-01'
UNION ALL SELECT DATE '2017-09-01'
UNION ALL SELECT DATE '2017-10-01'
UNION ALL SELECT DATE '2017-11-01'
UNION ALL SELECT DATE '2017-12-01'
UNION ALL SELECT DATE '2018-01-01'
UNION ALL SELECT DATE '2018-03-01'
UNION ALL SELECT DATE '2018-04-01'
UNION ALL SELECT DATE '2018-05-01'
UNION ALL SELECT DATE '2018-06-01'
UNION ALL SELECT DATE '2018-08-01'
UNION ALL SELECT DATE '2018-09-01'
UNION ALL SELECT DATE '2018-10-01'
UNION ALL SELECT DATE '2018-11-01'
UNION ALL SELECT DATE '2018-12-01'
UNION ALL SELECT DATE '2019-02-01'
UNION ALL SELECT DATE '2019-03-01'
UNION ALL SELECT DATE '2019-04-01'
)
,
-- need a series of month's firsts
-- TIMESERIES works for INTERVAL DAY TO SECOND
-- so build that timeseries, and filter out
-- the month's firsts
limits(mth1st) AS (
          SELECT MIN(mth1st) FROM input
UNION ALL SELECT MAX(mth1st) FROM input
)
,
alldates AS (
  SELECT dt::DATE FROM limits
  TIMESERIES dt AS '1 day' OVER(ORDER BY mth1st::TIMESTAMP)
)
,
allfirsts(mth1st) AS (
  SELECT dt FROM alldates WHERE DAY(dt)=1
)
SELECT
  allfirsts.mth1st
FROM allfirsts
LEFT JOIN input USING(mth1st)
WHERE input.mth1st IS NULL;
-- out    mth1st   
-- out ------------
-- out  2017-04-01
-- out  2018-02-01
-- out  2018-07-01
-- out  2019-01-01
© www.soinside.com 2019 - 2024. All rights reserved.