SQL Server: как использовать UNION с двумя запросами, которые ОБА имеют предложение WHERE? - PullRequest
25 голосов
/ 25 марта 2011

Дано:

Два запроса, требующие фильтрации:

select top 2 t1.ID, t1.ReceivedDate
  from Table t1
 where t1.Type = 'TYPE_1'
 order by t1.ReceivedDate desc

И:

select top 2 t2.ID
  from Table t2
 where t2.Type = 'TYPE_2'
 order by t2.ReceivedDate desc

Отдельно они возвращают ID s Я ищу: (13, 11 и 12, 6)

По сути, я хочу две самые последние записи для двух конкретных типов данных.

Я хочу объединить этидва запроса вместе, например:

select top 2 t1.ID, t2.ReceivedDate
  from Table t1
 where t1.Type = 'TYPE_1'
 order by ReceivedDate desc
union
select top 2 t2.ID
  from Table t2
 where t2.Type = 'TYPE_2'
 order by ReceivedDate desc

Проблема:

Проблема в том, что этот запрос недопустим, поскольку первый select не может иметь предложение order byесли это unioned.И у него не может быть top 2 без order by.

Как я могу исправить эту ситуацию?

Ответы [ 7 ]

40 голосов
/ 25 марта 2011

Вы должны иметь возможность использовать их псевдонимы и использовать в качестве подзапросов (одна из причин, по которой ваши первые попытки были недействительными, заключалась в том, что у первого выбора было два столбца (ID и ReceivedDate), а у второго - только один (ID) - также, Тип является зарезервированным словом в SQL Server, и его нельзя использовать, так как оно было указано в качестве имени столбца):

declare @Tbl1 table(ID int, ReceivedDate datetime, ItemType Varchar(10))
declare @Tbl2 table(ID int, ReceivedDate datetime, ItemType Varchar(10))

insert into @Tbl1 values(1, '20010101', 'Type_1')
insert into @Tbl1 values(2, '20010102', 'Type_1')
insert into @Tbl1 values(3, '20010103', 'Type_3')

insert into @Tbl2 values(10, '20010101', 'Type_2')
insert into @Tbl2 values(20, '20010102', 'Type_3')
insert into @Tbl2 values(30, '20010103', 'Type_2')

SELECT a.ID, a.ReceivedDate FROM
 (select top 2 t1.ID, t1.ReceivedDate
  from @tbl1 t1
  where t1.ItemType = 'TYPE_1'
  order by ReceivedDate desc
 ) a
union
SELECT b.ID, b.ReceivedDate FROM
 (select top 2 t2.ID, t2.ReceivedDate
  from @tbl2 t2
  where t2.ItemType = 'TYPE_2'
  order by t2.ReceivedDate desc
 ) b
9 голосов
/ 25 марта 2011
select * from 
(
    select top 2 t1.ID, t1.ReceivedDate
    from Table t1
    where t1.Type = 'TYPE_1'
    order by t1.ReceivedDate de
) t1
union
select * from 
(
    select top 2 t2.ID
    from Table t2
    where t2.Type = 'TYPE_2'
    order by t2.ReceivedDate desc
) t2

или с использованием CTE (SQL Server 2005 +)

;with One as
(
    select top 2 t1.ID, t1.ReceivedDate
    from Table t1
    where t1.Type = 'TYPE_1'
    order by t1.ReceivedDate de
)
,Two as
(
    select top 2 t2.ID
    from Table t2
    where t2.Type = 'TYPE_2'
    order by t2.ReceivedDate desc
)
select * from One
union
select * from Two
5 голосов
/ 25 марта 2011
declare @T1 table(ID int, ReceivedDate datetime, [type] varchar(10))
declare @T2 table(ID int, ReceivedDate datetime, [type] varchar(10))

insert into @T1 values(1, '20010101', '1')
insert into @T1 values(2, '20010102', '1')
insert into @T1 values(3, '20010103', '1')

insert into @T2 values(10, '20010101', '2')
insert into @T2 values(20, '20010102', '2')
insert into @T2 values(30, '20010103', '2')

;with cte1 as
(
  select *,
    row_number() over(order by ReceivedDate desc) as rn
  from @T1
  where [type] = '1'
),
cte2 as
(
  select *,
    row_number() over(order by ReceivedDate desc) as rn
  from @T2
  where [type] = '2'
)
select *
from cte1
where rn <= 2
union all
select *
from cte2
where rn <= 2
4 голосов
/ 17 августа 2013

Основная предпосылка вопроса и ответы неверны.Каждый выбор в объединении может иметь предложение where.Это ORDER BY в первом запросе, который выдает ошибку.

3 голосов
/ 09 июня 2015

Ответ вводит в заблуждение, потому что он пытается решить проблему, которая не является проблемой. Вы на самом деле МОЖЕТЕ иметь ГДЕ КЛАВИШУ в каждом сегменте СОЮЗА. Вы не можете иметь ORDER BY, кроме как в последнем сегменте. Поэтому это должно работать ...

select top 2 t1.ID, t1.ReceivedDate
from Table t1
where t1.Type = 'TYPE_1'
-----remove this-- order by ReceivedDate desc
union
select top 2 t2.ID,  t2.ReceivedDate --- add second column
  from Table t2
 where t2.Type = 'TYPE_2'
order by ReceivedDate desc
0 голосов
/ 30 мая 2014

Обратите внимание, что каждый оператор SELECT в UNION должен иметь одинаковое количество столбцов. Столбцы также должны иметь похожие типы данных. Кроме того, столбцы в каждом операторе SELECT должны быть в том же порядке. вы выбираете

t1.ID, t2.ReceivedDate из таблицы t1

союз

t2.ID из таблицы t2

что неверно.

так что вы должны написать

t1.ID, t1.ReceivedDate из таблицы t1 союз t2.ID, t2.ReceivedDate из таблицы t1

Вы можете использовать подзапрос здесь

 SELECT tbl1.ID, tbl1.ReceivedDate FROM
      (select top 2 t1.ID, t1.ReceivedDate
      from tbl1 t1
      where t1.ItemType = 'TYPE_1'
      order by ReceivedDate desc
      ) tbl1 
 union
    SELECT tbl2.ID, tbl2.ReceivedDate FROM
     (select top 2 t2.ID, t2.ReceivedDate
      from tbl2 t2
      where t2.ItemType = 'TYPE_2'
      order by t2.ReceivedDate desc
     ) tbl2 

, поэтому он будет возвращать только разные значения по умолчанию из обеих таблиц.

0 голосов
/ 25 марта 2011

Создайте представления для двух первых «выбирает» и «объединяет» их.

...