Столбцы в строки с разными датами - PullRequest
0 голосов
/ 24 октября 2018

См. Пример данных и требуемый формат вывода ниже:

--SAMPLE TABLE
DECLARE @TEMP TABLE(
    DATA_DATE DATE,
    PROD_ID INT,
    CAT_CODE NVARCHAR(10),
    DATABUCKET_1 FLOAT,
    DATABUCKET_2 FLOAT,
    DATABUCKET_3 FLOAT,
    DATABUCKET_4 FLOAT,
    DATABUCKET_5 FLOAT);

INSERT INTO @TEMP VALUES('19-Oct-2018',100,'C1', 100,200,300,400,500)

SELECT * FROM @TEMP;

--PREFERRED OUTPUT FORMAT

SELECT 'C1' AS CAT_CODE, '19-Oct-2018' AS DATA_DATE, 100 AS UNITS, 'W1' AS WEEK_NUM--FOR DATABUCKET_1, THE DATE REMAINS SAME (AS DATA_DATE)
UNION ALL
SELECT 'C1' AS CAT_CODE, '12-Oct-2018' AS DATA_DATE, 200 AS UNITS, 'W2' AS WEEK_NUM--FOR DATABUCKET_2, THE DATE IS ONE WEEK BEFORE THAT OF W1
UNION ALL
SELECT 'C1' AS CAT_CODE, '05-Oct-2018' AS DATA_DATE, 300 AS UNITS, 'W3' AS WEEK_NUM--FOR DATABUCKET_3, THE DATE IS ONE WEEK BEFORE THAT OF W2
UNION ALL
SELECT 'C1' AS CAT_CODE, '28-Sep-2018' AS DATA_DATE, 400 AS UNITS, 'W4' AS WEEK_NUM--FOR DATABUCKET_4, THE DATE IS ONE WEEK BEFORE THAT OF W3
UNION ALL
SELECT 'C1' AS CAT_CODE, '21-Sep-2018' AS DATA_DATE, 500 AS UNITS, 'W5' AS WEEK_NUM--FOR DATABUCKET_5, THE DATE IS ONE WEEK BEFORE THAT OF W4

Несколько дополнительных точек:

  • Моя фактическая таблица содержит 106 блоков данных и несколько других столбцов.
  • Я дал только несколько здесь для простоты.
  • Каждый месяц поступает новый файл с другим значением DATA_DATE.
  • Значение DATA_DATE одинаково для одного файла и соответствует DATABUCKET_1
  • Для других DATABUCKETS это значение за неделю до этого.

Пожалуйста, дайте мне знать, как яможно добиться этого с помощью UNPIVOT.Заранее спасибо

Ответы [ 2 ]

0 голосов
/ 24 октября 2018

Это можно сделать довольно легко с помощью динамического оператора T-SQL.Идея состоит в том, чтобы заранее получить столбцы, которые нам нужны для отмены поворота, и добавить идентификатор заказа на добавление для каждого столбца.Этот номер будет использоваться для расчета последнего столбца и столбца даты.

Обратите внимание, я изменил @table variable на normal table, чтобы иметь возможность динамически читать столбцы из представления sys.columns.Конечно, в вашем реальном примере вы можете заполнять таблицу так, как вам нравится, и упорядочивать столбцы по своему усмотрению.

--DROP TABLE IF EXISTS [dbo].[Temp];

CREATE TABLE [dbo].[Temp](
    DATA_DATE DATE,
    PROD_ID INT,
    CAT_CODE NVARCHAR(10),
    DATABUCKET_1 FLOAT,
    DATABUCKET_2 FLOAT,
    DATABUCKET_3 FLOAT,
    DATABUCKET_4 FLOAT,
    DATABUCKET_5 FLOAT);

INSERT INTO [dbo].[Temp] VALUES ('19-Oct-2018',100,'C1', 100,200,300,400,500)

SELECT * FROM [dbo].[Temp];

--PREFERRED OUTPUT FORMAT

