Динамическая сводная таблица, строки не сгущаются правильно - PullRequest
0 голосов
/ 28 июня 2018

Используя динамическую сводную таблицу, я пытаюсь отобразить строки для каждого года и месяца (YM), их почтовый индекс, регион, количество новых абонентов, количество повторных абонентов и счет того, что Тип абонентов это.

В сценарии, где у меня один и тот же YM, Zip, Region, но оба новых и повторных абонентов, я ожидаю увидеть строку как для нового, так и для повторного вызова, чтобы я мог различать счетчики типа вызывающего абонента.

Вот мой SQL Fiddle: http://sqlfiddle.com/#!18/56bc6/1

Я настроил данные до поворота как [InitialData], а ожидаемые результаты как [ExpectedResults]

Третий набор результатов, показанный в этой ссылке, находится там, где я сейчас нахожусь.

<Ч />

Здесь я спрятал скрипты создания и вставки SQL

CREATE TABLE InitialData
	(
	   [YM] int -- YYYYMM date format
	  ,[Zip] varchar(5)
	  ,[Region] varchar(18)
	  ,[NewCallers] int
	  ,[RepeatCallers] int
	  ,[CallerType] varchar(27)
	  ,[CallerTypeCount] int
	)
;
	
INSERT INTO InitialData
	([YM], [Zip], [Region], [NewCallers], [RepeatCallers], [CallerType], [CallerTypeCount])
VALUES
	(201805, NULL, NULL, 3, 0, 'Family / Friend', 3),
	(201805, NULL, NULL, 2, 0, 'Other', 2),
	(201805, NULL, NULL, 86, 0, 'Parent', 86),
	(201805, NULL, NULL, 6, 0, 'Professional', 6),
	(201805, '03598', NULL, 1, 0, 'Parent', 1),
	(201805, '56401', NULL, 1, 0, 'Parent', 1),
	(201805, '72209', NULL, 1, 0, 'Parent', 1),
	(201805, '85007', 'Phoenix South', 1, 0, 'Parent', 1),
	(201805, '85008', 'Phoenix South', 0, 3, 'Other', 3),
	(201805, '85008', 'Phoenix South', 2, 0, 'Family / Friend', 2),
	(201805, '85008', 'Phoenix South', 4, 0, 'Parent', 4),
	(201805, '85008', 'Phoenix South', 2, 0, 'Professional', 2),
	(201805, '85008', 'Phoenix South', 1, 0, 'Business', 1),
	(201805, '85009', 'Phoenix South', 1, 0, 'Parent', 1),
	(201805, '85013', 'Phoenix North', 2, 0, 'Parent', 2),
	(201805, '85014', 'Phoenix North', 1, 0, 'Parent', 1),
	(201805, '85143', 'Pinal', 2, 0, 'Parent', 2),
	(201805, '85201', 'Southeast Maricopa', 0, 4, 'Other', 4),
	(201805, '85203', 'Southeast Maricopa', 1, 0, 'Parent', 1),
	(201806, NULL, NULL, 1, 0, 'Other', 1),
	(201806, NULL, NULL, 70, 0, 'Parent', 70),
	(201806, NULL, NULL, 9, 0, 'Professional', 9),
	(201806, '85257', 'East Maricopa', 1, 0, 'Parent', 1),
	(201806, '85258', 'East Maricopa', 0, 2, 'Other', 2),
	(201806, '85258', 'East Maricopa', 2, 0, 'Parent', 2),
	(201806, '85283', 'East Maricopa', 6, 0, 'Parent', 6)
;

CREATE TABLE ExpectedResults
(
   [YM] int
  ,[Zip] varchar(5)
  ,[Region] varchar(18)
  ,[NewCallers] int
  ,[RepeatCallers] int
  ,[Business] int
  ,[Family / Friend] int  
  ,[Other] int
  ,[Parent] int
  ,[Professional] int
);

