Альтернатива отдельному запросу для Dynamic PIVOT - PullRequest
0 голосов
/ 03 мая 2018

Несколько дней это было для меня чем-то вроде мозгов, и я не могу решить эту проблему.

По сути, у меня есть таблица 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 (которые являются параметрами).

Вывод цели должен выглядеть примерно так:

enter image description here

Я пытался расширить 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 запроса.

1 Ответ

0 голосов
/ 03 мая 2018

Невозможно создать набор результатов с неизвестным (или управляемым данными) числом столбцов без использования динамического sql. Это не головоломка, это кирпичная стена.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...