web-dev-qa-db-fra.com

SQL Server: comment utiliser UNION avec deux requêtes qui ont toutes deux une clause WHERE?

Étant donné:

Deux requêtes qui nécessitent un filtrage:

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

Et:

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

Séparément, ceux-ci renvoient les IDs que je recherche: (13, 11 et 12, 6)

Fondamentalement, je veux les deux enregistrements les plus récents pour deux types de données spécifiques.

Je veux réunir ces deux requêtes comme suit:

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

Problème:

Le problème est que cette requête n'est pas valide car le premier select ne peut pas avoir un order by clause si elle est unioned. Et il ne peut pas avoir top 2 sans avoir order by.

Comment puis-je résoudre cette situation?

26
aarona

Vous devriez pouvoir les alias et les utiliser comme sous-requêtes (une partie de la raison pour laquelle votre premier effort n'était pas valide était parce que la première sélection avait deux colonnes (ID et ReceivedDate) mais votre seconde n'en avait qu'une (ID) - aussi, Type est un réservé Word dans SQL Server, et ne peut pas être utilisé comme vous l'aviez comme nom de colonne):

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
41
Ken White
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

ou en utilisant 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
9
amit_g
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
5
Mikael Eriksson

La prémisse de base de la question et des réponses est fausse. Chaque Select dans une union peut avoir une clause where. C'est l'ORDRE PAR dans la première requête qui vous donne l'erreur.

4
Paul Nielsen

La réponse est trompeuse car elle tente de résoudre un problème qui n'est pas un problème. Vous POUVEZ en fait avoir une CLAUSE OERE dans chaque segment d'une UNION. Vous ne pouvez pas avoir un ORDER BY sauf dans le dernier segment. Par conséquent, cela devrait fonctionner ...

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
3
user2967439

Créez des vues sur les deux premiers "selects" et "union".

0
Pavel Nefyodov

Notez que chaque instruction SELECT dans l'UNION doit avoir le même nombre de colonnes. Les colonnes doivent également avoir des types de données similaires. En outre, les colonnes de chaque instruction SELECT doivent être dans le même ordre. vous choisissez

t1.ID, t2.ReceivedDate du tableau t1

syndicat

t2.ID du tableau t2

ce qui est incorrect.

il faut donc écrire

t1.ID, t1.ReceivedDate du tableau t1 union t2.ID, t2.ReceivedDate du tableau t1

vous pouvez utiliser la sous-requête ici

 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 

il ne renverra donc que des valeurs distinctes par défaut des deux tables.

0
Pradeep atkari