2009-02-12 67 views
37

当谈到SQL语法时,我是一个noob。如何将2个select语句合并为一个?

我有一个表,有很多场的行和列:P 可以说,它看起来像这样:

 AAA BBB CCC DDD 
----------------------- 
Row1 | 1 A D X 
Row2 | 2 B C X 
Row3 | 3 C D Z 

现在我想建立一个先进的select语句,让我这个组合(伪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 ...) 




我真正的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语句的一个副本结合起来,并且'Status'字段会被一个字符串'DELETED'改变。

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这是一个非常好问的问题 – 2012-05-01 15:01:32

回答

55

在这里你有两个选择。首先是有两个结果集,其将根据WHERE子句中的条件中设置“测试1”或“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上有效地扫描/查找两次。

其他的解决办法是从表中一次基于表的条件来选择,并设置“测试1”或“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声明。

+0

谢谢(即时通讯使用MS SQL Server 2005)。似乎这是我正在寻找的。联盟扫描两次,但我可以忍受。而且我不知道CASE声明可能会被事先使用。 – Wolf5 2009-02-12 23:15:38

9

如果他们是来自同一个表,我想UNION是你要找的命令。

(如果你会永远需要选择不同的表列的值,你应该看看JOIN,而不是...)

1
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。

1

使用的情况下,进入选择,并在那里接近A或

像这样使用,我没有测试,但它应该工作,我想......

select case when CCC='D' then 'test1' else 'test2' end, * 
from table 
where (CCC='D' AND DDD='X') or (CCC<>'D' AND DDD='X') 
1

我以为这就是你要找的内容:

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 

,它更有效率。

2

感谢您的意见。尝试已经在这里提到的东西,这些是2我开始工作:

(
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的例子,但没有按预期工作。

+0

这是可靠的。谢谢:) – Jordon 2015-10-14 23:38:30

0
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 

另一种方法可以做到这一点!

+0

使用2行对单列表进行简单测试,并使用该查询将第一个选择为t1,将第二个选择为t2,则失败,仅返回t1。 – Wolf5 2017-07-03 11:07:42

相关问题