2012-03-07 1 views
1

У меня есть таблица, которая выглядит следующим образом:Попытка выбора строк и включают в себя первые 2 различных ненулевых значений из 4 столбцов

CREATE TABLE [Test].[dbo].[MyTest] 
(
[Id] INT NOT NULL, 
[ColA] VARCHAR(255) NULL, 
[ColB] VARCHAR(255) NULL, 
[ColC] VARCHAR(255) NULL, 
[ColD] VARCHAR(255) NULL 
); 

И скажем, у меня есть:

Id  ColA  ColB  ColC  ColD 
--------------------------------------- 
1  A  B  NULL  C 
2  A  A  NULL  D 
3  NULL  A  B  NULL 
4  B  B  B  B 
5  NULL  NULL  NULL  NULL 

Я Я пытаюсь сделать это, чтобы выбрать каждую строку из этой таблицы, но только для первых двух отличных ненулевых значений от ColA-ColD. Другими словами, если для одной строки ColA & ColB оба являются ненулевыми и отличаются друг от друга, это те, которые я хочу для этой строки. Используя данные, которые я дал выше, пожелавшие результаты этого запроса будет:

1, A (from ColA), B (from ColB) 
2, A (from ColA), D (from ColD) 
3, A (from ColB), B (from ColC) 
4, B (from ColA) 

Обратите внимание, что если все данные КОЛА-D для ряда является NULL, что строка не выбрана. Также это нормально, если есть только один ненулевой отдельный столбец (вы можете видеть из строки результата с Id 4) - это не должно быть 2, но в идеале это будет 2.

В принципе я бы идеально был способный получить TOP (2) DISTINCT из ColA-ColD WHERE, ни один из них не имеет значения NULL, но я понимаю, что TOP и DISTINCT работают над строками, а не в столбцах, которые я пытаюсь сделать. Любая помощь очень ценится.

Спасибо!

ответ

2

Это может быть самым быстрым с КТР и CASE заявление:

;WITH cte AS (
    SELECT id 
      ,COALESCE(ColA, ColB, ColC, ColD) AS col1 
      ,ColB 
      ,ColC 
      ,ColD 
    FROM tbl 
    ) 
SELECT id 
     ,col1 
     ,CASE WHEN ColB <> col1 THEN ColB 
      WHEN ColC <> col1 THEN ColC 
      WHEN ColD <> col1 THEN ColD 
      ELSE     NULL 
     END AS col2 
-- ,COALESCE(NULLIF(ColB, col1) 
--    ,NULLIF(ColC, col1) 
--    ,NULLIF(ColD, col1)) As col2 -- alt. syntax doing the same 
FROM cte 
WHERE col1 IS NOT NULL 
ORDER BY id 

Первая колонка возвращается (col1) является первым ненулевым столбца и второй столбец (col2) является вторым отдельным ненулевым значением в этом порядке. Оператор CASE работает, потому что NULL <> value никогда не оценивает TRUE.

Если есть только одно отличное значение, col2 возвращает NULL.
Если все столбцы источника - NULL, col1 - NULL, а строка фильтруется по статье WHERE.

Прокомментированный альтернативный синтаксис с NULLIF() короче, но я не ожидаю, что он будет быстрее.

+1

Вы можете сказать, что «второй столбец - это второе ненулевое значение» - изначально я думал, что ваш будет включать в себя значения null (которые будут отличаться от фактического значения). И можно отфильтровать только нулевые строки в cte. –

+0

@ X-Zero: У вас есть точка, «отличная» в языке SQL будет включать значение «NULL». Я объяснил свое объяснение, спасибо. –

+0

Блестящий! Это должно работать лучше, чем много вложенных заявлений COALESCE (хотя я тоже начинал думать об этом на этом маршруте и очень ценю ответ там Mark). Спасибо!! – fogwolf

0

Похоже, что ваш дизайн базы данных неправильный.

Возможно, у вас не должно быть ColA,..,ColD столбцов. Похоже, у вас должен быть второй стол с id, type (A, .., D) и value.

С этой структурой вы можете легко придумать любой выход.

+0

Спасибо за ответ. Извините, что не включил больше контекста. Это часть большого процесса. Существует таблица, в которой я сопоставляюсь, где у меня нет контроля над схемой. Этот процесс имеет несколько этапов с большим количеством временных таблиц, обрабатывает много данных и должен выполнять. Поэтому я действительно не могу перебирать каждую отдельную сущность, представленную «Id», и заполнять таблицу, как вы описываете.Я в основном должен иметь возможность делать массовые вставки, выбирая из одной таблицы в другую, и, как я уже сказал, на этом этапе я выбираю из таблицы с аналогичной схемой в схему таблицы temp, которую я приводил выше. – fogwolf

0

Try:

select id, 
     coalesce(ColA, ColB, ColC, ColD) Result1, 
     coalesce(nullif(coalesce(ColB, ColC, ColD), coalesce(ColA, ColB, ColC, ColD)), 
       nullif(coalesce(ColC, ColD), coalesce(ColB, ColC, ColD)), 
       nullif(ColD, coalesce(ColC, ColD))) Result2 
from [Test].[dbo].[MyTest] 
+0

Это близко. Я попробовал, но если ColA не является нулевым, например, данные оттуда заполняются в Result1 и Result2. Таким образом, это не совсем покрывает требование DISTINCT. Благодаря! – fogwolf

+0

Не только это, но даже если в ColB есть данные, отличные от данных в ColA, данные из ColA все еще возвращаются для Result1 и Result2. – fogwolf

+0

@ user1255182: Еще раз проверьте (этот запрос был отредактирован, так как я впервые разместил его) - если ColA не является нулевым, он заселяется в Result1, но ColA будет ** никогда ** не заполняться в Result2. Из представленных данных образца я получаю результаты (1, A, B); (2, А, D); (3, A, B); (4, B, NULL); (5, NULL, NULL). –

Смежные вопросы