如何修改我的数据透视查询,以便在输出中不排除具有空值的行?

时间:2019-05-09 06:35:37

标签: sql-server tsql pivot sql-null

我正在使用SQL Server 2014,并且有以下T-SQL查询用于数据透视:

SELECT *

FROM    

(
SELECT  

[PropertyCode],    
FORMAT([MTH], 'MMM') AS 'MthTxt',
[FY],    
ISNULL((SUM([Revenue])/SUM([GN])),0) AS 'RevByGN',    
[Market]   

FROM View1

WHERE [MTH] BETWEEN '2018-07-01' AND '2020-06-01'

AND [PropertyCode] = 'ABC'

GROUP BY [PropertyCode], [MTH], [FY], [Market]

) AS SourceTable

PIVOT
(
   AVG([RevByGN])
 FOR [MthTxt] IN ([Jul], [Aug], [Sep], [Oct], [Nov], [Dec], [Jan], [Feb], [Mar], [Apr], [May], [Jun])
) AS PivotTable

输出摘要如下所示:output

我的问题是重点关注的市场,即中国和俄罗斯。由于没有19-20财年的数据,因此枢轴结果不包括这两个市场的19-20财年行。

如何强制我的数据透视结果包含这些行? 我还希望将NULL的值显示为0

根据Shnugo的解决方案添加我到目前为止所做的事情:

CREATE TABLE #temp_table (
    PropertyCode nvarchar(15),
    FY nvarchar(10),
    Market nvarchar(255)
);

INSERT INTO #temp_table VALUES
('CDM', 'FY 18-19', 'France'),
('CDM', 'FY 18-19', 'United Kingdom'),
('CDM', 'FY 18-19', 'Germany'),
('CDM', 'FY 18-19', 'Reunion'),
('CDM', 'FY 18-19', 'South Africa'),
('CDM', 'FY 18-19', 'Russia'),
('CDM', 'FY 18-19', 'Middle East'),
('CDM', 'FY 19-20', 'France'),
('CDM', 'FY 19-20', 'United Kingdom'),
('CDM', 'FY 19-20', 'Germany'),
('CDM', 'FY 19-20', 'Reunion'),
('CDM', 'FY 19-20', 'South Africa'),
('CDM', 'FY 19-20', 'Russia'),
('CDM', 'FY 19-20', 'Middle East')

;WITH temp1 AS

(
SELECT *
FROM (SELECT [PropertyCode] FROM #temp_table
      GROUP BY [PropertyCode]) t1
      CROSS JOIN (SELECT [FY] FROM #temp_table
                   GROUP BY [FY]) t2
      CROSS JOIN (SELECT [Market] FROM #temp_table
                   GROUP BY [Market]) t3
)

SELECT PivotTable.*

FROM

(
SELECT 
a.[PropertyCode],
a.[FY],
a.[Market],
ISNULL((SUM(b.[Package Revenue Excl VAT])/SUM(b.[GN])),0) AS 'GADR',
FORMAT(b.[MTH], 'MMM') AS 'MthTxt'

FROM [temp1] a
LEFT JOIN [QueryType2_v06feb2019_TBL] b ON (b.PropertyCode = a.PropertyCode AND b.FY = a.FY AND b.Market = a.Market)

WHERE b.[MTH] BETWEEN '2018-07-01' AND '2020-06-01'

GROUP BY a.[PropertyCode], b.[MTH], a.[FY], a.[Market]

)AS SourceTable

PIVOT
(
   AVG([GADR])
 FOR [MthTxt] IN ([Jul], [Aug], [Sep], [Oct], [Nov], [Dec], [Jan], [Feb], [Mar], [Apr], [May], [Jun])
) AS PivotTable

仍然无法正常工作,并给出以下结果:

output 2

1 个答案:

答案 0 :(得分:0)

对于您的下一个问题,我将要求您创建一个MCVE以重现您的问题。最小的是一些样本数据,最好以DDL和DML的形式提供。

这次我为您做了。这不是您的确切问题,但这将有助于演示该方法。

首先,我们需要一个带有一些数据的模型表

system

-此查询存在您正在谈论的问题:

DECLARE @tbl TABLE(ID INT IDENTITY, GroupID INT, SubId CHAR(1),Sub2Id CHAR(1), SomeValue VARCHAR(100));
INSERT INTO @tbl VALUES
 (1,'a','x','a with x is First in 1')
,(1,'b','y','b with y is Second in 1')
,(1,'c','z','c with z is Third in 1')
,(2,'b','x','b with x is First in 2')
,(2,'c','z','c with z is Second in 2')
,(3,'a','y','a with y is First in 3');

结果

SELECT p.* 
FROM
(
    SELECT tbl.SubId
          ,tbl.GroupID
          ,tbl.Sub2Id
          ,tbl.SomeValue
    FROM @tbl tbl
) t
PIVOT
(
    MAX(SomeValue) FOR SubId IN(a,b,c)
) p
ORDER BY GroupId,Sub2Id;

您可以看到,每个GroupId的引用次数和数据一样多。第1组以3行x,y和z表示,而第2行以z和x表示,而第3行仅以y表示。

您需要的是一个固定的集合,无论如何您都希望看到所有行。如果可以确定,要查看的任何组合在您的集合中至少存在一次,则可以直接从数据中提取出来,否则必须维护一个提供此类修订集的表。在该示例中,我假设现有数据可以满足我的所有需求。

