当前位置: 首页 > 面试题库 >

使用日期范围的可能的递归CTE查询

华恩
2023-03-14
问题内容

不知道如何在这个标题上加上标题!

我有以下数据:

IF OBJECT_ID ('tempdb..#data') IS NOT NULL DROP TABLE #data
CREATE TABLE #data
(
id UNIQUEIDENTIFIER
,reference NVARCHAR(30)
,start_date DATETIME
,end_date DATETIME
,lapse_date DATETIME
,value_received DECIMAL(18,3)
)

INSERT INTO #data VALUES ('BE91B9C1-C02F-46F7-9B63-4D0B25D9BA2F','168780','2006-05-01 00:00:00.000',NULL,'2011-09-27 00:00:00.000',537.42)
INSERT INTO #data VALUES ('B538F123-C839-447A-B300-5D16EACF4560','320858','2011-08-08 00:00:00.000',NULL,NULL,0)
INSERT INTO #data VALUES ('1922465D-2A55-434D-BAAA-8E15D681CF12','306597','2011-04-08 00:00:00.000','2011-06-22 13:14:40.083','2011-08-07 00:00:00.000',12)
INSERT INTO #data VALUES ('7DF8FBCC-B490-4892-BDC5-8FD2D73B0323','321461','2011-07-01 00:00:00.000',NULL,'2011-09-25 00:00:00.000',8.44)
INSERT INTO #data VALUES ('1EC2E754-F325-4313-BDFC-9010E255F6FE','74215','2000-10-31 00:00:00.000',NULL,'2011-08-30 00:00:00.000',258)
INSERT INTO #data VALUES ('9E59B09C-0198-48AC-8EEC-A0D76CEA9385','169194','2008-06-25 00:00:00.000',NULL,'2011-09-25 00:00:00.000',1766.4)
INSERT INTO #data VALUES ('97CF6C0F-324A-49A6-B9D8-AC848A1F821A','288039','2010-09-01 00:00:00.000','2011-07-29 00:00:00.000','2011-08-21 00:00:00.000',55)
INSERT INTO #data VALUES ('97CF6C0F-324A-49A6-B9D8-AC848A1F821A','324423','2011-08-01 00:00:00.000',NULL,'2011-09-25 00:00:00.000',5)
INSERT INTO #data VALUES ('D5E5197A-E8E1-468C-9991-C8712224C2BF','323395','2011-08-25 00:00:00.000',NULL,NULL,0)
INSERT INTO #data VALUES ('0EC4976C-16B9-4C99-BD07-D0CBDF014D32','323741','2011-08-25 00:00:00.000',NULL,NULL,0)

我希望能够根据以下标准将所有引用分为“活动”,“失效”或“新”类别:

  • Active 起始日期小于参考月份的最后日期,失效日期在上个月的最后一天之后,并且value_received> 0;

  • New 开始日期在参考月份之内;

  • Lapsed 失效日期在参考月份之内。

然后将这些定义应用到连续13个月的每个引用中(因此从Now追溯到2010年7月),以便每个月我可以看到每个组中有多少引用。

我可以使用以下内容来定义当前月份:

select 
id
,reference
,start_date
,end_date
,lapse_date 
,value_received
,CASE   WHEN start_date < DATEADD(month,DATEPART(Month,GETDATE()) + 1,DATEADD(year,DATEPART(year,GETDATE())-1900,0)) --next month start date
        AND lapse_date > DATEADD(ms,-3,DATEADD(mm,DATEDIFF(mm,0,GETDATE())+1,0)) --last day of current month
        AND value_received > 0
        THEN 'Active'
        WHEN lapse_date < DATEADD(month,DATEPART(Month,GETDATE()) + 1,DATEADD(year,DATEPART(year,GETDATE())-1900,0)) --next month start
            AND lapse_date > DATEADD(ms,-3,DATEADD(mm,DATEDIFF(mm,0,GETDATE()),0)) --last day of prior month
        THEN 'lapse'
        WHEN start_date < DATEADD(month,DATEPART(Month,GETDATE()) + 1,DATEADD(year,DATEPART(year,GETDATE())-1900,0)) --next month start date
        AND start_date > DATEADD(ms,-3,DATEADD(mm,DATEDIFF(mm,0,GETDATE()),0)) --last day of prior month
        THEN 'New'
        ELSE 'Not applicable'
 END AS [type]
from #data

但是我看不到一个很好的/有效的方法(除了重复此查询13次并合并结果,我知道这很糟糕)

使用当前月份作为锚点并使用递归(如果这样的话,一些指针将是最好的选择)吗?

一如既往的帮助:)

编辑为包含实际解决方案

