如何将 UNION 更改为 IN 子句?

Posted

技术标签:

【中文标题】如何将 UNION 更改为 IN 子句?【英文标题】:How to change a UNION to a IN clause? 【发布时间】:2019-07-04 16:37:17 【问题描述】:

我需要从同一张表中获取最多 3 条不同的记录,所以目前我正在做:

SELECT 1, mycolumn FROM mytable WHERE id = @firstId
UNION ALL
SELECT 2, mycolumn FROM mytable WHERE id = @secondId
UNION ALL
SELECT 3, mycolumn FROM mytable WHERE id = @thirdId

实际的SELECT 部分包含超过20 列,FROM 部分包含许多JOINs。第一列是一个常数,并且始终根据记录而固定。我不知道可能会返回多少条记录。可以是 0 到 3 条记录。

是否可以更改上述查询,使其使用IN,如下所示:

SELECT ???, mycolumn FROM mytable WHERE id IN (@firstId, @secondId, @thirdId)

但是如果我使用IN,如何将每条记录显式映射到固定常量?

【问题讨论】:

【参考方案1】:

您可以在此处将CASE 表达式与单个查询一起使用:

SELECT
    CASE id WHEN @firstId  THEN 1
            WHEN @secondId THEN 2
            WHEN @thirdId  THEN 3 END AS val,
    mycolumn
FROM mytable
WHERE
    id IN (@firstId, @secondId, @thirdId);

如果您还希望按计算列排序,请将ORDER BY val 添加到上述查询的末尾。

【讨论】:

ORDER BY val 以确保结果与原始查询相同,或者不需要(@firstId, @secondId, @thirdId 不需要按升序排列)? @Cid OP的原始查询没有外部order by,因此它也可以将行返回为3,1,2。 @Cid 好点,但 OP 实际上并没有订购。如果他愿意,OP 可以添加一个ORDER BY 子句。【参考方案2】:

您可以使用CASE,如下所示。

SELECT 
       CASE 
              WHEN id= @firstId THEN 1 
              WHEN id=@secondId THEN 2 
              ELSE 3 
       END AS rn, 
       mycolumn 
FROM   mytable 
WHERE  id IN (@firstId, 
              @secondId, 
              @thirdId)

如果您为每个提供的 id 和 @firstId、@secondId 和 @thirdId 按升序排列,则可以使用 DENSE_RANK 的另一种方法。

SELECT DENSE_RANK() 
         OVER( 
           ORDER BY id) rn, 
       mycolumn 
FROM   mytable 
WHERE  id IN ( @firstId, @secondId, @thirdId ) 

【讨论】:

Same thing - 不,它们是不同的。第二个在编号方面会有空白,就像在 OP 的示例中一样,第一个不会。我假设 OP 正在使用这些数字来识别通过哪个 in 参数找到记录。 我喜欢你的CASE 方法,但如果id 没有以某种方式+1 排序,第一种方法可能不起作用。 Row_number 查询会匹配行吗?例如,如果我只有 @firstIdthirdId 的记录,则常量列必须为 1 和 3。 @PSK 还是错了。如果缺少某些行,则需要有间隙。 @TimBiegeleisen,谢谢,我已经相应地更新了描述【参考方案3】:

为此我会推荐一个表值构造函数:

select v.outputnum, my_column
from mytable t join
     (values (@firstid, 1),
             (@secondid, 2),
             (@thirdid, 3)
     ) v(id, outputnum)
     on t.id = v.id
order by v.outputnum;

我认为这比其他版本更简单,因为 id 列表仅在查询中出现一次 - 因此查询的不同部分不同步的危险。

【讨论】:

这肯定是最好的解决方案。 +1

以上是关于如何将 UNION 更改为 IN 子句?的主要内容,如果未能解决你的问题,请参考以下文章

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

如何在 UNION 之间的 SQL 中放置 ORDER BY 子句

带有 union 和 in 子句的 Mysql 错误

MySQL UNION SELECT 和 IN 子句

Mysql Unknown column in where 子句 union all

强制 MySQL 从 WHERE IN 子句返回重复项而不使用 JOIN/UNION?