在非透视列中包含空值

Tes*_*ser 5 t-sql unpivot

考虑下表:

id  title   genre1  genre2  genre3  genre4  genre5
1   Movie1  Thriller    Crime   NULL    NULL    NULL
2   Movie2  Fantasy NULL    NULL    NULL    NULL
3   Movie3  Political   Philosophical   Historical  NULL    NULL
4   Movie4  Science Fiction NULL    NULL    NULL    NULL
Run Code Online (Sandbox Code Playgroud)

当我取消旋转流派 1、流派 2 时,删除了 NULL 值,例如,Movie1 的行将是:

id title  genre     original_column
1  Movie1 Thriller  genre1
1  Movie1 Crime     genre2
Run Code Online (Sandbox Code Playgroud)

有没有办法包含 NULL 值,例如:

id title  genre     original_column
1  Movie1 Thriller  genre1
1  Movie1 Crime     genre2
1  Movie1 NULL      genre3
1  Movie1 NULL      genre4
1  Movie1 NULL      genre5
Run Code Online (Sandbox Code Playgroud)

我可以SELECT ISNULL(genre1, '*'), ISNULL(genre2, '*') ...,但假设我希望这些值显示为 NULL?有没有比以下更好的方法:

WITH 
-- SELECT that unpivots table
AS unpivoted
SELECT unpivoted.id, 
  unpivoted.title, 
  ,CASE unpivoted.genre WHEN '*' THEN NULL ELSE unpivoted.genre END 
  ,unpivoted.original_transaction
FROM unpivoted
Run Code Online (Sandbox Code Playgroud)

此外,我注意到返回要取消透视的源数据的查询必须具有别名。例如:

SELECT ... FROM
  -- *must* give it an alias or it's a syntax error
  (SELECT ... FROM) AS source 
  UNPIVOT(genre for original_column IN (genre1,genre2, genre3,genre4,genre5))
Run Code Online (Sandbox Code Playgroud)

有谁知道为什么?我还没有找到在查询中的任何地方引用别名的方法。

Mik*_*son 7

您可以在交叉应用中执行逆透视以获得您想要的结果。

declare @T table
(
  id int,
  title varchar(50),
  genre1 varchar(50),
  genre2 varchar(50),
  genre3 varchar(50),
  genre4 varchar(50),
  genre5 varchar(50)
);

insert into @T values
(1, 'Movie1', 'Thriller', 'Crime',  NULL,  NULL, NULL),
(2, 'Movie2', 'Fantasy', NULL, NULL, NULL, NULL),
(3, 'Movie3', 'Political', 'Philosophical', 'Historical', NULL, NULL),
(4, 'Movie4', 'Science Fiction', NULL, NULL, NULL, NULL);

select T.id,
       T.title,
       G.genre,
       G.original_column
from @T as T
  cross apply (
              select T.genre1, 'genre1' union all
              select T.genre2, 'genre2' union all
              select T.genre3, 'genre3' union all
              select T.genre4, 'genre4' union all
              select T.genre5, 'genre5'
              ) as G(genre, original_column);
Run Code Online (Sandbox Code Playgroud)

如果您使用的是 SQL Server 2008 或更高版本,则可以使用表值构造函数,而不是union all按照 Vladimir Baranov 在评论中的建议。

select T.id,
       T.title,
       G.genre,
       G.original_column
from @T as T
  cross apply (values (T.genre1, 'genre1'),
                      (T.genre2, 'genre2'),
                      (T.genre3, 'genre3'),
                      (T.genre4, 'genre4'),
                      (T.genre5, 'genre5')
              ) as G(genre, original_column);
Run Code Online (Sandbox Code Playgroud)

  • 除了“UNION ALL”,您还可以使用“VALUES”语法:“cross apply ( values (T.genre1,'genre1'), (T.genre2,'genre2'), (T.genre3,'genre3'), (T.genre4,'genre4'), (T.genre5,'genre5') ) AS G(genre, original_column)` (5认同)