INSERT INTO ExpectedResults
VALUES
   (201805, null, null, 97, 0, 0, 3, 2, 86, 6)
  ,(201805, 03598, null, 1, 0, 0, 0, 0, 1, 0)
  ,(201805, 56401, null, 1, 0, 0, 0, 0, 1, 0)
  ,(201805, 72209, null, 1, 0, 0, 0, 0, 1, 0)
  ,(201805, 85007, 'Phoenix South', 1, 0, 0, 0, 0, 1, 0)
  ,(201805, 85008, 'Phoenix South', 0, 3, 0, 0, 3, 0, 0)
  ,(201805, 85008, 'Phoenix South', 9, 0, 1, 2, 0, 4, 2)
  ,(201805, 85009, 'Phoenix South', 1, 0, 0, 0, 0, 1, 0)
  ,(201805, 85013, 'Phoenix North', 2, 0, 0, 0, 0, 2, 0)
  ,(201805, 85014, 'Phoenix North', 1, 0, 0, 0, 0, 1, 0)
  ,(201805, 85143, 'Pinal', 2, 0, 0, 0, 0, 2, 0)
  ,(201805, 85201, 'Southeast Maricopa', 0, 4, 0, 0, 4, 0, 0)
  ,(201805, 85203, 'Southeast Maricopa', 1, 0, 0, 0, 0, 1, 0)
  ,(201806, null, null, 80, 0, 0, 1, 0, 70, 9)
  ,(201806, 85257, 'East Maricopa', 1, 0, 0, 0, 0, 1, 0)
  ,(201806, 85258, 'East Maricopa', 0, 2, 0, 0, 2, 0, 0)
  ,(201806, 85258, 'East Maricopa', 2, 0, 0, 0, 0, 2, 0)
  ,(201806, 85283, 'East Maricopa', 6, 0, 0, 0, 0, 6, 0);
  
CREATE TABLE CallerTypes
(
   [Id] UNIQUEIDENTIFIER
  ,[Name] VARCHAR(50)
);

INSERT INTO CallerTypes
VALUES
   (NEWID(), 'Business')
  ,(NEWID(), 'Family / Friend')
  ,(NEWID(), 'Other')
  ,(NEWID(), 'Parent')
  ,(NEWID(), 'Professional');

Здесь я спрятал свой текущий SQL-скрипт для поворота данных

SELECT * FROM [InitialData];
//
SELECT * FROM [ExpectedResults];
//
-- What I have tried so far:
DECLARE
   @columns AS NVARCHAR(MAX)
  ,@sql AS NVARCHAR(MAX);
SET @columns = N'';

-- Setup column names using dbo.CallerTypes
SELECT
  @columns += N', PivotResults.' + QUOTENAME(Name)
FROM
(
  SELECT DISTINCT
	[CallerTypes].[Name]
  FROM CallerTypes
  
  INNER JOIN [InitialData]
	ON [CallerTypes].[Name] = [InitialData].[CallerType]
) AS x;

