使用 T-SQL 在枢轴 table 中计算和分组挑战

Counting and grouping challenge in a pivot table with T-SQL

我有一个枢轴 table 可以将垂直数据库设计转换为水平数据库设计:

来源table:

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

然后,查找 table 列 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

因此,鉴于上述结构,我正在寻找一种查询枢轴 table 的方法,以便我可以计算 TypeATypeBTypeC 其中 Date 是有效日期并且 CountValue 不为空且大于 0。

我怎样才能达到预期的结果并输出如下:

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

我已经通过创建三个查询并使用 UNION 粘合结果来完成结果,但我认为也应该可以使用数据透视表 table,但我不确定如何操作。使用枢轴table?

是否可以实现预期的结果

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

没有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;

我不会使用 PIVOT,否则您必须对数据进行透视,然后对它进行逆透视以获得所需的输出。逐步分解它,您可以使用以下方法获得有效的 parent 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;

这两个 having 子句将此限制为具有有效日期和大于 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

现在我们可以将其与无效的属性结合起来以获得计数,并与有效的 parent 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,忘了它不支持 table 值构造函数。

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');