SQL Pivot 2-й шаг - объединить строки / удалить нули - PullRequest
0 голосов
/ 15 октября 2018

Я пытаюсь изменить данные.Начнем с двух столбцов: ListNum и Value

Строка «целостность»не имеет значения, я просто хочу, чтобы все значения свернулись вверх и удалили пустые значения.

В этом случае ListNum похож на enum, значения ограничены List1, List2 или List3.Обратите внимание, что они не в порядке (1,3,3,1,2, а не 1,2,3,1,2,3 и т. Д.).

Было бы неплохо иметь решение, которое используетСтандартный SQL, поэтому он будет работать во многих базах данных.

Начальная точка:

+---------+------------+
| ListNum |   Value    |
+---------+------------+
| List1   | A          |
| List3   | 123        |
| List3   | CDE        |
| List1   | Somestring |
| List2   | randString |
+---------+------------+

Мне удалось разделить списки на столбцы с:

  select
      case when ListNum = "List1" then Value end as List1,
      case when ListNum = "List2" then Value end as List2,
      case when ListNum = "List3" then Value end as List3
  from Table;

Средняя точка:

+------------+------------+-------+
|   List1    |   List2    | List3 |
+------------+------------+-------+
| A          | NULL       | NULL  |
| NULL       | NULL       | 123   |
| NULL       | NULL       | CDE   |
| Somestring | NULL       | NULL  |
| NULL       | randString | NULL  |
+------------+------------+-------+

но теперь мне нужно свернуть вверх / удалить нули, чтобы получить - Желаемый результат:

+------------+------------+-------+
|   List1    |   List2    | List3 |
+------------+------------+-------+
| A          | randString | 123   |
| Somestring | NULL       | CDE   |
+------------+------------+-------+

Ответы [ 3 ]

0 голосов
/ 15 октября 2018

Не упускаете ли вы какой-то критерий группировки?Как вы определяете, что A принадлежит 123, а не CDE?И почему randString в первой строке, а не во второй?

Это легко с таким ключом группировки:

DECLARE @tbl TABLE(GroupingKey INT, ListNum VARCHAR(100),[Value] VARCHAR(100));
INSERT INTO @tbl VALUES
 (1,'List1','A')
,(1,'List3','123')
,(2,'List3','CDE')
,(2,'List1','Somestring')
,(1,'List2','randString');

SELECT p.*
FROM @tbl
PIVOT
(
    MAX([Value]) FOR ListNum IN(List1,List2,List3)
) p;

Но с вашими данными это кажется довольно случайным...

ОБНОВЛЕНИЕ: случайный подход ...

При следующем подходе значения будут отсортированы по столбцам довольно случайным образом:

DECLARE @tbl TABLE(ListNum VARCHAR(100),[Value] VARCHAR(100));
INSERT INTO @tbl VALUES
 ('List1','A')
,('List3','123')
,('List3','CDE')
,('List1','Somestring')
,('List2','randString');

- будет использоваться тринезависимые, но пронумерованные наборы и присоединение к ним:

WITH All1 AS (SELECT [Value],ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS RandomNumber FROM @tbl WHERE ListNum='List1')
    ,All2 AS (SELECT [Value],ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS RandomNumber FROM @tbl WHERE ListNum='List2')
    ,All3 AS (SELECT [Value],ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS RandomNumber FROM @tbl WHERE ListNum='List3')
SELECT All1.[Value] AS List1
      ,All2.[Value] AS List2
      ,All3.[Value] AS List3
FROM All1  
FULL OUTER JOIN All2 ON All1.RandomNumber=All2.RandomNumber
FULL OUTER JOIN All3 ON All1.RandomNumber=All3.RandomNumber ;

Подсказка: в вашей таблице нет неявного порядка сортировки!

Из вашего комментария:

Этопросто номер индекса / экземпляра.randString - первая ненулевая строка.

Без определенного ORDER BY тот же SELECT может вернуть ваши данные в любом случайном порядке.Таким образом, нет первой ненулевой строки , по крайней мере, не в значении сначала предшествует второй ...

0 голосов
/ 15 октября 2018

Что-то с рекурсивным CTE может работать:

DECLARE @tbl TABLE(  ListNum VARCHAR(100),[Value] VARCHAR(100));
INSERT INTO @tbl VALUES
 ( 'List1','A')
,( 'List3','123')
,( 'List3','CDE')
,( 'List1','Somestring')
,( 'List2','randString');

DECLARE @mmax int;
SELECT @mmax = cnt from (SELECT TOP 1  count(*) cnt from @tbl group by ListNum ORDER BY count(*) DESC) t;

With rec AS (
    SELECT 1 AS num
    UNION ALL
    SELECT num+1 FROM rec WHERE num+1<=@mmax
)
SELECT t1.List1, t2.List2,  t3.List3  FROM rec
FULL JOIN ( 
    select Value as List1, row_number() over(order by ListNum) rn from  @tbl where ListNum = 'List1'
) t1
ON rec.num = t1.rn
FULL JOIN 
( 
    select Value as List2, row_number() over(order by ListNum) rn from  @tbl where ListNum = 'List2'
) t2
ON rec.num = t2.rn
FULL JOIN 
( 
    select Value as List3, row_number() over(order by ListNum) rn from  @tbl where ListNum = 'List3'
) t3
ON rec.num = t3.rn;

DEMO

0 голосов
/ 15 октября 2018

Обычно вы используете агрегирующую операцию, такую ​​как MAX, потому что она скрывает нули (ноль не может быть максимальным, если в группе нет другого действительного значения) .. но ваш запрос немного странный, потому что вы неПохоже, у него есть надежная опорная точка, и вы позволяете любым своим данным связываться с чем-либо еще.В реальном мире это, вероятно, не произошло бы, потому что это не особенно полезно

Более точные данные примера:

Person, Attribute, Value
1, Name, John
1, Age, 10
2, Name, Sarah
3 Age, 39

Запрос поворота:

SELECT
  Person,
  MAX(case when attribute = 'name' then value end) as name,
  MAX(case when attribute = 'age' then value end) as age
FROM
  data
GROUP BY person

Результат:

Person, Name, Age
1, John, 10
2, Sarah, NULL
3, NULL, 39
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...