2009-06-16 53 views
16

UNPIVOT不會返回NULL,但我需要它們進行比較查詢。我試圖避免使用ISNULL下面的例子(因爲在實際的SQL有超過100個字段:SQL Server - 使用UNPIVOT包含NULL

Select ID, theValue, column_name 
From 
(select ID, 
    ISNULL(CAST([TheColumnToCompare] AS VarChar(1000)), '') as TheColumnToCompare 
    from MyView 
    where The_Date = '04/30/2009' 
) MA 
UNPIVOT 
    (theValue FOR column_name IN 
    ([TheColumnToCompare]) 
) AS unpvt 

其它方法嗎?

回答

11

這是一個真正的痛苦。你必須之前轉出來UNPIVOT,因爲沒有爲ISNULL()生產經營上排 - 代碼生成是你的朋友在這裏

我有PIVOT問題以及缺少的行變成NULL,你有ISNULL()包裹一路。如果缺少,則橫跨該行例如,值與0.0相同。

+0

CROSS JOIN ... CASE將保留空值。見下面的例子。 – 2009-06-17 13:47:55

15

要保留空值,使用CROSS JOIN ... CASE:

select a.ID, b.column_name 
, column_value = 
    case b.column_name 
     when 'col1' then a.col1 
     when 'col2' then a.col2 
     when 'col3' then a.col3 
     when 'col4' then a.col4 
    end 
from (
    select ID, col1, col2, col3, col4 
    from table1 
) a 
cross join (
    select 'col1' union all 
    select 'col2' union all 
    select 'col3' union all 
    select 'col4' 
) b (column_name) 

相反的:

select ID, column_name, column_value 
From (
    select ID, col1, col2, col3, col4 
    from from table1 
) a 
unpivot (
    column_value FOR column_name IN (
    col1, col2, col3, col4) 
) b 

與列模式下的文本編輯器,使得這樣的查詢更容易編寫。 UltraEdit擁有它,Emacs也是如此。在Emacs中,它被稱爲矩形編輯。

您可能需要將其腳本編寫爲100列。在較短的方式

+0

我想爲它編寫5個以上的列,但我很懶:-)。下面是一個例子:`select'select'''+ column_name +'''UNION ALL'FROM information_schema。列WHERE table_name ='table1'和table_schema ='dbo'` – Anssssss 2015-12-28 20:18:11

3

,或者在2008年的SQLServer:

... 
cross join 
(values('col1'), ('col2'), ('col3'), ('col4')) column_names(column_name) 
1

使用動態SQL和COALESCE,我解決了這樣的問題:

DECLARE @SQL NVARCHAR(MAX) 
DECLARE @cols NVARCHAR(MAX) 
DECLARE @dataCols NVARCHAR(MAX) 

SELECT 
    @dataCols = COALESCE(@dataCols + ', ' + 'ISNULL(' + Name + ',0) ' + Name , 'ISNULL(' + Name + ',0) ' + Name) 
FROM Metric WITH (NOLOCK) 
ORDER BY ID 

SELECT 
    @cols = COALESCE(@cols + ', ' + Name , Name) 
FROM Metric WITH (NOLOCK) 
ORDER BY ID 

SET @SQL = 'SELECT ArchiveID, MetricDate, BoxID, GroupID, ID MetricID, MetricName, Value 
      FROM 
       (SELECT ArchiveID, [Date] MetricDate, BoxID, GroupID, ' + @dataCols + ' 
       FROM MetricData WITH (NOLOCK) 
       INNER JOIN Archive WITH (NOLOCK) 
        ON ArchiveID = ID 
       WHERE BoxID = ' + CONVERT(VARCHAR(40), @BoxID) + ' 
       AND GroupID = ' + CONVERT(VARCHAR(40), @GroupID) + ') p 
      UNPIVOT 
       (Value FOR MetricName IN 
        (' + @cols + ') 
      )AS unpvt 
      INNER JOIN Metric WITH (NOLOCK) 
       ON MetricName = Name 
      ORDER BY MetricID, MetricDate' 

EXECUTE(@SQL) 
2

我發現左外加入UNPIVOT結果到INFORMATION_SCHEMA提供的全部字段列表,以便在某些情況下實際解決此問題。

