SQL Server:如何将 UNION 与两个都有 WHERE 子句的查询一起使用?

Posted

技术标签:

【中文标题】SQL Server:如何将 UNION 与两个都有 WHERE 子句的查询一起使用?【英文标题】:SQL Server: How to use UNION with two queries that BOTH have a WHERE clause? 【发布时间】:2011-07-22 13:22:00 【问题描述】:

鉴于:

需要过滤的两个查询:

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

另外,这些返回我正在寻找的 IDs:(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

问题:

问题是这个查询无效,因为如果第一个selectunioned,它就不能有order by 子句。如果没有order by,它就不可能有top 2

我该如何解决这种情况?

【问题讨论】:

我猜你的意思是order by 不是where 有问题。 【参考方案1】:

您应该能够为它们取别名并用作子查询(您的第一次尝试无效的部分原因是因为第一个选择有两列(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

【讨论】:

【参考方案2】:
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

【讨论】:

这是最好的答案,尤其是使用 CTE。就风格而言,Microsoft 建议使用分号结束 all SQL 语句,并将在未来版本中要求它。如果您以分号结束所有语句,则无需在 WITH 前面加上一个来伪造它。【参考方案3】:
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】:

问题的基本前提和答案都是错误的。联合中的每个 Select 都可以有一个 where 子句。这是第一个查询中的 ORDER BY 给你的错误。

【讨论】:

所以我的评论 = 15 个字符,但这就是答案。【参考方案5】:

答案具有误导性,因为它试图解决不是问题的问题。实际上,您可以在 UNION 的每个段中都有一个 WHERE 子句。除了最后一段之外,您不能有 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

【讨论】:

第一个查询中的TOP 2需要第一个ORDER BY【参考方案6】:

在两个前“选择”和“联合”它们上创建视图。

【讨论】:

-1 创建两个视图只是为了选择和合并它们似乎是错误的。 +1 因为这个答案在技术上是正确的,但它不是最好的解决方案。 @Ken White 你真的认为仅仅因为答案不是最佳解决方案而否决答案是个好主意吗?这是在 30 秒内给出的技术上正确的解决方案,并且不涉及任何代码。 @DJTripleThreat:感谢您的专业态度。 是的,我愿意。本网站的重点是找到问题的最佳答案,并为他人的问题提供最佳答案。声誉系统奖励给出正确(和深思熟虑的)答案的人,而给出快速、构思不当或错误答案的人会失去声誉。 “技术上正确”并不总是合适的(或正确的)。我可以说解决方案是打印出每个查询的结果并用剪刀和粘贴将它们放在一起 - 虽然“技术上正确”,因为它会起作用,你会投票支持那个答案吗? 我的观点是,如果答案有理想的结果,就不应该被否决。但是,如果没有用,并不是每个正确答案都应该被投票。 Pavel 也是第一个回复的人,所以我通常会在发布的第一个小时内对我得到的任何正确答案进行投票。但这只是我。【参考方案7】:

请注意,UNION 中的每个 SELECT 语句必须具有相同数量的列。这些列还必须具有相似的数据类型。此外,每个 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 

所以默认情况下它只会从两个表中返回不同的值。

【讨论】:

【参考方案8】:

select top 2 t1.ID, t2.ReceivedDate, 1 SortBy 从表 t1 其中 t1.Type = 'TYPE_1' 联盟 选择前 2 个 t2.ID,2 个 SortBy 从表 t2 其中 t2.Type = 'TYPE_2' 按 3,2 订购

【讨论】:

以上是关于SQL Server:如何将 UNION 与两个都有 WHERE 子句的查询一起使用?的主要内容,如果未能解决你的问题,请参考以下文章

与 UNION 一起使用时,对每个 SQL Server 查询都不起作用的排序

SQL 中的 UNION 和UNION ALL 有啥区别?

SQL 中的 UNION 和UNION ALL 有啥区别?

SQL语句中:UNION与UNION ALL的区别

sql server 中union的用法

SQL Server (2008) UNION 与 ROLL UP