Несколько дней это было для меня чем-то вроде мозгов, и я не могу решить эту проблему.
По сути, у меня есть таблица Project, Resource and Allocation, в которой я ежедневно храню распределение Project-Resource. Вы можете использовать следующие запросы для построения структуры таблицы:
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;
А для заполнения таблицы размещения случайными фиктивными данными:
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
Я не смог найти агрегатную функцию для PIVOT, которая соответствует моей логике (в настоящее время у меня есть «ошибка», потому что я использую 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 запроса.