使用T-SQL对数据透视表中的挑战进行计数和分组

时间:2015-10-08 08:01:30

标签: sql tsql sql-server-2005

我有一个数据透视表,可以将垂直数据库设计转换为水平数据库设计:

源表:

Id  ParentId    Property    Value
---------------------------------
1   1           Date        01-09-2015
2   1           CountValue  2
3   1           TypeA       Value1
4   1           TypeB       Value2
5   1           TypeC       Value2
6   2           Date        15-10-2015
7   2           CountValue  3
8   2           TypeA       Value3
9   2           TypeB       Value22
10  2           TypeC       Value99

旋转后,这看起来像:

ParentId    Date        CountValue  TypeA   TypeB   TypeC
----------------------------------------------------------
1           01-09-2015  2           Value1  Value2  Value2
2           15-10-2015  3           Value3  Value22 Value99

然后,在TypeATypeBTypeC列中有一个有效值的查找表:

Id  Name    Value
-----------------
1   TypeA   Value1
2   TypeA   Value2
3   TypeA   Value3
4   TypeB   Value20
5   TypeB   Value21
6   TypeB   Value22
7   TypeC   Value1
8   TypeC   Value2

因此,鉴于上述结构,我正在寻找一种方法来查询数据透视表,以便我可以计算TypeATypeB和{{中{{}}}中所有无效值的计数1}}其中TypeC是有效日期,Date不为空且大于0。

如何实现预期和输出的结果如下:

CountValue

我通过创建三个查询并使用UNION粘贴结果来完成结果,但我认为也应该可以使用数据透视表,但我不确定如何。可以使用数据透视表实现所需的结果吗?

注意:使用的数据库是SQL Server 2005数据库。

2 个答案:

答案 0 :(得分:2)

我不会接近这个PIVOT,否则你必须转动你的数据,然后取消它以获得所需的输出。逐步分解,您可以使用以下方法获取有效的父ID:

SELECT  t.ParentID
FROM    #T AS t
GROUP BY t.ParentID
HAVING  ISDATE(MAX(CASE WHEN t.Property = 'Date' THEN t.Value END)) = 1 
AND     MAX(CASE WHEN t.Property = 'CountValue' THEN CONVERT(INT, t.Value) END) > 0;

这两个条款将此限制为您拥有有效日期的条件,以及大于0的CountValue

下一步是找到无效的属性:

SELECT  t.*
FROM    #T AS t
WHERE   NOT EXISTS
        (   SELECT  1
            FROM    #V AS v
            WHERE   v.Name = t.Property
            AND     v.Value = t.Value
        );

这将包括Date和CountValue,并且也不包括TypeA,因为所有属性都是有效的,因此需要更多的工作,我们必须找到我们感兴趣的不同属性:

SELECT  DISTINCT Name 
FROM    #V

现在我们可以将它与无效属性结合起来获取计数,并使用有效的父ID来获得所需的结果:

WITH ValidParents AS
(   SELECT  t.ParentID
    FROM    #T AS t
    GROUP BY t.ParentID
    HAVING  ISDATE(MAX(CASE WHEN t.Property = 'Date' THEN t.Value END)) = 1 
    AND     MAX(CASE WHEN t.Property = 'CountValue' THEN CONVERT(INT, t.Value) END) > 0
), InvalidProperties AS
(   SELECT  t.Property
    FROM    #T AS t
    WHERE   t.ParentID IN (SELECT vp.ParentID FROM ValidParents AS vp)
    AND     NOT EXISTS
            (   SELECT  1
                FROM    #V AS v
                WHERE   v.Name = t.Property
                AND     v.Value = t.Value
            )
)
SELECT  [Count] =  COUNT(t.Property), 
        [Column] = v.Name
