SQL Server - включить NULL с помощью UNPIVOT
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
Любые альтернативы?
Ответы
Ответ 1
Это настоящая боль. Вы должны переключить их перед UNPIVOT
, потому что для работы с кодом ISNULL()
нет строки для работы - генерация кода - ваш друг здесь.
У меня проблема с PIVOT
. Пропущенные строки превращаются в NULL
, которые вы должны обернуть в ISNULL()
полностью через строку, если пропущенные значения такие же, как 0.0
.
Ответ 2
Чтобы сохранить NULL, используйте 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 он называется прямоугольным правлением.
Вам может понадобиться script для 100 столбцов.
Ответ 3
или в SQLServer 2008 короче:
...
cross join
(values('col1'), ('col2'), ('col3'), ('col4')) column_names(column_name)
Ответ 4
Я обнаружил, что внешний внешний элемент присоединяется к результату 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 |
+----------------------+-----------------------+
Ответ 5
Я запускаюсь в ту же проблему, используя CROSS APPLY (Sql Server 2005 и более поздние версии) Вместо Unpivot Решил проблему. Я нашел решение на основе этой статьи Альтернативный метод (лучше?) Для 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(Measure, MeasureType)
SELECT OrderDate, product,employee,Measure,MeasureType
from #Orders orders
UNPIVOT
(Measure FOR MeasureType IN
(ItemsCount,GrossAmount)
)AS unpvt;
drop table #Orders
Ответ 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 )
Ответ 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" в качестве моего промежуточного значения. Вы можете использовать все, что захотите. Однако вы рискуете столкнуться с пользовательским вводом, если вы выберете что-то реальное, например "Null". Мусор работает отлично "! @# 34()) 0", но может быть более запутанным для будущих кодеров. Я уверен, что вы получите картину.