2015-10-08 5 views
1

У меня есть сводная таблица, которая преобразует вертикальную структуру базы данных к горизонтальному:Подсчета и группировка вызова в сводной таблице с T-SQL

Источника таблица:

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 

Тогда есть таблица поиска для действительных значений в столбцах 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 

Таким образом, с учетом приведенной выше структурой Я ищу способ запросить сводную таблицу таким образом, что я буду получать количество всех недопустимых значений в TypeA, TypeB и TypeC где Date является действительным дата и CountValue не пусто и больше 0.

Как можно достичь результата, который, как ожидается, и выдается, как показано ниже:

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

я достиг результата, создав три несколько запросов и склейте результаты с помощью UNION, но я думаю, что это также должно быть возможно с помощью сводной таблицы, но я не уверен, как это сделать. Можно ли реализовать желаемый результат с помощью сводной таблицы?

Примечание: в базе данных используется база данных SQL Server 2005.

ответ

2

Я бы не подойти к этому сводную, в противном случае вы должны повернуть свои данные, а затем UNPIVOT его, чтобы получить требуемый результат.Разбив его шаг за шагом вы можете получить действительные удостоверения личности родителя с помощью этого:

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; 

Два имеющие положения ограничивают это ваши критерии, имеющие действительную дату и CountValue, который больше, чем 0

следующий шаг будет найти ваши некорректные свойства:

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

Это будет включать в себя Дату и CountValue, а также не будет включать в себя TypeA, потому что все свойства являются действительными, так что требуется немного больше работы, мы должны найти отличительные свойства мы заинтересованы в:

SELECT DISTINCT Name 
FROM #V 

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

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   

SCHEMA ДЛЯ ВЫШЕ Запрашивает

Для 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'); 
+0

Это занимает некоторое время, чтобы понять, как это работает. Спасибо за ваш исчерпывающий ответ. Я преобразовал имена образцов в свою реальную ситуацию (вертикальная таблица содержит более 1.300 уникальных элементов «Свойство»). Я действительно считаю, что таблица PIVOT не была правильным способом решить ее в конце, но я начал оттуда, чтобы заставить стол вращаться. Спасибо, +1, и согласился также с учетом критериев Date и CountValue. – Ben

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

EDIT:

Добавление нескольких критериев:

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; 
+0

Мне нравится, как это просто решить. Только две вещи не были учтены; имея действительную дату и гарантируя, что CountValue больше 0. +1 для вашего ответа. – Ben

+0

@Ben Не могли бы вы предоставить данные, которые нарушают мой код? Я постараюсь улучшить его. О 'DATE' вы должны проверить его перед вставкой в ​​БД. К сожалению, в SQL Server 2005 нет причудливых методов как 'TRY_PARSE'. – lad2025

+0

Я не уверен, что он сломается; но два критерия являются обязательными для получения правильного результата. Поддержка TRY_PARSE была бы аккуратной, так как я часто сталкивался с недействительными данными, которые вызывают ошибку при выполнении запроса. Например; даты хранятся в виде текста (из-за вертикального дизайна), но не всегда являются действительной датой ... Я знаю; не идеальный дизайн, но это дизайн, который существует, и я должен работать. – Ben

Смежные вопросы