سؤال

لن يعيد Unpivot Nulls ، لكنني أحتاجها في استعلام مقارنة. أحاول تجنب استخدام 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

أي بدائل؟

هل كانت مفيدة؟

المحلول

إنه ألم حقيقي. عليك أن تبديلها قبل UNPIVOT, ، لأنه لا يوجد صف ينتج عنه ISNULL() للعمل على - توليد الكود هو صديقك هنا.

لدي مشكلة في PIVOT كذلك. تتحول الصفوف المفقودة إلى NULL, ، والتي عليك أن تلتف فيها ISNULL() على طول الطريق عبر الصف إذا كانت القيم المفقودة هي نفسها مثل 0.0 فمثلا.

نصائح أخرى

للحفاظ على خميرة ، استخدم الصليب الانضمام ... الحالة:

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 عمود.

وقعت في نفس المشكلة. استخدام CROSS APPLY (SQL Server 2005 وما بعده) بدلاً من Unpivot حل المشكلة. لقد وجدت الحل بناءً على هذه المقالة طريقة بديلة (أفضل؟)وقدمت المثال التالي لإثبات أن Cross Apply لن يتجاهل Nulls مثل 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

أو ، في SQLServer 2008 بطريقة أقصر:

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

لقد وجدت اليسار الخارجي للانضمام إلى النتيجة غير المتوفرة إلى القائمة الكاملة للحقول ، التي يتم سحبها بشكل مناسب من 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                     |
+----------------------+-----------------------+
    

باستخدام Dynamic 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 )

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". تعمل Garbage بشكل جيد "!@#34 ()) 0" ولكن قد يكون أكثر إرباكًا للمبرمجين في المستقبل. أنا متأكد من أنك تحصل على الصورة.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top