查找不在给定日期范围内的日期

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

我有一个应用程序,我需要存储在我的数据库中的货币兑换率。 我有一个表,用于存储货币汇率,如下

enter image description here

我想知道是否有任何日期,我的数据库中没有转换率,以便我可以插入它。

考虑到我没有上表中一周的汇率,结果应该给我所有没有汇率的 7 个日期。

我创建了一个日历表,其中存储了过去 10 年的所有日期。但我不确定,如何连接两个表以从日历表中获取日期,该日期不存在于

FromDate
ToDate
表中的
CurrancyRate

创建日历表的脚本如下

IF EXISTS (SELECT * FROM information_schema.tables WHERE Table_Name = 'Calendar' AND Table_Type = 'BASE TABLE')
BEGIN
DROP TABLE [Calendar]
END

CREATE TABLE [Calendar]
(
    [CalendarDate] DATETIME
)

DECLARE @StartDate DATETIME
DECLARE @EndDate DATETIME
SET @StartDate = GETDATE()
SET @EndDate = DATEADD(d, 3650, @StartDate)

WHILE @StartDate <= @EndDate
      BEGIN
             INSERT INTO [Calendar]
             (
                   CalendarDate
             )
             SELECT
                   @StartDate

             SET @StartDate = DATEADD(dd, 1, @StartDate)
             
      END
sql sql-server
1个回答
0
投票

Thom A 和 T N 的剧本都不错。但是,GENERATE_SERIES() 函数目前仅在 SQL 2022 中可用。如果您使用 SQL 2019 或更早版本,我建议您使用其他方法来生成日历表。不要使用 WHILE 循环,因为它的性能很差。

选项 1 使用递归 SQL 和公用表表达式 (CTE):

-- Define the start and end dates
DECLARE @StartDate DATE = '2020-01-01';
DECLARE @EndDate DATE = '2030-12-31';

-- Create the calendar table using a recursive CTE
WITH CalendarCTE AS (
    SELECT @StartDate AS CalendarDate
    UNION ALL
    SELECT DATEADD(DAY, 1, CalendarDate)
    FROM CalendarCTE
    WHERE DATEADD(DAY, 1, CalendarDate) <= @EndDate
)
SELECT CalendarDate
FROM CalendarCTE
OPTION (MAXRECURSION 5000); -- Allow recursion to continue beyond the default 100 levels

仅使用 CTE 的选项 2:

-- Define the start and end dates
DECLARE @StartDate DATE = '2020-01-01';
DECLARE @EndDate DATE = '2030-12-31';


-- Create a tally table with numbers from 1 to 1000000
IF OBJECT_ID('tempdb..#Tally') IS NOT NULL DROP TABLE #Tally;
CREATE TABLE #Tally (N INT);

WITH E1(N) AS (SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
               SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1),  -- E1 has 10 records.
     E2(N) AS (SELECT 1 FROM E1 a, E1 b), -- E2 has 10*10=100 records.
     E4(N) AS (SELECT 1 FROM E2 a, E2 b), -- E4 has 100*100=10,000 records.
     E8(N) AS (SELECT 1 FROM E1 a, E4 b), -- E8 has 10*10,000=100,000 records. This is already more than enough for 200 years.
     --CteTally(N) AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E8)
     CteTally(N) AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E8)
INSERT INTO #Tally(N)
SELECT N
FROM CteTally


-- Generate the calendar table. Since the tally table starts with 1, we need to make it minus 1 to start with zero.
SELECT DATEADD(DAY, T.N-1, @StartDate) AS col
FROM #Tally T
WHERE T.N <= DATEDIFF(DAY, @StartDate, @EndDate) + 1
© www.soinside.com 2019 - 2024. All rights reserved.