如何将 2 个 select 语句合并为一个?
Posted
技术标签:
【中文标题】如何将 2 个 select 语句合并为一个?【英文标题】:How do I combine 2 select statements into one? 【发布时间】:2010-10-07 06:16:43 【问题描述】:在 SQL 语法方面,我是个菜鸟。
当然,我有一张有很多行和列的表格:P 假设它看起来像这样:
AAA BBB CCC DDD
-----------------------
Row1 | 1 A D X
Row2 | 2 B C X
Row3 | 3 C D Z
现在我想创建一个高级选择语句,它给我这个组合(这里是伪 SQLish):
select 'Test1', * from TABLE Where CCC='D' AND DDD='X'
select 'Test2', * from TABLE Where CCC<>'D' AND DDD='X'
输出将是:
Test1, 1, A, D, X
Test2, 2, B, C, X
如何将这两个 select 语句组合成一个不错的 select 语句?
如果我像下面这样复杂化 SQL 会起作用吗(因为我自己的 SQL 语句包含一个存在语句)?我只是想知道如何组合选择,然后尝试将其应用到我更高级的 SQL 中。
select 'Test1', * from TABLE Where CCC='D' AND DDD='X' AND exists(select ...)
select 'Test2', * from TABLE Where CCC<>'D' AND DDD='X' AND exists(select ...)
我的 REAL SQL 语句是这样的:
select Status, * from WorkItems t1
where exists (select 1 from workitems t2 where t1.TextField01=t2.TextField01 AND (BoolField05=1) )
AND TimeStamp=(select max(t2.TimeStamp) from workitems t2 where t2.TextField01=t1.TextField01)
AND TimeStamp>'2009-02-12 18:00:00'
这给了我一个结果。但我想将它与此 select 语句的副本结合起来,并在末尾添加 AND,并且“状态”字段将更改为类似“已删除”的字符串。
select 'DELETED', * from WorkItems t1
where exists (select 1 from workitems t2 where t1.TextField01=t2.TextField01 AND (BoolField05=1) )
AND TimeStamp=(select max(t2.TimeStamp) from workitems t2 where t2.TextField01=t1.TextField01)
AND TimeStamp>'2009-02-12 18:00:00'
AND NOT (BoolField05=1)
【问题讨论】:
+1 这个问题问得非常好 【参考方案1】:select t1.* from
(select * from TABLE Where CCC='D' AND DDD='X') as t1,
(select * from TABLE Where CCC<>'D' AND DDD='X') as t2
另一种方法!
【讨论】:
对具有 2 行的单列表进行简单测试,并使用该查询选择第一个作为 t1,第二个作为 t2,失败,仅返回 t1。【参考方案2】:这里有两个选择。第一个是有两个结果集,它们将根据WHERE
子句中的条件设置“Test1”或“Test2”,然后将它们放在一起UNION
:
select
'Test1', *
from
TABLE
Where
CCC='D' AND DDD='X' AND exists(select ...)
UNION
select
'Test2', *
from
TABLE
Where
CCC<>'D' AND DDD='X' AND exists(select ...)
这可能是个问题,因为您将有效地扫描/查找 TABLE 两次。
另一种解决方案是从表中选择一次,然后根据 TABLE 中的条件设置“Test1”或“Test2”:
select
case
when CCC='D' AND DDD='X' AND exists(select ...) then 'Test1'
when CCC<>'D' AND DDD='X' AND exists(select ...) then 'Test2'
end,
*
from
TABLE
Where
(CCC='D' AND DDD='X' AND exists(select ...)) or
(CCC<>'D' AND DDD='X' AND exists(select ...))
这里的问题是您必须在CASE
语句和WHERE
语句中复制过滤条件。
【讨论】:
谢谢(我使用 MS SQL Server 2005)。好像这就是我要找的。 UNION 扫描两次,但我可以忍受。而且我不知道 CASE 语句可以被预先使用。【参考方案3】:感谢您的意见。尝试了这里提到的东西,这些是我要工作的两个:
(
select 'OK', * from WorkItems t1
where exists(select 1 from workitems t2 where t1.TextField01=t2.TextField01 AND (BoolField05=1) )
AND TimeStamp=(select max(t2.TimeStamp) from workitems t2 where t2.TextField01=t1.TextField01)
AND TimeStamp>'2009-02-12 18:00:00'
AND (BoolField05=1)
)
UNION
(
select 'DEL', * from WorkItems t1
where exists(select 1 from workitems t2 where t1.TextField01=t2.TextField01 AND (BoolField05=1) )
AND TimeStamp=(select max(t2.TimeStamp) from workitems t2 where t2.TextField01=t1.TextField01)
AND TimeStamp>'2009-02-12 18:00:00'
AND NOT (BoolField05=1)
)
与
select
case
when
(BoolField05=1)
then 'OK'
else 'DEL'
end,
*
from WorkItems t1
Where
exists(select 1 from workitems t2 where t1.TextField01=t2.TextField01 AND (BoolField05=1) )
AND TimeStamp=(select max(t2.TimeStamp) from workitems t2 where t2.TextField01=t1.TextField01)
AND TimeStamp>'2009-02-12 18:00:00'
哪一个是最有效的(编辑:第二个,因为它只扫描表一次),是否有可能让它更有效? (BoolField=1)实际上是一个变量(dyn sql),可以包含表上的任何where语句。
我在 MS SQL 2005 上运行。尝试了 Quassnoi 示例,但没有按预期工作。
【讨论】:
这是可靠的。谢谢:)【参考方案4】:我想这就是你要找的东西:
SELECT CASE WHEN BoolField05 = 1 THEN Status ELSE 'DELETED' END AS MyStatus, t1.*
FROM WorkItems t1
WHERE (TextField01, TimeStamp) IN(
SELECT TextField01, MAX(TimeStamp)
FROM WorkItems t2
GROUP BY t2.TextField01
)
AND TimeStamp > '2009-02-12 18:00:00'
如果您使用的是 Oracle 或 MS SQL 2005 及更高版本,那么您可以这样做:
SELECT *
FROM (
SELECT CASE WHEN BoolField05 = 1 THEN Status ELSE 'DELETED' END AS MyStatus, t1.*,
ROW_NUMBER() OVER (PARTITION BY TextField01 ORDER BY TimeStamp DESC) AS rn
FROM WorkItems t1
) to
WHERE rn = 1
,效率更高。
【讨论】:
【参考方案5】:在 select 中使用 case 并在 where close 中使用 OR
类似的东西,我没有测试过,但它应该可以工作,我认为......
select case when CCC='D' then 'test1' else 'test2' end, *
from table
where (CCC='D' AND DDD='X') or (CCC<>'D' AND DDD='X')
【讨论】:
【参考方案6】:The Union command is what you need. 如果这不起作用,您可能需要改进您所处的环境。
【讨论】:
【参考方案7】:select Status, * from WorkItems t1
where exists (select 1 from workitems t2 where t1.TextField01=t2.TextField01 AND (BoolField05=1) )
AND TimeStamp=(select max(t2.TimeStamp) from workitems t2 where t2.TextField01=t1.TextField01)
AND TimeStamp>'2009-02-12 18:00:00'
UNION
select 'DELETED', * from WorkItems t1
where exists (select 1 from workitems t2 where t1.TextField01=t2.TextField01 AND (BoolField05=1) )
AND TimeStamp=(select max(t2.TimeStamp) from workitems t2 where t2.TextField01=t1.TextField01)
AND TimeStamp>'2009-02-12 18:00:00'
AND NOT (BoolField05=1)
也许这样就可以了。不过,我无法从这里对其进行测试,而且我不确定您使用的是哪个版本的 SQL。
【讨论】:
【参考方案8】:如果它们来自同一个表,我认为UNION
是您要查找的命令。
(如果您需要从不同表的列中选择值,则应改为查看 JOIN
...)
【讨论】:
以上是关于如何将 2 个 select 语句合并为一个?的主要内容,如果未能解决你的问题,请参考以下文章
如何将这些 SQL SELECT 查询合并到一个 SELECT 语句中
将多个 CASE 语句合并为一个并 SELECT INTO 临时表