+---------+--------+------------------------+-------------------------+-------------------------+
| GroupID | Sub2Id | a                      | b                       | c                       |
+---------+--------+------------------------+-------------------------+-------------------------+
| 1       | x      | a with x is First in 1 | NULL                    | NULL                    |
+---------+--------+------------------------+-------------------------+-------------------------+
| 1       | y      | NULL                   | b with y is Second in 1 | NULL                    |
+---------+--------+------------------------+-------------------------+-------------------------+
| 1       | z      | NULL                   | NULL                    | c with z is Third in 1  |
+---------+--------+------------------------+-------------------------+-------------------------+
| 2       | x      | NULL                   | b with x is First in 2  | NULL                    |
+---------+--------+------------------------+-------------------------+-------------------------+
| 2       | z      | NULL                   | NULL                    | c with z is Second in 2 |
+---------+--------+------------------------+-------------------------+-------------------------+
| 3       | y      | a with y is First in 3 | NULL                    | NULL                    |
+---------+--------+------------------------+-------------------------+-------------------------+

您看到,我--Create a combination of all existing Groups *cross joined* with all existing subs. WITH AllCombinations AS ( SELECT * FROM (SELECT GroupID FROM @tbl GROUP BY GroupID) t1 CROSS JOIN (SELECT Sub2Id FROM @tbl GROUP BY Sub2Id) t2 ) SELECT p.* FROM ( SELECT tbl.SubId ,combos.GroupID ,combos.Sub2Id ,tbl.SomeValue FROM AllCombinations combos LEFT JOIN @tbl tbl ON combos.GroupID=tbl.GroupID AND combos.Sub2Id=tbl.Sub2Id ) t PIVOT ( MAX(SomeValue) FOR SubId IN(a,b,c) ) p ORDER BY GroupId,Sub2Id; 与实际表的组合集。我使用LEFT JOIN别名而不是combos来选择值。这样可以确保这些值在结果集中,并显示在数据透视表中。

结果

tbl

更新

我试图解决您的查询,但我无法对其进行测试。因此,这是在半夜蒙着双眼穿过茂密的森林;-)

+---------+--------+------------------------+-------------------------+-------------------------+
| GroupID | Sub2Id | a                      | b                       | c                       |
+---------+--------+------------------------+-------------------------+-------------------------+
| 1       | x      | a with x is First in 1 | NULL                    | NULL                    |
+---------+--------+------------------------+-------------------------+-------------------------+
| 1       | y      | NULL                   | b with y is Second in 1 | NULL                    |
+---------+--------+------------------------+-------------------------+-------------------------+
| 1       | z      | NULL                   | NULL                    | c with z is Third in 1  |
+---------+--------+------------------------+-------------------------+-------------------------+
| 2       | x      | NULL                   | b with x is First in 2  | NULL                    |
+---------+--------+------------------------+-------------------------+-------------------------+
| 2       | y      | NULL                   | NULL                    | NULL                    |
+---------+--------+------------------------+-------------------------+-------------------------+
| 2       | z      | NULL                   | NULL                    | c with z is Second in 2 |
+---------+--------+------------------------+-------------------------+-------------------------+
| 3       | x      | NULL                   | NULL                    | NULL                    |
+---------+--------+------------------------+-------------------------+-------------------------+
| 3       | y      | a with y is First in 3 | NULL                    | NULL                    |
+---------+--------+------------------------+-------------------------+-------------------------+
| 3       | z      | NULL                   | NULL                    | NULL                    |
+---------+--------+------------------------+-------------------------+-------------------------+

我用易于维护的树替换了您的单个临时表。检查注释过的SELECT,看看会发生什么...

我又介绍了一个CTE,以将您的聚合/计算与枢纽CREATE TABLE #propCodes (PropertyCode nvarchar(15)); CREATE TABLE #FYs (FY nvarchar(10)); CREATE TABLE #Markets(Market nvarchar(255)); INSERT INTO #propCodes VALUES('CDM'); INSERT INTO #FYs VALUES('FY 18-19'),('FY 19-20'); INSERT INTO #Markets VALUES ('France'), ('United Kingdom'), ('Germany'), ('Reunion'), ('South Africa'), ('Russia'), ('Middle East'), ('France'); /* Check this to see the *cartesian product* SELECT * FROM #propCodes CROSS JOIN #FYs CROSS JOIN #Markets; */ ;WITH temp1 AS ( SELECT * FROM #propCodes CROSS JOIN #FYs CROSS JOIN #Markets ) ,Aggregated AS ( SELECT [PropertyCode], [FY], [Market], ISNULL((SUM([Package Revenue Excl VAT])/SUM([GN])),0) AS 'GADR', FORMAT([MTH], 'MMM') AS 'MthTxt' FROM [QueryType2_v06feb2019_TBL] WHERE [MTH] BETWEEN '2018-07-01' AND '2020-06-01' GROUP BY [PropertyCode], [MTH], a.[FY], [Market] ) SELECT PivotTable.* FROM ( SELECT * FROM [temp1] a LEFT JOIN Aggregated b ON (b.PropertyCode = a.PropertyCode AND b.FY = a.FY AND b.Market = a.Market) )AS SourceTable PIVOT ( AVG([GADR]) FOR [MthTxt] IN ([Jul], [Aug], [Sep], [Oct], [Nov], [Dec], [Jan], [Feb], [Mar], [Apr], [May], [Jun]) ) AS PivotTable; 分开。

祝你好运。如果这样做不起作用,请以消耗品格式提供样本数据,并减少到所需的最低数量...