SELECT 'C1' AS CAT_CODE, '19-Oct-2018' AS DATA_DATE, 100 AS UNITS, 'W1' AS WEEK_NUM--FOR DATABUCKET_1, THE DATE REMAINS SAME (AS DATA_DATE)
UNION ALL
SELECT 'C1' AS CAT_CODE, '12-Oct-2018' AS DATA_DATE, 200 AS UNITS, 'W2' AS WEEK_NUM--FOR DATABUCKET_2, THE DATE IS ONE WEEK BEFORE THAT OF W1
UNION ALL
SELECT 'C1' AS CAT_CODE, '05-Oct-2018' AS DATA_DATE, 300 AS UNITS, 'W3' AS WEEK_NUM--FOR DATABUCKET_3, THE DATE IS ONE WEEK BEFORE THAT OF W2
UNION ALL
SELECT 'C1' AS CAT_CODE, '28-Sep-2018' AS DATA_DATE, 400 AS UNITS, 'W4' AS WEEK_NUM--FOR DATABUCKET_4, THE DATE IS ONE WEEK BEFORE THAT OF W3
UNION ALL
SELECT 'C1' AS CAT_CODE, '21-Sep-2018' AS DATA_DATE, 500 AS UNITS, 'W5' AS WEEK_NUM--FOR DATABUCKET_5, THE DATE IS ONE WEEK BEFORE THAT OF W4


DECLARE @DynamicTSQLStatement NVARCHAR(MAX)
       ,@ColumnNames NVARCHAR(MAX);

--DROP TABLE IF EXISTS #Columns;

CREATE TABLE #Columns
(
    [ID] INT
   ,[name] SYSNAME
);

INSERT INTO #Columns ([ID], [name])
SELECT ROW_NUMBER() OVER (ORDER BY [column_id]) - 1
      ,[name]
FROM [sys].[columns]
WHERE [object_id] = OBJECT_ID('[dbo].[Temp]')
    AND [name] LIKE '%DATABUCKET%';

SELECT @ColumnNames = STUFF
(
    (
        SELECT ',[' + [name] + ']'
        FROM #Columns
        ORDER BY [id]
        FOR XML PATH(''), TYPE
    ).value('.', 'NVARCHAR(MAX)')
   ,1
   ,1
   ,''
);


SET @DynamicTSQLStatement = N'
SELECT [CAT_CODE]
      ,DATEADD(WEEK, -1 * C.id, DATA_DATE) AS DATA_DATE
      ,value as UNITS
      ,''W'' + CAST(c.id + 1 AS VARCHAR(8)) as [WEEK_NUM]
FROM [dbo].[Temp] 
UNPIVOT
(
    [value] FOR [column] IN ('+ @ColumnNames +')
) UNPVT
INNER JOIN #Columns C
    ON UNPVT.[column] = c.[name] 
ORDER BY DATA_DATE DESC
;'

EXEC sp_executesql @DynamicTSQLStatement;

enter image description here

Итак, это идея.Это зависит от манипулирования кодом для работы с вашими данными.

0 голосов
/ 24 октября 2018

вы можете сделать un-pivot, используя CROSS APPLY

SELECT  t.CAT_CODE, d.*
FROM    @TEMP t
    CROSS APPLY
    (
        SELECT  DATA_DATE = t.DATA_DATE, UNITS = t.DATABUCKET_1, WEEK_NUM = 'W1'    union all
        SELECT  DATA_DATE = DATEADD(DAY, -7, t.DATA_DATE), UNITS = t.DATABUCKET_2, WEEK_NUM = 'W2'  union all
        SELECT  DATA_DATE = DATEADD(DAY, -14, t.DATA_DATE), UNITS = t.DATABUCKET_3, WEEK_NUM = 'W3' union all
        SELECT  DATA_DATE = DATEADD(DAY, -21, t.DATA_DATE), UNITS = t.DATABUCKET_4, WEEK_NUM = 'W4' union all
        SELECT  DATA_DATE = DATEADD(DAY, -28, t.DATA_DATE), UNITS = t.DATABUCKET_5, WEEK_NUM = 'W5'
    ) d

ИЛИ использовать таблицу подсчета / числа

SELECT  t.CAT_CODE, DATA_DATE = DATEADD(DAY, -7 * n, t.DATA_DATE),
    UNITS   = CASE n
            WHEN 0 THEN t.DATABUCKET_1
            WHEN 1 THEN t.DATABUCKET_2
            WHEN 2 THEN t.DATABUCKET_3
            WHEN 3 THEN t.DATABUCKET_4
            WHEN 4 THEN t.DATABUCKET_5
            END,
    WEEK_NUM = 'W' + CONVERT(VARCHAR(10), n + 1)
FROM    @TEMP t
    INNER JOIN NUMBERS n    ON  n   between 0 and 4

Если у вас действительно 106 блоков, вам следует подуматьнормализуй свой стол.В противном случае вам нужно повторить вышеизложенное для 106 строк.Другой способ - использовать Dynamic SQL для обработки

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