FROM    (SELECT DISTINCT Name FROM #V) AS V
        LEFT JOIN InvalidProperties AS t
            ON t.Property = v.Name
GROUP BY v.Name;        

给出了:

Count   Column
--------------
0       TypeA
1       TypeB
1       TypeC           

查询以上查询

对于SQL Server 2008+。道歉,我没有SQL Server 2005了,忘了它不支持表值构造函数。

CREATE TABLE #T (Id INT, ParentId INT, Property VARCHAR(10), Value VARCHAR(10));
INSERT #T (Id, ParentId, Property, Value)
VALUES
    (1, 1, 'Date', '01-09-2015'), (2, 1, 'CountValue', '2'), (3, 1, 'TypeA', 'Value1'),
    (4, 1, 'TypeB', 'Value2'), (5, 1, 'TypeC', 'Value2'), (6, 2, 'Date', '15-10-2015'),
    (7, 2, 'CountValue', '3'), (8, 2, 'TypeA', 'Value3'), (9, 2, 'TypeB', 'Value22'),
    (10, 2, 'TypeC', 'Value99');

CREATE TABLE #V (ID INT, Name VARCHAR(5), Value VARCHAR(7));    
INSERT #V (Id, Name, Value)
VALUES
    (1, 'TypeA', 'Value1'), (2, 'TypeA', 'Value2'), (3, 'TypeA', 'Value3'), 
    (4, 'TypeB', 'Value20'), (5, 'TypeB', 'Value21'), (6, 'TypeB', 'Value22'), 
    (7, 'TypeC', 'Value1'), (8, 'TypeC', 'Value2');

答案 1 :(得分:1)

没有PIVOT的最终结果:

SELECT [count] = SUM(CASE WHEN l.id IS NULL THEN 1 ELSE 0 END)
  ,t.Property
FROM #lookup l
RIGHT JOIN #tab t  
  ON t.Property = l.Name
  AND t.Value = l.Value
WHERE t.Property LIKE 'Type%'
GROUP BY t.Property;

<强> LiveDemo

数据:

CREATE TABLE #tab(
   Id       INTEGER  NOT NULL PRIMARY KEY 
  ,ParentId INTEGER  NOT NULL
  ,Property VARCHAR(10) NOT NULL
  ,Value    VARCHAR(10) NOT NULL
);
INSERT INTO #tab(Id,ParentId,Property,Value) VALUES (1,1,'Date','01-09-2015');
INSERT INTO #tab(Id,ParentId,Property,Value) VALUES (2,1,'CountValue','2');
INSERT INTO #tab(Id,ParentId,Property,Value) VALUES (3,1,'TypeA','Value1');
INSERT INTO #tab(Id,ParentId,Property,Value) VALUES (4,1,'TypeB','Value2');
INSERT INTO #tab(Id,ParentId,Property,Value) VALUES (5,1,'TypeC','Value2');
INSERT INTO #tab(Id,ParentId,Property,Value) VALUES (6,2,'Date','15-10-2015');
INSERT INTO #tab(Id,ParentId,Property,Value) VALUES (7,2,'CountValue','3');
INSERT INTO #tab(Id,ParentId,Property,Value) VALUES (8,2,'TypeA','Value3');
INSERT INTO #tab(Id,ParentId,Property,Value) VALUES (9,2,'TypeB','Value22');
INSERT INTO #tab(Id,ParentId,Property,Value) VALUES (10,2,'TypeC','Value99');

CREATE TABLE #lookup(
   Id    INTEGER  NOT NULL PRIMARY KEY 
  ,Name  VARCHAR(5) NOT NULL
  ,Value VARCHAR(7) NOT NULL
);
INSERT INTO #lookup(Id,Name,Value) VALUES (1,'TypeA','Value1');
INSERT INTO #lookup(Id,Name,Value) VALUES (2,'TypeA','Value2');
INSERT INTO #lookup(Id,Name,Value) VALUES (3,'TypeA','Value3');
INSERT INTO #lookup(Id,Name,Value) VALUES (4,'TypeB','Value20');
INSERT INTO #lookup(Id,Name,Value) VALUES (5,'TypeB','Value21');
INSERT INTO #lookup(Id,Name,Value) VALUES (6,'TypeB','Value22');
INSERT INTO #lookup(Id,Name,Value) VALUES (7,'TypeC','Value1');
INSERT INTO #lookup(Id,Name,Value) VALUES (8,'TypeC','Value2');

修改

添加更多条件:

<强> LiveDemo2

SELECT [count] = SUM(CASE WHEN l.id IS NULL THEN 1 ELSE 0 END)
      ,t.Property
FROM #lookup l
RIGHT JOIN #tab t  
  ON t.Property = l.Name
  AND t.Value = l.Value
WHERE t.Property LIKE 'Type%'
  AND t.ParentId IN (SELECT ParentId FROM #tab WHERE Property = 'Date' AND ISDATE(VALUE) = 1)
  AND t.ParentID IN (SELECT ParentId FROM #tab WHERE Property = 'CountValue' AND Value > 0)
GROUP BY t.Property;