Слияние двух строк в SQL
У меня есть таблица с следующей информацией:
FK | Field1 | Field2
=====================
3 | ABC | *NULL*
3 | *NULL* | DEF
Существует ли способ выполнить запрос SELECT к этой таблице, чтобы получить следующий результат:
FK | Field1 | Field2
=====================
3 | ABC | DEF
Спасибо!
Редактирование: Исправил название поля Field2 для ясности.
5 ответ(ов)
Функции агрегации могут помочь вам в этой ситуации. Функции агрегации игнорируют NULL
(по крайней мере, это справедливо для SQL Server, Oracle и Jet/Access), поэтому вы можете использовать такой запрос (тестировался на SQL Server Express 2008 R2):
SELECT
FK,
MAX(Field1) AS Field1,
MAX(Field2) AS Field2
FROM
table1
GROUP BY
FK;
Я использовал MAX
, но подойдет любая агрегирующая функция, которая выбирает одно значение из строк, сгруппированных по GROUP BY
.
Тестовые данные:
CREATE TABLE table1 (FK int, Field1 varchar(10), Field2 varchar(10));
INSERT INTO table1 VALUES (3, 'ABC', NULL);
INSERT INTO table1 VALUES (3, NULL, 'DEF');
INSERT INTO table1 VALUES (4, 'GHI', NULL);
INSERT INTO table1 VALUES (4, 'JKL', 'MNO');
INSERT INTO table1 VALUES (4, NULL, 'PQR');
Результаты:
FK Field1 Field2
-- ------ ------
3 ABC DEF
4 JKL PQR
Есть несколько способов в зависимости от правил работы с данными, которые вы не указали, но вот один из возможных вариантов, исходя из предоставленной вами информации.
SELECT
t1.Field1,
t2.Field2
FROM Table1 t1
LEFT JOIN Table1 t2 ON t1.FK = t2.FK AND t2.Field1 IS NULL
Другой способ:
SELECT
t1.Field1,
(SELECT Field2 FROM Table2 t2 WHERE t2.FK = t1.FK AND Field1 IS NULL) AS Field2
FROM Table1 t1
Если у вас есть дополнительные условия или специфические требования к данным, пожалуйста, уточните, и я смогу предложить более точное решение.
Существуют более изящные методы, но следующий подход можно рассмотреть как один из вариантов:
SELECT t.fk,
(
SELECT t1.Field1
FROM `table` t1
WHERE t1.fk = t.fk AND t1.Field1 IS NOT NULL
LIMIT 1
) AS Field1,
(
SELECT t2.Field2
FROM `table` t2
WHERE t2.fk = t.fk AND t2.Field2 IS NOT NULL
LIMIT 1
) AS Field2
FROM `table` t
WHERE t.fk = 3
GROUP BY t.fk;
Пример теста:
CREATE TABLE `table` (fk int, Field1 varchar(10), Field2 varchar(10));
INSERT INTO `table` VALUES (3, 'ABC', NULL);
INSERT INTO `table` VALUES (3, NULL, 'DEF');
INSERT INTO `table` VALUES (4, 'GHI', NULL);
INSERT INTO `table` VALUES (4, NULL, 'JKL');
INSERT INTO `table` VALUES (5, NULL, 'MNO');
Результат выполнения запроса:
+------+--------+--------+
| fk | Field1 | Field2 |
+------+--------+--------+
| 3 | ABC | DEF |
+------+--------+--------+
1 row in set (0.01 sec)
Если выполнить тот же запрос без условия WHERE t.fk = 3
, результат будет следующим:
+------+--------+--------+
| fk | Field1 | Field2 |
+------+--------+--------+
| 3 | ABC | DEF |
| 4 | GHI | JKL |
| 5 | NULL | MNO |
+------+--------+--------+
3 rows in set (0.01 sec)
Таким образом, приведённый запрос позволяет извлекать ненулевые значения из столбцов Field1
и Field2
для конкретного значения fk
, в данном случае — 3, при этом учитываются только существующие ненулевые записи.
У меня была похожая проблема. Разница заключалась в том, что мне нужно было гораздо больше контроля над тем, что я возвращаю, поэтому я в итоге создал простой, но довольно длинный запрос. Вот его упрощенная версия, основанная на вашем примере.
select main.id, Field1_Q.Field1, Field2_Q.Field2
from
(
select distinct id
from Table1
) as main
left outer join (
select id, max(Field1)
from Table1
where Field1 is not null
group by id
) as Field1_Q on main.id = Field1_Q.id
left outer join (
select id, max(Field2)
from Table1
where Field2 is not null
group by id
) as Field2_Q on main.id = Field2_Q.id
;
Фишка здесь в том, что первый select
под названием main
выбирает строки для отображения. Затем у вас есть один select
для каждого поля. Осуществляемые соединения должны использовать все те же значения, возвращаемые запросом main
.
Имейте в виду, что другие запросы должны возвращать только одну строку на id
, иначе вы упустите данные.
Если в одной из строк есть значение в столбце Field1, а в других строках значения равны NULL, то данный запрос может работать.
Вот сам запрос:
SELECT
FK,
MAX(Field1) as Field1,
MAX(Field2) as Field2
FROM
(
SELECT FK, ISNULL(Field1, '') as Field1, ISNULL(Field2, '') as Field2
FROM table1
) tbl
GROUP BY FK
В этом запросе мы используем подзапрос для замены значений NULL в полях Field1 и Field2 на пустые строки. Затем, в основном запросе, мы группируем результаты по FK и используем агрегатные функции MAX для получения значений. Таким образом, если в одной из строк в поле Field1 есть значение, оно будет выбрано в результате, даже если в других строках этого значения нет.
В чем разница между "INNER JOIN" и "OUTER JOIN"?
В чем разница между JOIN и INNER JOIN?
INNER JOIN ON vs WHERE: что выбрать?
Присоединение против подзапроса: что выбрать?
Обновление данных в одной таблице из другой на основе совпадения ID