如果任何人都感兴趣,这是我使用的最后一个查询:

;WITH Months as 
(
SELECT DATEADD(ms,-3,DATEADD(mm,DATEDIFF(mm,0,GETDATE())+1,0)) as month_end
,0 AS level
UNION ALL     
SELECT DATEADD(month, -1, month_end)as month_end
,level + 1 FROM Months
WHERE level < 13 
) 
SELECT 
DATENAME(Month,month_end) + ' ' + DATENAME(YEAR,month_end) as date
,SUM(CASE WHEN start_date <= month_end
        AND Month(start_date) <> MONTH(Month_end)
        AND lapse_date > Month_end 
 THEN 1 ELSE 0 END) AS Active
,SUM(CASE WHEN start_date <= Month_end 
        AND DATENAME(MONTH,start_date) + ' ' + DATENAME(YEAR,start_date) = 
        DATENAME(MONTH,month_end) + ' ' + DATENAME(YEAR,month_end)
THEN 1 ELSE 0 END) AS New
,SUM(CASE WHEN lapse_date <= Month_end 
        AND Month(lapse_date) = MONTH(Month_end)
THEN 1 ELSE 0 END) AS lapse
FROM #data
CROSS JOIN Months
WHERE id IS NOT NULL
AND start_date IS NOT NULL
GROUP BY DATENAME(Month,month_end)  + ' ' + DATENAME(YEAR,month_end) 
ORDER by MAX(level) ASC

问题答案:

您在这里不需要“真实的”递归CTE。不过,您可以使用一个作为月份参考:

;WITH Months
as
(
    SELECT DATEADD(day, -DATEPART(day, GETDATE())+1, GETDATE()) as 'MonthStart'
    UNION ALL
    SELECT DATEADD(month, -1, MonthStart) as 'MonthStart'
    FROM Months
)

然后,你可以JOINSELECT TOP 13 * FROM Months你上面的查询。

我不会尝试解析所有CASE语句,但是从本质上讲,您可以GROUP BY在日期和MonthStart字段上使用a ,例如:

GROUP BY Datepart(year, monthstart), Datepart(month, monthstart)

并按月汇总。将所有选项(活动,失效等)列为一列并使用来计算每个选项可能是最容易的SUM(CASE WHEN ... THEN 1 ELSE 0 END),因为使用会更容易GROUP BY



 类似资料:
  • > 每个对象表示一个重复发生的事件。该事件可以在多个日期发生。因此,请考虑以下内容: 我有一个日历在客户端,用户可以选择一个日期范围。 > 对所选日期范围的每个条目进行调用,并在客户端处理聚合。问题是会有大量的读取,因为我们会多次读取重叠的日期范围内的同一个列表对象。 尝试使用类似ElasticSearch/Algolia的服务来完成此操作 任何建议都会很有帮助!

  • 问题内容: 以下问题的正确答案: 如果我没有记错的话,那是在11.2.0.3或更高版本中修复的错误。(无论如何不再支持11.2.0.1.11.2.0.4是唯一仍受支持的11.2版本)-@a_horse_with_no_name 错误号为11840579,已在11.2.0.3和12.1.0.1中进行了修复-@a_horse_with_no_name问题 I have a table The foll

  • 我的文档中有一个日期范围(使用日期对象)如下所示 我试图弄清楚如何构建一个查询来返回包含特定日期的所有事件,例如,像.... 如果查询显示类似这样的内容,但在Firestore查询限制下可能不可能出现这种情况。 因此,我一直在挠头几个小时,要么为此构建一个查询,要么以某种方式结构我的数据,以允许这样做。 这有可能吗?

  • 问题内容: 嗨,我有供cpu使用的文档,其中包含date_time字段。现在,我想查找日期范围内的avg cpu用法。我想出了以下解决方案。如果我是Elastic Search的新手,请告诉我是否有任何先进或更好的方法。 现在,上面的查询返回我期望的文档,该文档在/日期范围内。现在,我要做的是,使用这些文档找到所有唯一的日期,并将这些唯一的日期组合存储在中,然后针对其中的所有项目执行以下查询 现在

  • 问题内容: 我有一个看起来像这样的数据库表: 写入此日志时,它包含日志记录和unix时间戳。我需要的是获取每周报告,以了解每周有多少日志记录。这是我写的查询: 这给出了这样的结果: 伟大的!但是我想看到的是一个日期范围,如,所以我的结果集如下所示: 有什么办法吗? 问题答案: 使用以获得合适的日期一样,然后用得到你需要的格式。

  • 我需要帮助查询与日期范围的长收集。请参阅下面的示例文档。我想用日期范围查询startTime字段。