-- Setup Dynamic Pivot Table
SET @sql = N'
  SELECT
	 [PivotResults].[YM]
	,[PivotResults].[Zip]
	,[PivotResults].[Region]
	,[PivotResults].[NewCallers]
	,[PivotResults].[RepeatCallers]
	,' + STUFF(@columns, 1, 2, '') + '
  FROM
  (
	SELECT
	   [CallerTypes].[Name]
	  ,[InitialData].[YM]
	  ,[InitialData].[Zip]
	  ,[InitialData].[Region]
	  ,[InitialData].[NewCallers]
	  ,[InitialData].[RepeatCallers]
	  ,[InitialData].[CallerTypeCount]
	FROM CallerTypes
	
	INNER JOIN [InitialData]
		ON [CallerTypes].[Name] = [InitialData].[CallerType]
  ) AS InnerSelect
  PIVOT (
	SUM([CallerTypeCount])
	FOR [InnerSelect].[Name] IN (' + STUFF(REPLACE(@columns, ', PivotResults.[', ',['), 1, 1, '') + ')
  ) AS PivotResults';
  
 EXEC sp_executesql @sql;

Вот слегка уменьшенная версия.
Я пытаюсь преобразовать это:

+========+=======+===============+============+===============+=================+=================+
|   YM   |  Zip  |    Region     | NewCallers | RepeatCallers |   CallerType    | CallerTypeCount |
+========+=======+===============+============+===============+=================+=================+
| 201805 | null  | null          |          3 |             0 | Family / Friend |               3 |
+--------+-------+---------------+------------+---------------+-----------------+-----------------+
| 201805 | null  | null          |          2 |             0 | Other           |               2 |
+--------+-------+---------------+------------+---------------+-----------------+-----------------+
| 201805 | 72209 | null          |          1 |             0 | Parent          |               1 |
+--------+-------+---------------+------------+---------------+-----------------+-----------------+
| 201805 | 85008 | Phoenix South |          1 |             0 | Parent          |               1 |
+--------+-------+---------------+------------+---------------+-----------------+-----------------+
| 201805 | 85008 | Phoenix South |          2 |             0 | Family / Friend |               2 |
+--------+-------+---------------+------------+---------------+-----------------+-----------------+
| 201805 | 85008 | Phoenix South |          0 |             3 | Other           |               3 |
+--------+-------+---------------+------------+---------------+-----------------+-----------------+
| 201806 | null  | null          |          9 |             0 | Professional    |               9 |
+--------+-------+---------------+------------+---------------+-----------------+-----------------+
| 201806 | 85258 | East Maricopa |          2 |             0 | Parent          |               2 |
+--------+-------+---------------+------------+---------------+-----------------+-----------------+
| 201806 | 85258 | East Maricopa |          0 |             2 | Other           |               2 |
+--------+-------+---------------+------------+---------------+-----------------+-----------------+

В это:

+========+=======+===============+============+===============+=================+=======+========+==============+
|   YM   |  Zip  |    Region     | NewCallers | RepeatCallers | Family / Friend | Other | Parent | Professional |
+========+=======+===============+============+===============+=================+=======+========+==============+
| 201805 | null  | null          |          5 |             0 |               3 |     2 |      0 |            0 |
+--------+-------+---------------+------------+---------------+-----------------+-------+--------+--------------+
| 201805 | 72209 | null          |          1 |             0 |               0 |     0 |      1 |            0 |
+--------+-------+---------------+------------+---------------+-----------------+-------+--------+--------------+
| 201805 | 85008 | Phoenix South |          3 |             0 |               2 |     0 |      1 |            0 |
+--------+-------+---------------+------------+---------------+-----------------+-------+--------+--------------+
| 201805 | 85008 | Phoenix South |          0 |             3 |               0 |     3 |      0 |            0 |
+--------+-------+---------------+------------+---------------+-----------------+-------+--------+--------------+
| 201806 | null  | null          |          9 |             0 |               0 |     0 |      0 |            9 |
+--------+-------+---------------+------------+---------------+-----------------+-------+--------+--------------+
| 201806 | 85258 | East Maricopa |          2 |             0 |               0 |     0 |      2 |            0 |
+--------+-------+---------------+------------+---------------+-----------------+-------+--------+--------------+
| 201806 | 85258 | East Maricopa |          0 |             2 |               0 |     2 |      0 |            0 |
+--------+-------+---------------+------------+---------------+-----------------+-------+--------+--------------+
<Ч />

[InitialData] вроде бы нормально, я изо всех сил пытаюсь повернуть его правильно, я думаю.

У меня столбцы с одинаковыми значениями YM, Zip и Region, которые можно разместить в одной строке. Первые четыре строки являются примером этого.

Кажется, что он разделяется по типу вызывающего и не разделяет строки с другими типами вызывающего, но 11-я строка (201805, 85008, Phoenix South, 2, 0, null, 2, null, null, 2) идет вразрез с этой логикой, а также отображает 2 в 4-м столбце, когда теоретически это должно быть 4 (сумма всех значений Caller Type)

Это также неправильно, потому что это будет 12-я строка в [ExpectedResults], где значение дополнительно объединяется в 9).

Я вижу, что это происходит только тогда, когда все значения типа вызывающего абонента равны null или имеют одинаковые значения (2).

Моя текущая идея заключается в том, что мне, возможно, придется также поворачиваться как на Новых, так и на Повторных Абонентах, но я пока не уверен, как это сделать, или если это правильный ответ.

Есть предложения?

1 Ответ

0 голосов
/ 29 июня 2018

Динамический запрос для статической версии ниже

(добавлено 2018-06-22: 49 по израильскому времени)

-------------Step 1 ----------------------
-- get the list of [CallerType],
-- which will become our column's names
Declare @ColumnsList1 nvarchar(MAX) = N''
SELECT @ColumnsList1 = 
STUFF(
    (
        SELECT distinct ',' + QUOTENAME([CallerType]) 
        FROM InitialData
        FOR XML PATH(''), TYPE
    ).value('.', 'NVARCHAR(MAX)')
    ,1,1,''
)
-- print @ColumnsList1
-- [Business],[Family / Friend],[Other],[Parent],[Professional]
Declare @ColumnsList2 nvarchar(MAX) = N''
SELECT @ColumnsList2 = 
STUFF(
    (
        SELECT distinct ',
            ISNULL(' + QUOTENAME([CallerType]) + ',0) as '+ QUOTENAME([CallerType])
        FROM InitialData
        FOR XML PATH(''), TYPE
    ).value('.', 'NVARCHAR(MAX)')
    ,1,1,''
)
--print @ColumnsList2
/*
            ISNULL([Business],0) as [Business],
            ISNULL([Family / Friend],0) as [Family / Friend],
            ISNULL([Other],0) as [Other],
            ISNULL([Parent],0) as [Parent],
            ISNULL([Professional],0) as [Professional]
*/
Declare @ColumnsList3 nvarchar(MAX) = N''
SELECT @ColumnsList3 = 
STUFF(
    (
        SELECT distinct '+
            ISNULL(' + QUOTENAME([CallerType]) + ',0)'
        FROM InitialData
        FOR XML PATH(''), TYPE
    ).value('.', 'NVARCHAR(MAX)')
    ,1,1,''
)
-- print @ColumnsList3
/*
            ISNULL([Business],0)+
            ISNULL([Family / Friend],0)+
            ISNULL([Other],0)+
            ISNULL([Parent],0)+
            ISNULL([Professional],0)
*/
-------------Step 2----------------------
DECLARE @MyDynQuery NVARCHAR(MAX) = '
;with MyCTE as (
    select *
    from
    (
      select 
        [YM], [Zip], [Region], [IsNew] = CASE WHEN [NewCallers]>0 then 1 else 0 END, 
        [CallerType], 
        [CallerTypeCount] 
      from InitialData
    ) x
    pivot(
        SUM([CallerTypeCount])
        for [CallerType] in(
            ' + @ColumnsList1 + '
        )
    )p
)
select 
    [YM], [Zip], [Region],--[IsNew] ,
    [NewCallers] = CASE
        WHEN [IsNew] = 1 then 0 +
            ' + @ColumnsList3 + '
        else 0
    END,
    [RepeatCallers] = CASE
        WHEN [IsNew] = 0 then  0 +
            ' + @ColumnsList3 + '
        else 0
    END,
    ' + @ColumnsList2 + '
from MyCTE
'
-- Print @MyDynQuery
execute(@MyDynQuery)
GO

Это статическая версия запроса. После подтверждения соответствия мы опубликуем динамическую версию выше

;with MyCTE as (
    select *
    from
    (
      select 
        [YM], [Zip], [Region], [IsNew] = CASE WHEN [NewCallers]>0 then 1 else 0 END, 
        [CallerType], 
        [CallerTypeCount] 
      from InitialData
    ) x
    pivot(
        SUM([CallerTypeCount])
        for [CallerType] in(
            [Family / Friend], [Other], [Parent]
            ,[Professional],[Business]
        )
    )p
)
select 
    [YM], [Zip], [Region],--[IsNew] ,
    [NewCallers] = CASE
        WHEN [IsNew] = 1 then 0 +
            ISNULL([Family / Friend] ,0) + 
            ISNULL([Other]           ,0) + 
            ISNULL([Parent]          ,0) +
            ISNULL([Professional]    ,0) +
            ISNULL([Business]        ,0) 
        else 0
    END,
    [RepeatCallers] = CASE
        WHEN [IsNew] = 0 then  0 +
            ISNULL([Family / Friend] ,0) + 
            ISNULL([Other]           ,0) + 
            ISNULL([Parent]          ,0) +
            ISNULL([Professional]    ,0) +
            ISNULL([Business]        ,0)
        else 0
    END,
            ISNULL([Family / Friend] ,0) [Family / Friend], 
            ISNULL([Other]           ,0) [Other]          , 
            ISNULL([Parent]          ,0) [Parent]         ,
            ISNULL([Professional]    ,0) [Professional]   ,
            ISNULL([Business]        ,0) [Business]       
from MyCTE
GO

Обновить информацию выше этой строки 2018-06-29 21:45 Израильское время

Добрый день, Райан,

Теперь, когда у меня есть DDL + DML, я могу довольно быстро найти решение (при условии, что я понимаю запрос): -)

