У меня есть таблица с несколькими сведениями, относящимися к одному и тому же объекту, поступающим из разных источников данных.
Допустим, структура таблицы следующая (в реальной таблице гораздо больше столбцов):
create table dbo.infoBySource
(
entityId int
,dataSourceId int
,col1 varchar(50)
,col2 int
,constraint pk_infoBySource primary key (entityId, dataSourceId)
)
insert dbo.infoBySource values
(1 ,1 ,'a' ,null),
(1 ,2 ,'a2' ,10),
(2 ,2 ,'c' ,20)
Я хотел бы написать запрос, который удаляет поле dataSourceId, сохраняя «лучшую» доступную информацию (столбец за столбцом), игнорируя null
информацию.
Здесь предполагается, что различные источники данных упорядочены по «приоритету качества» (предположим для простоты, что этот приоритет задается самим значением dataSourceId
)
Это лучшее решение, к которому я пришел:
;with
info as
(select
a.*
,isCol1ToKeep = case when ROW_NUMBER() over(partition by entityId
order by case when a.col1 is null then null else -dataSourceId end desc) = 1 then 1 else 0 end
,isCol2ToKeep = case when ROW_NUMBER() over(partition by entityId
order by case when a.col2 is null then null else -dataSourceId end desc) = 1 then 1 else 0 end
from
dbo.infoBySource a
)
select
i.entityId
,col1 = max(case when i.isCol1ToKeep = 1 then i.col1 else null end)
,col2 = max(case when i.isCol2ToKeep = 1 then i.col2 else null end)
from
info i
group by i.entityId
Но я думаю, что мое решение неудовлетворительно: его сложно поддерживать, оно подвержено ошибкам и, возможно, неэффективно. Есть ли лучшая стратегия?
Если вы используете SQL Server 2022 или более позднюю версию, вы можете использовать оконную функцию FIRST_VALUE
с опцией IGNORE NULLS
:
WITH info AS (
SELECT entityId,
isCol1ToKeep = FIRST_VALUE(col1 ) IGNORE NULLS OVER(PARTITION BY entityId ORDER BY dataSourceId),
isCol2ToKeep = FIRST_VALUE(col2 ) IGNORE NULLS OVER(PARTITION BY entityId ORDER BY dataSourceId)
FROM dbo.infoBySource
)
SELECT entityId
,col1 = max(isCol1ToKeep)
,col2 = max(isCol2ToKeep)
FROM info
GROUP BY entityId
Я использую Azure SQL, он работает и намного чище, чем мое решение, спасибо.
Рад слышать, что смог помочь :)
Я успешно использую ваше решение, мне просто интересно, как сообщить моему редактору (Azure Data Studio 1.48.1), что этот синтаксис действительно действителен в SQL Azure: он продолжает добавлять красную волнистую линию под ключевым словом IGNORE, и я не могу найти, где указать целевой диалект SQL
Вероятно, вы можете упростить и использовать:
FIRST_VALUE(colX) OVER(ORER BY case when colX IS NOT NULL THEN 0 ELSE 1 END, ...