57

当谈到 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'

这给了我一个结果。但是我想将它与这个选择语句的副本结合起来,并在末尾添加一个 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)
4

8 回答 8

77

你在这里有两个选择。第一个是有两个结果集,它们将根据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语句中复制过滤条件。

于 2009-02-12T18:49:40.743 回答
9

如果它们来自同一张桌子,我认为UNION是您正在寻找的命令。

(如果您需要从不同表的列中选择值,则应该查看JOIN...)

于 2009-02-12T18:45:44.047 回答
6

感谢您的输入。尝试了这里提到的东西,这些是我要工作的两个:

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

于 2009-02-13T10:28:19.490 回答
3
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

另一种方法来做到这一点!

于 2017-07-03T10:06:00.643 回答
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。

于 2009-02-12T18:45:56.650 回答
1

Union 命令是您所需要的。 如果这不起作用,您可能需要改进您所处的环境。

于 2009-02-12T18:46:30.957 回答
1

在选择中使用 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')
于 2009-02-12T18:49:55.580 回答
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

,效率更高。

于 2009-02-12T18:52:38.163 回答