Выберите различные значения из нескольких столбцов в одной таблице

Я пытаюсь построить один оператор SQL, который возвращает уникальные, ненулевые значения из нескольких столбцов, расположенных в одной таблице.

SELECT distinct tbl_data.code_1 FROM tbl_data
 WHERE tbl_data.code_1 is not null
 UNION
 SELECT tbl_data.code_2 FROM tbl_data
 WHERE tbl_data.code_2 is not null;

Например, tbl_data выглядит следующим образом:

id code_1 code_2
 --- -------- ----------
 1 AB BC
 2 BC 
 3 DE EF
 4 BC

В приведенной выше таблице SQL-запрос должен возвращать все уникальные ненулевые значения из двух столбцов, а именно: AB, BC, DE, EF.

Я новичок в SQL. Мое утверждение выше работает, но есть ли более чистый способ написать этот оператор SQL, поскольку столбцы из одной таблицы?

2 ответа

Лучше включить код вашего вопроса, а не двусмысленные текстовые данные, чтобы мы все работали с одними и теми же данными. Вот пример схемы и данных, которые я предположил:

CREATE TABLE tbl_data (
 id INT NOT NULL,
 code_1 CHAR(2),
 code_2 CHAR(2)
);
INSERT INTO tbl_data (
 id,
 code_1,
 code_2
)
VALUES
 (1, 'AB', 'BC'),
 (2, 'BC', NULL),
 (3, 'DE', 'EF'),
 (4, NULL, 'BC');

Как заметил Blorgbeard, предложение DISTINCT в вашем решении не нужно, потому что оператор UNION исключает повторяющиеся строки. Существует оператор UNION ALL, который не устраняет дубликатов, но здесь это не подходит.

Переписывание запроса без предложения DISTINCT является прекрасным решением этой проблемы:

SELECT code_1
FROM tbl_data
WHERE code_1 IS NOT NULL
UNION
SELECT code_2
FROM tbl_data
WHERE code_2 IS NOT NULL;

Не имеет значения, что два столбца находятся в одной таблице. Решение будет таким же, даже если столбцы были в разных таблицах.

Если вам не нравится избыточность задания одного и того же предложения фильтра дважды, вы можете инкапсулировать запрос объединения в виртуальную таблицу, прежде чем фильтровать это:

SELECT code
FROM (
 SELECT code_1
 FROM tbl_data
 UNION
 SELECT code_2
 FROM tbl_data
) AS DistinctCodes (code)
WHERE code IS NOT NULL;

Я считаю синтаксис второго более уродливым, но он логически более аккуратный. Но какой из них лучше работает?

Я создал sqlfiddle, который демонстрирует, что оптимизатор запросов SQL Server 2005 создает один и тот же план выполнения для двух разных запросов:

Если SQL Server создает один и тот же план выполнения для двух запросов, то они практически так же логически эквивалентны.

Сравните приведенное выше с планом выполнения запроса в своем вопросе:

Предложение DISTINCT заставляет SQL Server 2005 выполнять избыточную операцию сортировки, поскольку оптимизатор запросов не знает, что любые дубликаты, отфильтрованные DISTINCT в первом запросе, будут отфильтрованы UNION позже в любом случае.

Этот запрос логически эквивалентен двум другим, но избыточная операция делает его менее эффективным. В большом наборе данных я ожидаю, что ваш запрос займет больше времени, чтобы вернуть результирующий набор, чем два здесь. Не верьте мне на слово; эксперимент в вашей собственной среде, чтобы быть уверенным!


попробуйте что-то вроде SubQuery:

SELECT derivedtable.NewColumn
FROM
(
 SELECT code_1 as NewColumn FROM tbl_data 
 UNION
 SELECT code_2 as NewColumn FROM tbl_data 
) derivedtable
WHERE derivedtable.NewColumn IS NOT NULL

UNION уже возвращает значения DISTINCT из комбинированного запроса.

licensed under cc by-sa 3.0 with attribution.