Пожалуйста, проверьте, удовлетворяют ли запросы ниже. Сначала, когда нам нужен динамический запрос, я пишу простой статический сводный запрос. Только после того, как я думаю, что нашел правильное решение, я перехожу к динамическому запросу, который является вторым запросом ниже

;with MyCTE as (
    select *
    from
    (
      select 
        [YM], [Zip], [Region], 
        [NewCallers], [RepeatCallers], [CallerType], 
        [CallerTypeCount] 
      from InitialData
    ) x
    pivot(
        SUM([CallerTypeCount])
        for [CallerType] in(
            [Family / Friend], [Other], [Parent]
            ,[Professional],[Business]
        )
    )p
)
select 
    [YM], [Zip], [Region], 
    SUM(ISNULL([NewCallers]      ,0)), 
    SUM(ISNULL([RepeatCallers]   ,0)),
    SUM(ISNULL([Family / Friend] ,0)), 
    SUM(ISNULL([Other]           ,0)), 
    SUM(ISNULL([Parent]          ,0)),
    SUM(ISNULL([Professional]    ,0)),
    SUM(ISNULL([Business]        ,0))
from MyCTE
group by [YM], [Zip], [Region]
GO

И теперь, предполагая, что вышеупомянутый запрос работает хорошо, мы можем перейти к записи динамического запроса.

