【问题标题】:SQL Server: How to use UNION with two queries that BOTH have a WHERE clause?SQL Server:如何将 UNION 与两个都有 WHERE 子句的查询一起使用?
【发布时间】: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 有问题。

标签: sql-server union where-clause


【解决方案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 订购

        【讨论】:

          猜你喜欢
          • 2016-05-06
          • 1970-01-01
          • 2012-12-23
          • 1970-01-01
          • 2017-08-08
          • 2015-03-29
          • 1970-01-01
          • 1970-01-01
          • 2021-10-14
          相关资源
          最近更新 更多