SQL服务器 - 包括使用UNPIVOT NULL(SQL Server - Include NUL

2019-06-23 10:33发布

UNPIVOT不会返回NULL值,但我需要他们在一个比较查询。 我试图避免使用ISNULL下面的例子(因为在实际的SQL有超过100个字段:

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

任何替代方案?

Answer 1:

这是一个真正的痛苦。 你有之前切换出来UNPIVOT ,因为用于生产没有行ISNULL()进行操作-代码生成是你的朋友在这里。

我对这个问题PIVOT为好。 缺少行变成NULL ,你必须在包装ISNULL()所有跨如果缺失值是相同的行路0.0的例子。



Answer 2:

为了保持空值,使用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列。



Answer 3:

我遇到了同样的问题。 使用CROSS APPLY (SQL Server 2005和更高版本),而不是Unpivot解决了这个问题。 我找到了解决方案基于这篇文章的替代方案(更好?)方法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(MeasureType, Measure) 


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


 drop table #Orders


Answer 4:

或者,在更短的方式2008年的SQLServer:

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


Answer 5:

我发现左外加入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 |  值|  + ---------------------- + ----------------------- +  |  名称|  blah1 |  |  OBJECT_ID |  3 |  |  principal_id |  NULL |  <==  |  schema_id |  4 |  |  parent_object_id |  0 |  |  键入|  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 |  + ---------------------- + ----------------------- +     



Answer 6:

使用动态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 )


Answer 7:

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”作为我的中间值。 你可以使用任何你喜欢的。 但是,你如果你选择的东西现实世界,如“零”风险与用户输入的碰撞。 垃圾工作正常“!@#34())0”,但可能会更混乱的未来程序员。 我相信你得到的图片。



文章来源: SQL Server - Include NULL using UNPIVOT