使用 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 列 TypeA
、TypeB
和 TypeC
:
中的有效值
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 的方法,以便我可以计算 TypeA
、TypeB
和 TypeC
其中 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;
数据:
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');
编辑:
添加更多条件:
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');
我有一个枢轴 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 列 TypeA
、TypeB
和 TypeC
:
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 的方法,以便我可以计算 TypeA
、TypeB
和 TypeC
其中 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;
数据:
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');
编辑:
添加更多条件:
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');