这对我来说已经有几天的脑筋急转弯了,我似乎无法解决它。
基本上我有一个项目,资源和分配表,我每天都会存储项目资源分配。您可以使用以下查询来构建表结构:
CREATE TABLE Projects ([ProjectID] INT IDENTITY PRIMARY KEY, [Name] VARCHAR(100));
CREATE TABLE Resources ([ResourceID] INT IDENTITY PRIMARY KEY,[Name] VARCHAR(100));
CREATE TABLE Allocation (
[Resource] INT FOREIGN KEY REFERENCES Resources (ResourceID),
[Project] INT FOREIGN KEY REFERENCES Projects (ProjectID),
[Date] DATE);
此外,您可以使用下一个查询来生成虚拟数据:
DECLARE @seed INT = 65;
;WITH proj_cte
AS (
SELECT @seed [seed]
UNION ALL
SELECT [seed] + 1
FROM proj_cte
WHERE [seed] < 90
)
INSERT INTO Projects (name)
SELECT 'Project ' + CHAR([seed])
FROM proj_cte;
;WITH res_cte
AS (
SELECT @seed [seed]
UNION ALL
SELECT [seed] + 1
FROM res_cte
WHERE [seed] < 90
)
INSERT INTO Resources (name)
SELECT 'Resource ' + CHAR([seed])
FROM res_cte;
并使用随机虚拟数据填充Allocation表:
CREATE UNIQUE NONCLUSTERED INDEX ncu_resource_project_date ON Allocation (Resource, Project, DATE);
INSERT INTO Allocation (Resource, Project, DATE)
SELECT DISTINCT ResourceId, ProjectID, AllocationDate
FROM (
SELECT ProjectID, abs(checksum(newid())) % 26 [ResourceId], cast(getdate() + (abs(checksum(newid())) % 26) AS DATE) [AllocationDate], abs(checksum(newid())) % 26 [filter]
FROM Projects
) f
WHERE f.ResourceId > 0
AND f.ProjectID > 0;
GO
INSERT INTO Allocation (Resource, Project, DATE)
SELECT DISTINCT ResourceId, ProjectID, AllocationDate
FROM (
SELECT ProjectID, abs(checksum(newid())) % 26 [ResourceId], cast(getdate() + (abs(checksum(newid())) % 26) AS DATE) [AllocationDate], abs(checksum(newid())) % 26 [filter]
FROM Projects
) f
INNER JOIN Allocation u
ON u.Resource = f.ResourceId
AND u.Project = f.ProjectID
AND f.AllocationDate <> u.[Date]
AND f.ResourceId > 0
AND f.ProjectID > 0
WHERE NOT EXISTS (
SELECT 1
FROM Allocation uin
WHERE uin.resource = u.resource
AND uin.project = uin.project
AND uin.DATE = f.AllocationDate;
) GO 250
现在,所有这一切的目标是编写一个可以参数化的单个查询(包括CTE),并返回类似于Allocation表的横截面的结果。在2个日期,@StartDate
和@EndDate
(这些是参数)。
目标输出应如下所示:
我试图扩展一个CTE,它生成@StartDate
和@EndDate
之间的日期范围,几乎可以通过以下查询找到一个有效的解决方案,但它有一些障碍:
我找不到符合我逻辑的PIVOT聚合函数(目前我有一个“bug”,因为我使用MIN(Project)
为整个资源返回MIN(Project)
日期范围)。
DECLARE @srcdt DATE = '20180101', @enddt DATE = '20180116';
;WITH dates
AS (
SELECT @srcdt srcdt
UNION ALL
SELECT dateadd(day, 1, srcdt)
FROM dates
WHERE srcdt < @enddt
)
SELECT pvt.*
FROM (
SELECT r.Name AS Resource, p.Name AS Project, DATE
FROM Allocation u
INNER JOIN Projects p
ON u.Project = p.ProjectID
RIGHT JOIN Resources r
ON u.resource = r.ResourceID
) pvt_src
PIVOT (min(Project) FOR [Date] IN ([2018-05-01], [2018-05-02], [2018-05-03], [2018-05-04], [2018-05-05], [2018-05-06], [2018-05-07], [2018-05-08], [2018-05-09], [2018-05-10], [2018-05-11], [2018-05-12], [2018-05-13], [2018-05-14], [2018-05-15], [2018-05-16], [2018-05-17], [2018-05-18], [2018-05-19], [2018-05-20], [2018-05-21], [2018-05-22], [2018-05-23], [2018-05-24], [2018-05-25], [2018-05-26], [2018-05-27], [2018-05-28], [2018-05-29], [2018-05-30])) pvt
我可以使用动态PIVOT和动态SQL来生成我PIVOT
的日期范围列,但这已经超过1个查询。
答案 0 :(得分:0)
在不使用动态sql的情况下,无法生成未知(或数据驱动)列数的结果集。这不是一个脑筋急转弯,它是一堵砖墙。