1

只能通过查询方式,没有执行块方式。

我尝试了以下但没有运气

SELECT
    TO_CHAR(dt, 'mon'),
    COUNT(*) AS noofsat
FROM
    (
        SELECT
            from_date + 1 AS dt
        FROM
            dual
        CONNECT BY
            level <= (
                SELECT
                    TO_DATE - from_date
                FROM
                    dual
            )
    )
WHERE
    TO_CHAR(dt, 'd') = 7
GROUP BY
    TO_CHAR(dt, 'mon')
HAVING
    COUNT(*) = 5

我只需要像 2019 年 8 月这样有五个星期六的月份和年份

4

3 回答 3

0

这是一个非常好的问题,在我的情况下,我需要完全相同的东西,但在 SQL Server 中,我就是这样做的,我将为那些最终在这里寻找 SQL Server 解决方案的人发布答案。

我最终在我的数据仓库中构建了一个日期维度并对其进行了查询:

DROP TABLE IF EXISTS ##Dates


 CREATE TABLE ##Dates(DateValue Date, 
                      YearValue INT, 
                      MonthValue INT, 
                      DayValue INT,
                      WeekDayValue INT)


  DECLARE @start DATE = '2019-01-01'
  WHILE @start < '2019-12-31'
  BEGIN
    INSERT INTO  ##Dates(DateValue,
                         YearValue, 
                         MonthValue, 
                         DayValue,
                         WeekDayValue)
    VALUES(@start,
            DATEPART(YY,@start), 
            DATEPART(mm,@start), -- In oracle TO_CHAR(dt, 'mon')
            DATEPART(dd,@start),
            DATEPART(dw,@start)) --In oracle  TO_CHAR(dt, 'd')

    SET @start = DATEADD(dd,1,@start)
  END



  SELECT MonthValue, SUM(CASE WHEN WeekDayValue = 7 THEN 1 ELSE 0 END) AS NumOfSaturdays FROM ##Dates
WHERE DateValue BETWEEN '2019-01-01' AND '2019-12-01'
GROUP BY MonthValue
HAVING SUM(CASE WHEN WeekDayValue = 7 THEN 1 ELSE 0 END) > 4

输出:

MonthValue  NumOfSaturdays
3            5
6            5
8            5
11           5
于 2019-07-08T17:23:45.503 回答
0

将您的日期源更改为:

    SELECT
        TO_DATE('20190101','YYYYMMDD') + (LEVEL - 1) AS dt
    FROM
        dual
    CONNECT BY
        level <= 365
于 2019-07-08T17:30:47.417 回答
0

您可以获得日期范围涵盖的每个月的开始时间;这使用一对虚构的固定值,因为不清楚您从哪里获得范围:

select add_months(trunc(date '2019-03-15', 'MM'), level - 1) as month_start
from dual
connect by level <= ceil(months_between(date '2019-11-21', date '2019-03-15'));

MONTH_STAR
----------
2019-03-01
2019-04-01
2019-05-01
2019-06-01
2019-07-01
2019-08-01
2019-09-01
2019-10-01
2019-11-01

9 rows selected. 

然后,您可以以各种方式操纵这些日期。您可以使用该next_day()功能查找该月的第一个星期六 - 基于一天,以防该月的 1 日本身是星期六。如果再加上 28 天,则得到该月的第五个星期六 - 或者,对于只有四个星期六的月份,下个月的第一个星期六。因此,如果您比较那些生成的星期六,如果它们在同一个月,那么该月实际上必须有五个星期六。

select month_start,
  next_day(month_start - 1, 'SATURDAY') as first_sat,
  next_day(month_start - 1, 'SATURDAY') + 28 as poss_fifth_sat,
  extract(month from month_start) as month_num,
  extract(month from (next_day(month_start - 1, 'SATURDAY') + 28)) as poss_fifth_sat_month
from (
  select add_months(trunc(date '2019-03-15', 'MM'), level - 1) as month_start
  from dual
  connect by level <= ceil(months_between(date '2019-11-21', date '2019-03-15'))
);

MONTH_STAR FIRST_SAT  POSS_FIFTH  MONTH_NUM POSS_FIFTH_SAT_MONTH
---------- ---------- ---------- ---------- --------------------
2019-03-01 2019-03-02 2019-03-30          3                    3 -- same
2019-04-01 2019-04-06 2019-05-04          4                    5
2019-05-01 2019-05-04 2019-06-01          5                    6
2019-06-01 2019-06-01 2019-06-29          6                    6 -- same
2019-07-01 2019-07-06 2019-08-03          7                    8
2019-08-01 2019-08-03 2019-08-31          8                    8 -- same
2019-09-01 2019-09-07 2019-10-05          9                   10
2019-10-01 2019-10-05 2019-11-02         10                   11
2019-11-01 2019-11-02 2019-11-30         11                   11 -- same

9 rows selected. 

您实际上不需要查看这些值,我只是在展示工作。但是您可以使用最后两个作为过滤器:

select month_start
from (
  select add_months(trunc(date '2019-03-15', 'MM'), level - 1) as month_start
  from dual
  connect by level <= ceil(months_between(date '2019-11-21', date '2019-03-15'))
)
where extract(month from month_start)
  = extract(month from (next_day(month_start - 1, 'SATURDAY') + 28));

MONTH_STAR
----------
2019-03-01
2019-06-01
2019-08-01
2019-11-01

然后,您可以根据需要格式化这些日期。


文档中提到了一个可能的问题(我确定还有其他问题):

参数char必须是会话日期语言中的一周中的一天,可以是全名或缩写。

因此,只要您的会话日期语言是英语,上面的代码就可以工作。如果您可以 100% 确定运行它的每个人将始终使用相同的会话设置,那么您使用该固定值(或任何合适的语言)。

如果您无法控制它,那么您就无法像使用其他一些功能那样覆盖日期语言。作为一种解决方法,您可以使用已知的星期六日期来获取当前日期语言的名称或星期六的缩写,而无需知道该语言实际上是什么:

alter session set nls_date_language = 'Spanish';

select month_start
from (
  select add_months(trunc(date '2019-03-15', 'MM'), level - 1) as month_start
  from dual
  connect by level <= ceil(months_between(date '2019-11-21', date '2019-03-15'))
)
where extract(month from month_start)
  = extract(month from (next_day(month_start - 1, to_char(date '2000-01-01', 'Dy')) + 28));

MONTH_STAR
----------
2019-03-01
2019-06-01
2019-08-01
2019-11-01
于 2019-07-08T17:59:07.420 回答