SQL 服务器 - 在子查询中使用多个日期范围进行查询
SQL Server - Query With Multiple Date Ranges in subquery
我在另一个需要使用多个日期范围的查询中使用了条件聚合。在这种情况下,子查询中需要日期范围。
我想知道我是否可以在一个查询中获得想要的结果(不使用 UNION)。
我需要检查给定记录是否存在于具有日期范围的子查询中。因为我需要使用 EXISTS 而不是连接 - 我 运行 进入这个问题。
这是一个示例 script/data。预期结果table用于演示
IF OBJECT_ID('tempdb..#Entity') IS NOT NULL DROP TABLE #Entity
IF OBJECT_ID('tempdb..#EntityDate') IS NOT NULL DROP TABLE #EntityDate
IF OBJECT_ID('tempdb..#ExpectedOutput') IS NOT NULL DROP TABLE #ExpectedOutput
> `DECLARE @FortnightStart DATETIME = '2020/08/01', @FortnightEnd DATETIME = '2020/08/14 23:59:59'
DECLARE @QuarterStart DATE = '2020/04/01', @QuarterEnd DATE = '2020/06/30 23:59:59'
> `SELECT 'Fortnight' DateRange, @FortnightStart 'Start', @FortnightEnd 'End'
UNION
SELECT 'Quarter', @QuarterStart, @QuarterEnd
CREATE TABLE #Entity (
EntityId INT IDENTITY(1, 1),
EntityName VARCHAR(50)
)
CREATE TABLE #EntityDate (
EntityDateId INT IDENTITY(1, 1),
EntityId INT,
SubmittedDate DATETIME
)
ALTER TABLE #EntityDate ADD CONSTRAINT FK_EntityDate_Entity FOREIGN KEY (EntityId) REFERENCES Entity(EntityId)
INSERT INTO #Entity (EntityName)
SELECT 'Alice'
UNION
SELECT 'Bob'
UNION
SELECT 'Cameron'
UNION
SELECT 'Diego'
UNION
SELECT 'Elliot'
SELECT * FROM #Entity
INSERT INTO #EntityDate(EntityId, SubmittedDate)
SELECT 1, '08/01/2020 11:00:00' -- only 1 record is expected in the output for this Entity
UNION
SELECT 1, '08/10/2020 10:00:00'
UNION
SELECT 1, '04/10/2020 10:00:00' -- this record should show up for the quarter date range
UNION
SELECT 2, '06/01/2020 11:00:00' --
UNION
SELECT 3, '05/01/2020' -- only 1 record is expected in the output for this Entity
UNION
SELECT 3, '06/01/2020'
UNION
SELECT 4, '10/01/2021' -- does not fit in any date range
UNION
SELECT 5, '08/02/2020'
SELECT *
FROM #EntityDate d
INNER JOIN #Entity e ON d.EntityId = e.EntityId
SELECT *
FROM #Entity E
WHERE EXISTS ( SELECT 1
FROM #EntityDate d
WHERE SubmittedDate BETWEEN @FortnightStart AND @FortnightEnd AND e.EntityId = D.EntityId
)
SELECT *
FROM #Entity E
WHERE EXISTS ( SELECT 1
FROM #EntityDate d
WHERE SubmittedDate BETWEEN @QuarterStart AND @QuarterEnd AND e.EntityId = D.EntityId
)
CREATE TABLE #ExpectedOutput
(
EntityId INT,
DateRange VARCHAR(50)
)
INSERT INTO #ExpectedOutput (EntityId, DateRange)
SELECT 1, 'Fortnight'
UNION
SELECT 5, 'Fortnight'
UNION
SELECT 1, 'Quarter'
UNION
SELECT 2, 'Quarter'
UNION
SELECT 3, 'Quarter'
SELECT o.*, e.EntityName
FROM #ExpectedOutput o
INNER JOIN #Entity e ON o.EntityId = e.EntityId
ORDER BY O.DateRange, o.EntityId
尝试这样的事情
SELECT * FROM (VALUES(1, '08/01/2020 11:00:00'),
(1, '08/10/2020 10:00:00'),
(1, '04/10/2020 10:00:00'),
(2, '06/01/2020 11:00:00'), --
(3, '05/01/2020'),
(3, '06/01/2020'),
(4, '10/01/2021'),
(5, '08/02/2020')
) EntityIDate(EntityId,SubmittedDate)
使用您在脚本顶部创建的虚拟日期 table,您需要将其加入 Entity
,使用 EXISTS
作为 ON
条件
DECLARE @FortnightStart DATETIME = '2020/08/01', @FortnightEnd DATETIME = '2020/08/14 23:59:59';
DECLARE @QuarterStart DATE = '2020/04/01', @QuarterEnd DATE = '2020/06/30 23:59:59';
WITH Dates AS (
SELECT 'Fortnight' DateRange, @FortnightStart Start, @FortnightEnd [End]
UNION ALL
SELECT 'Quarter', @QuarterStart, @QuarterEnd
)
SELECT
e.EntityId,
d.DateRange
FROM Dates d
JOIN #Entity E ON EXISTS (SELECT 1
FROM #EntityDate ed
WHERE ed.SubmittedDate BETWEEN d.Start AND d.[End]
AND ed.EntityId = e.EntityId
);
为什么你有这样的要求?使用多个 UNION ALL
有什么危害?性能方面没有坏处。
希望我正确理解了您的要求。
DECLARE @FortnightStart DATETIME = '2020/08/01', @FortnightEnd DATETIME = '2020/08/14 23:59:59'
DECLARE @QuarterStart DATE = '2020/04/01', @QuarterEnd DATE = '2020/06/30 23:59:59'
;WITH CTE
AS (SELECT 1 AS Orderflg,
'Fortnight' DateRange,
@FortnightStart 'StartDate',
@FortnightEnd 'EndDate'
UNION ALL
SELECT 2,
'Quarter',
@QuarterStart,
@QuarterEnd),
CTE1
AS (SELECT *,
ROW_NUMBER() OVER(PARTITION BY EntityId,
Orderflg
ORDER BY SubmittedDate) rn
FROM #EntityDate d
CROSS APPLY
(
SELECT TOP 1 DateRange,
Orderflg
FROM CTE C
WHERE SubmittedDate >= StartDate
AND SubmittedDate < EndDate
) ca -- e.EntityId = D.EntityId
)
SELECT e.EntityId,
DateRange,
EntityName
FROM CTE1 C1
INNER JOIN #Entity E ON c1.EntityId = e.EntityId
WHERE rn = 1
ORDER BY Orderflg;
我在另一个需要使用多个日期范围的查询中使用了条件聚合。在这种情况下,子查询中需要日期范围。
我想知道我是否可以在一个查询中获得想要的结果(不使用 UNION)。
我需要检查给定记录是否存在于具有日期范围的子查询中。因为我需要使用 EXISTS 而不是连接 - 我 运行 进入这个问题。
这是一个示例 script/data。预期结果table用于演示
IF OBJECT_ID('tempdb..#Entity') IS NOT NULL DROP TABLE #Entity
IF OBJECT_ID('tempdb..#EntityDate') IS NOT NULL DROP TABLE #EntityDate
IF OBJECT_ID('tempdb..#ExpectedOutput') IS NOT NULL DROP TABLE #ExpectedOutput
> `DECLARE @FortnightStart DATETIME = '2020/08/01', @FortnightEnd DATETIME = '2020/08/14 23:59:59'
DECLARE @QuarterStart DATE = '2020/04/01', @QuarterEnd DATE = '2020/06/30 23:59:59'
> `SELECT 'Fortnight' DateRange, @FortnightStart 'Start', @FortnightEnd 'End'
UNION
SELECT 'Quarter', @QuarterStart, @QuarterEnd
CREATE TABLE #Entity (
EntityId INT IDENTITY(1, 1),
EntityName VARCHAR(50)
)
CREATE TABLE #EntityDate (
EntityDateId INT IDENTITY(1, 1),
EntityId INT,
SubmittedDate DATETIME
)
ALTER TABLE #EntityDate ADD CONSTRAINT FK_EntityDate_Entity FOREIGN KEY (EntityId) REFERENCES Entity(EntityId)
INSERT INTO #Entity (EntityName)
SELECT 'Alice'
UNION
SELECT 'Bob'
UNION
SELECT 'Cameron'
UNION
SELECT 'Diego'
UNION
SELECT 'Elliot'
SELECT * FROM #Entity
INSERT INTO #EntityDate(EntityId, SubmittedDate)
SELECT 1, '08/01/2020 11:00:00' -- only 1 record is expected in the output for this Entity
UNION
SELECT 1, '08/10/2020 10:00:00'
UNION
SELECT 1, '04/10/2020 10:00:00' -- this record should show up for the quarter date range
UNION
SELECT 2, '06/01/2020 11:00:00' --
UNION
SELECT 3, '05/01/2020' -- only 1 record is expected in the output for this Entity
UNION
SELECT 3, '06/01/2020'
UNION
SELECT 4, '10/01/2021' -- does not fit in any date range
UNION
SELECT 5, '08/02/2020'
SELECT *
FROM #EntityDate d
INNER JOIN #Entity e ON d.EntityId = e.EntityId
SELECT *
FROM #Entity E
WHERE EXISTS ( SELECT 1
FROM #EntityDate d
WHERE SubmittedDate BETWEEN @FortnightStart AND @FortnightEnd AND e.EntityId = D.EntityId
)
SELECT *
FROM #Entity E
WHERE EXISTS ( SELECT 1
FROM #EntityDate d
WHERE SubmittedDate BETWEEN @QuarterStart AND @QuarterEnd AND e.EntityId = D.EntityId
)
CREATE TABLE #ExpectedOutput
(
EntityId INT,
DateRange VARCHAR(50)
)
INSERT INTO #ExpectedOutput (EntityId, DateRange)
SELECT 1, 'Fortnight'
UNION
SELECT 5, 'Fortnight'
UNION
SELECT 1, 'Quarter'
UNION
SELECT 2, 'Quarter'
UNION
SELECT 3, 'Quarter'
SELECT o.*, e.EntityName
FROM #ExpectedOutput o
INNER JOIN #Entity e ON o.EntityId = e.EntityId
ORDER BY O.DateRange, o.EntityId
尝试这样的事情
SELECT * FROM (VALUES(1, '08/01/2020 11:00:00'),
(1, '08/10/2020 10:00:00'),
(1, '04/10/2020 10:00:00'),
(2, '06/01/2020 11:00:00'), --
(3, '05/01/2020'),
(3, '06/01/2020'),
(4, '10/01/2021'),
(5, '08/02/2020')
) EntityIDate(EntityId,SubmittedDate)
使用您在脚本顶部创建的虚拟日期 table,您需要将其加入 Entity
,使用 EXISTS
作为 ON
条件
DECLARE @FortnightStart DATETIME = '2020/08/01', @FortnightEnd DATETIME = '2020/08/14 23:59:59';
DECLARE @QuarterStart DATE = '2020/04/01', @QuarterEnd DATE = '2020/06/30 23:59:59';
WITH Dates AS (
SELECT 'Fortnight' DateRange, @FortnightStart Start, @FortnightEnd [End]
UNION ALL
SELECT 'Quarter', @QuarterStart, @QuarterEnd
)
SELECT
e.EntityId,
d.DateRange
FROM Dates d
JOIN #Entity E ON EXISTS (SELECT 1
FROM #EntityDate ed
WHERE ed.SubmittedDate BETWEEN d.Start AND d.[End]
AND ed.EntityId = e.EntityId
);
为什么你有这样的要求?使用多个 UNION ALL
有什么危害?性能方面没有坏处。
希望我正确理解了您的要求。
DECLARE @FortnightStart DATETIME = '2020/08/01', @FortnightEnd DATETIME = '2020/08/14 23:59:59'
DECLARE @QuarterStart DATE = '2020/04/01', @QuarterEnd DATE = '2020/06/30 23:59:59'
;WITH CTE
AS (SELECT 1 AS Orderflg,
'Fortnight' DateRange,
@FortnightStart 'StartDate',
@FortnightEnd 'EndDate'
UNION ALL
SELECT 2,
'Quarter',
@QuarterStart,
@QuarterEnd),
CTE1
AS (SELECT *,
ROW_NUMBER() OVER(PARTITION BY EntityId,
Orderflg
ORDER BY SubmittedDate) rn
FROM #EntityDate d
CROSS APPLY
(
SELECT TOP 1 DateRange,
Orderflg
FROM CTE C
WHERE SubmittedDate >= StartDate
AND SubmittedDate < EndDate
) ca -- e.EntityId = D.EntityId
)
SELECT e.EntityId,
DateRange,
EntityName
FROM CTE1 C1
INNER JOIN #Entity E ON c1.EntityId = e.EntityId
WHERE rn = 1
ORDER BY Orderflg;