我有一个应用程序,我需要存储在我的数据库中的货币兑换率。 我有一个表,用于存储货币汇率,如下
我想知道是否有任何日期,我的数据库中没有转换率,以便我可以插入它。
考虑到我没有上表中一周的汇率,结果应该给我所有没有汇率的 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
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