Как объединить 2 оператора select в один?
Я использую noob, когда дело доходит до синтаксиса SQL.
У меня есть таблица с большим количеством строк и столбцов: P
Предположим, что это выглядит так:
AAA BBB CCC DDD
-----------------------
Row1 | 1 A D X
Row2 | 2 B C X
Row3 | 3 C D Z
Теперь я хочу создать расширенный оператор select, который дает мне этот комбинированный (псевдо-SQLish здесь):
select 'Test1', * from TABLE Where CCC='D' AND DDD='X'
select 'Test2', * from TABLE Where CCC<>'D' AND DDD='X'
Вывод будет:
Test1, 1, A, D, X
Test2, 2, B, C, X
Как бы объединить эти два оператора select в один оператор nice select?
Будет ли он работать, если я усложняю SQL, как показано ниже (потому что мой собственный оператор SQL содержит оператор exists)? Я просто хочу знать, как я могу объединить выборки, а затем попытаться применить их к более продвинутому SQL.
select 'Test1', * from TABLE Where CCC='D' AND DDD='X' AND exists(select ...)
select 'Test2', * from TABLE Where CCC<>'D' AND DDD='X' AND exists(select ...)
Мой REAL SQL-оператор:
select Status, * from WorkItems t1
where exists (select 1 from workitems t2 where t1.TextField01=t2.TextField01 AND (BoolField05=1) )
AND TimeStamp=(select max(t2.TimeStamp) from workitems t2 where t2.TextField01=t1.TextField01)
AND TimeStamp>'2009-02-12 18:00:00'
что дает мне результат. Но я хочу объединить его с копией этого оператора select с добавленным AND в конце, а поле "Status" будет изменено с помощью строки типа "DELETED".
select 'DELETED', * from WorkItems t1
where exists (select 1 from workitems t2 where t1.TextField01=t2.TextField01 AND (BoolField05=1) )
AND TimeStamp=(select max(t2.TimeStamp) from workitems t2 where t2.TextField01=t1.TextField01)
AND TimeStamp>'2009-02-12 18:00:00'
AND NOT (BoolField05=1)
Ответы
Ответ 1
У вас есть два варианта. Первое состоит в том, чтобы иметь два набора результатов, которые будут устанавливать "Test1" или "Test2" на основе условия в предложении WHERE
, а затем UNION
вместе:
select
'Test1', *
from
TABLE
Where
CCC='D' AND DDD='X' AND exists(select ...)
UNION
select
'Test2', *
from
TABLE
Where
CCC<>'D' AND DDD='X' AND exists(select ...)
Это может быть проблемой, потому что вы собираетесь эффективно сканировать/искать в таблице дважды.
Другим решением было бы выбрать один раз из таблицы и установить "Test1" или "Test2" на основе условий в таблице:
select
case
when CCC='D' AND DDD='X' AND exists(select ...) then 'Test1'
when CCC<>'D' AND DDD='X' AND exists(select ...) then 'Test2'
end,
*
from
TABLE
Where
(CCC='D' AND DDD='X' AND exists(select ...)) or
(CCC<>'D' AND DDD='X' AND exists(select ...))
Уловка заключается в том, что вам придется дублировать условия фильтра в инструкции CASE
и инструкции WHERE
.
Ответ 2
Если они из одной таблицы, я думаю, что UNION
- это команда, которую вы ищете.
(Если вам когда-либо понадобится выбирать значения из столбцов разных таблиц, вы должны посмотреть JOIN
вместо этого)
Ответ 3
Спасибо за ввод. Пробовал материал, упомянутый здесь, и это 2, которые я должен был выполнить:
(
select 'OK', * from WorkItems t1
where exists(select 1 from workitems t2 where t1.TextField01=t2.TextField01 AND (BoolField05=1) )
AND TimeStamp=(select max(t2.TimeStamp) from workitems t2 where t2.TextField01=t1.TextField01)
AND TimeStamp>'2009-02-12 18:00:00'
AND (BoolField05=1)
)
UNION
(
select 'DEL', * from WorkItems t1
where exists(select 1 from workitems t2 where t1.TextField01=t2.TextField01 AND (BoolField05=1) )
AND TimeStamp=(select max(t2.TimeStamp) from workitems t2 where t2.TextField01=t1.TextField01)
AND TimeStamp>'2009-02-12 18:00:00'
AND NOT (BoolField05=1)
)
и
select
case
when
(BoolField05=1)
then 'OK'
else 'DEL'
end,
*
from WorkItems t1
Where
exists(select 1 from workitems t2 where t1.TextField01=t2.TextField01 AND (BoolField05=1) )
AND TimeStamp=(select max(t2.TimeStamp) from workitems t2 where t2.TextField01=t1.TextField01)
AND TimeStamp>'2009-02-12 18:00:00'
Какой из них был бы наиболее эффективным (отредактируйте: второй, поскольку он только сканирует таблицу один раз), и можно ли сделать его еще более эффективным? (BoolField = 1) - это действительно переменная (dyn sql), которая может содержать любой оператор where в таблице.
Я работаю на MS SQL 2005. Пробовал примеры Quassnoi, но не работал должным образом.
Ответ 4
select Status, * from WorkItems t1
where exists (select 1 from workitems t2 where t1.TextField01=t2.TextField01 AND (BoolField05=1) )
AND TimeStamp=(select max(t2.TimeStamp) from workitems t2 where t2.TextField01=t1.TextField01)
AND TimeStamp>'2009-02-12 18:00:00'
UNION
select 'DELETED', * from WorkItems t1
where exists (select 1 from workitems t2 where t1.TextField01=t2.TextField01 AND (BoolField05=1) )
AND TimeStamp=(select max(t2.TimeStamp) from workitems t2 where t2.TextField01=t1.TextField01)
AND TimeStamp>'2009-02-12 18:00:00'
AND NOT (BoolField05=1)
Возможно, это будет трюк. Я не могу проверить это здесь, и я не уверен, в какой версии SQL вы работаете.
Ответ 5
Команда Union - это то, что вам нужно. Если это не сработает, вам может потребоваться уточнить, в какой среде вы находитесь.
Ответ 6
использовать случай в select и использовать в том, где close a OR
что-то вроде этого, я не тестировал его, но он должен работать, я думаю...
select case when CCC='D' then 'test1' else 'test2' end, *
from table
where (CCC='D' AND DDD='X') or (CCC<>'D' AND DDD='X')
Ответ 7
Я думаю, что вы ищете:
SELECT CASE WHEN BoolField05 = 1 THEN Status ELSE 'DELETED' END AS MyStatus, t1.*
FROM WorkItems t1
WHERE (TextField01, TimeStamp) IN(
SELECT TextField01, MAX(TimeStamp)
FROM WorkItems t2
GROUP BY t2.TextField01
)
AND TimeStamp > '2009-02-12 18:00:00'
Если вы находитесь в Oracle или MS SQL 2005 и выше, вы можете сделать:
SELECT *
FROM (
SELECT CASE WHEN BoolField05 = 1 THEN Status ELSE 'DELETED' END AS MyStatus, t1.*,
ROW_NUMBER() OVER (PARTITION BY TextField01 ORDER BY TimeStamp DESC) AS rn
FROM WorkItems t1
) to
WHERE rn = 1
он более эффективен.
Ответ 8
select t1.* from
(select * from TABLE Where CCC='D' AND DDD='X') as t1,
(select * from TABLE Where CCC<>'D' AND DDD='X') as t2
Другой способ сделать это!