Как объединить 2 оператора select в один?

Я нуб, когда дело доходит до синтаксиса SQL.

Конечно, у меня есть таблица с большим количеством строк и столбцов: P Допустим, она выглядит так:

      AAA BBB CCC DDD
-----------------------
Row1 | 1   A   D   X
Row2 | 2   B   C   X
Row3 | 3   C   D   Z

Теперь я хочу создать расширенный оператор выбора, который дает мне это в сочетании (здесь псевдо-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 в один хороший оператор 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 ...)




Мой НАСТОЯЩИЙ оператор 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 '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)

person Wolf5    schedule 12.02.2009    source источник
comment
+1 это очень хорошо заданный вопрос   -  person gloomy.penguin    schedule 01.05.2012


Ответы (8)


Здесь у вас есть два варианта. Во-первых, иметь два набора результатов, которые будут устанавливать «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 ...)

Это может быть проблемой, потому что вы собираетесь эффективно сканировать/искать TABLE дважды.

Другим решением было бы выбрать из таблицы один раз и установить «Test1» или «Test2» в зависимости от условий в TABLE:

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.

person casperOne    schedule 12.02.2009
comment
Спасибо (я использую MS SQL Server 2005). Кажется, это то, что я ищу. UNION сканирует дважды, но я могу с этим смириться. И я не знал, что оператор CASE может быть использован заранее. - person Wolf5; 13.02.2009

Если они из одной таблицы, я думаю, что UNION — это команда, которую вы ищешь.

(Если вам когда-нибудь понадобится выбирать значения из столбцов разных таблиц, посмотрите на JOIN вместо...)

person Tomas Aschan    schedule 12.02.2009

Спасибо за отзыв. Пробовал вещи, которые были упомянуты здесь, и это 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, но не работал должным образом.

person Wolf5    schedule 13.02.2009
comment
Это солидно. Спасибо :) - person ; 15.10.2015

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

Другой способ сделать это!

person arthur bryant    schedule 03.07.2017
comment
Простой тест таблицы с одним столбцом с двумя строками и использование этого запроса для выбора первого как t1, а второго как t2 завершается неудачей, возвращается только t1. - person Wolf5; 03.07.2017

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 вы работаете.

person Kezzer    schedule 12.02.2009

Команда Union — это то, что вам нужно. Если это не работает, вам может понадобиться уточнить, в какой среде вы находитесь.

person JB King    schedule 12.02.2009

используйте случай в выборе и используйте в том, где закрыть ИЛИ

что-то вроде этого, я не проверял, но, думаю, должно работать...

select case when CCC='D' then 'test1' else 'test2' end, *
from table
where (CCC='D' AND DDD='X') or (CCC<>'D' AND DDD='X')
person Fredou    schedule 12.02.2009

Я думаю, это то, что вы ищете:

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

, это более эффективно.

person Quassnoi    schedule 12.02.2009