-- test data 
CREATE TABLE _t1(name varchar(20),object_id varchar(20),principal_id varchar(20),schema_id varchar(20),parent_object_id varchar(20),type varchar(20),type_desc varchar(20),create_date varchar(20),modify_date varchar(20),is_ms_shipped varchar(20),is_published varchar(20),is_schema_published varchar(20)) 
INSERT INTO _t1 SELECT 'blah1', 3, NULL, 4, 0, 'blah2', 'blah3', '20100402 16:59:23.267', NULL, 1, 0, 0 

-- example 
select c.COLUMN_NAME, Value 
from INFORMATION_SCHEMA.COLUMNS c 
left join (
    select * from _t1 
) q1 
unpivot (Value for COLUMN_NAME in (name,object_id,principal_id,schema_id,parent_object_id,type,type_desc,create_date,modify_date,is_ms_shipped,is_published,is_schema_published) 
) t on t.COLUMN_NAME = c.COLUMN_NAME 
where c.TABLE_NAME = '_t1' 
</pre> 

輸出如下:

+----------------------+-----------------------+ 
| COLUMN_NAME  |  Value   | 
+----------------------+-----------------------+ 
| name     | blah1     | 
| object_id   | 3      | 
| principal_id   | NULL     | <====== 
| schema_id   | 4      | 
| parent_object_id  | 0      | 
| type     | blah2     | 
| type_desc   | blah3     | 
| create_date   | 20100402 16:59:23.26 | 
| modify_date   | NULL     | <====== 
| is_ms_shipped  | 1      | 
| is_published   | 0      | 
| is_schema_published | 0      | 
+----------------------+-----------------------+ 

+0

這唯一的缺點是所有源字段必須連續輸入。 – Ozziemedes 2014-11-21 00:01:13

+0

@Ozziemedes我認爲你可能會忽略這一點,即使OP將原始數據轉換爲varchar ...在所有這些技術的某一點上,原始類型都必須丟失,這是由於unpivot的基本性質返回了先前的不同的列,在一個列下。另外,你確定你正確使用「連續」這個詞嗎?這個詞的定義意思是「彼此相鄰」,而不是像你想要的那樣「相同」? – Beej 2014-11-22 02:12:57

-1

ISNULL一半的答案。使用NULLIF轉換回NULL。例如。

DECLARE @temp TABLE(
    Foo varchar(50), 
    Bar varchar(50) NULL 
    ); 

INSERT INTO @temp(Foo,Bar)VALUES('licious',NULL); 

SELECT * FROM @temp; 

SELECT 
    Col, 
    NULLIF(Val,'0Null') AS Val 
FROM(
    SELECT 
     Foo, 
     ISNULL(Bar,'0Null') AS Bar 
    FROM 
     @temp 
    ) AS t 
UNPIVOT(
    Val FOR Col IN(
     Foo, 
     Bar 
     ) 
    ) up; 

這裏我使用「0Null」作爲我的中間值。你可以使用任何你喜歡的東西。但是,如果您選擇像「Null」這樣的真實世界,則可能會與用戶輸入產生衝突。垃圾正常工作「!@#34())0」,但對未來的程序員可能會更困惑。我相信你會得到這張照片。

2

我遇到了同樣的問題,使用CROSS APPLY(Sql Server 2005和更高版本)而不是Unpivot解決了這個問題。我找到了解決方案基於這篇文章An Alternative (Better?) Method to UNPIVOT 我做了下面的例子來證明CROSS APPLY不會忽略像Unpivot這樣的空。

create table #Orders (OrderDate datetime, product nvarchar(100), ItemsCount float,GrossAmount float, employee nvarchar(100)) 

insert into #Orders 
select getutcdate(),'Windows',10,10.32,'Me' 
union 
select getutcdate(),'Office',31,21.23,'you' 
union 
select getutcdate(),'Office',31,55.45,'me' 
union 
select getutcdate(),'Windows',10,null,'You' 

SELECT OrderDate, product,employee,Measure,MeasureType 
from #Orders orders 
CROSS APPLY (
    VALUES ('ItemsCount',ItemsCount),('GrossAmount',GrossAmount) 
    ) 
    x(Measure, MeasureType) 


SELECT OrderDate, product,employee,Measure,MeasureType 
from #Orders orders 
UNPIVOT 
    (Measure FOR MeasureType IN 
     (ItemsCount,GrossAmount) 
)AS unpvt; 


drop table #Orders