------------------------------------------------------------
-- Now let's do it in dynamic pivot
-------------Step 1 ----------------------
-- get the list of [CallerType],
-- which will become our column's names
Declare @ColumnsList1 nvarchar(MAX) = N''
SELECT @ColumnsList1 = 
STUFF(
    (
        SELECT distinct ',' + QUOTENAME([CallerType]) 
        FROM InitialData
        FOR XML PATH(''), TYPE
    ).value('.', 'NVARCHAR(MAX)')
    ,1,1,''
)
Declare @ColumnsList2 nvarchar(MAX) = N''
SELECT @ColumnsList2 = 
replace (@ColumnsList1,'[','
SUM(ISNULL([')
SELECT @ColumnsList2 = REPLACE(@ColumnsList2,'],','],0)),') + N',0))'
-- print @ColumnsList2
-------------Step 2----------------------
-- Back to the suery we replace the column with the parameter @ColumnsList
DECLARE @MyDynQuery NVARCHAR(MAX) = 
';with MyCTE as (
    select *
    from
    (
      select 
        [YM], [Zip], [Region], 
        [NewCallers], [RepeatCallers], [CallerType], 
        [CallerTypeCount] 
      from InitialData
    ) x
    pivot(
        SUM([CallerTypeCount])
        for [CallerType] in(
            ' + @ColumnsList1 + '
        )
    )p
)
select 
    [YM], [Zip], [Region], 
    SUM(ISNULL([NewCallers]      ,0)), 
    SUM(ISNULL([RepeatCallers]   ,0)),
    ' + @ColumnsList2 + '
from MyCTE
group by [YM], [Zip], [Region]
'
-- Print @MyDynQuery
execute(@MyDynQuery)
GO
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...