1

我正在尝试编写一个带有 where 子句的 sql,它检查列表中的任何元素是否在另一个列表中。有没有更短的方法来完成这个而不是检查第一个列表的每个成员?

SELECT * from FOO
WHERE FOO.A IN ('2','3', '5', '7','11','13','17','19') OR
  FOO.B IN ('2','3', '5', '7','11','13','17','19') OR
  FOO.C IN ('2','3', '5', '7','11','13','17','19') OR
  FOO.D IN ('2','3', '5', '7','11','13','17','19') OR
  FOO.E IN ('2','3', '5', '7','11','13','17','19') OR
  FOO.F IN ('2','3', '5', '7','11','13','17','19')

那是简化的sql。

试图不要把水弄得太多,但既然你问:

最终我在这里要做的是,从 FOO 中选择行,其中的列满足各种标准。这些条件存储在第二个表(称为 BAR)中,主要是 db、名称、类型必须匹配且标志必须为 1。计划从 BAR 构建 IN 列表,将它们与包含 FOO 的 INFORMATION_SCHEMA.COLUMNS 中的列名进行比较

福:

+--------+--------+---------+---------+--------+-------+
|   DB   | Name   | Type    | Col1    |  Col2  | Col3  |
+--------+--------+---------+---------+--------+-------+
|   4    | AC1    | LO      | 1       |  10    | 2     |
|   4    | AC1    | HI      | 2       |  20    | 4     |
|   1    | DC2    | HI-HI   | 11      |  5     | 2     |
|   1    | DC2    | HI      | 22      |  10    | 4     |
|   1    | DC2    | LO      | 33      |  15    | 6     |
+--------+--------+---------+---------+--------+-------+

酒吧:

+--------+--------+---------+---------+--------+
|   DB   | Name   | Type    | Field   |  Flag  |
+--------+--------+---------+---------+--------+
|   4    | AC1    | LO      | Col1    |  1     |
|   4    | AC1    | HI      | Col1    |  1     |
|   1    | DC2    | HI-HI   | Col1    |  1     |
|   1    | DC2    | HI      | Col1    |  1     |
|   1    | DC2    | LO      | Col1    |  1     |
|   4    | AC1    | LO      | Col2    |  0     |
|   4    | AC1    | HI      | Col2    |  0     |
|   1    | DC2    | LO      | Col2    |  0     |
|   1    | DC2    | HI-HI   | Col2    |  0     |
|   1    | DC2    | HI      | Col2    |  0     |
|   4    | AC1    | LO      | Col3    |  0     |
|   4    | AC1    | HI      | Col3    |  0     |
|   1    | DC2    | LO      | Col3    |  0     |
|   1    | DC2    | HI-HI   | Col3    |  0     |
|   1    | DC2    | HI      | Col3    |  0     |
+--------+--------+---------+---------+--------+
4

3 回答 3

0

您的方法可能效果最好。这是一个只需要创建一次列表的替代方法。它使用 CTE 创建值列表,然后使用exists子句检查是否有任何值匹配:

with vals as (
      select '2' as p union all
      select '3' union all
      select '5' union all
      select '7' union all
      select '11' union all
      select '13' union all
      select '17' union all
      select '19'
     )
select *
from foo
where exists (select 1 from vals where vals.p in (foo.A, foo.B, foo.C, foo.D, foo.E, foo.F))

如果您使用的数据库不支持 CTE,则只需将代码放在where子句中:

select 8
from foo
where exists (select 1
              from (select '2' as p union all
                    select '3' union all
                    select '5' union all
                    select '7' union all
                    select '11' union all
                    select '13' union all
                    select '17' union all
                    select '19'
                   ) t
              where vals.p in (foo.A, foo.B, foo.C, foo.D, foo.E, foo.F)
             )

如果您使用的是 Oracle,那么您需要from dual在字符串常量之后添加语句。否则,我认为其中一个应该适用于任何 SQL 数据库。

于 2013-04-19T20:05:42.090 回答
0

虽然尚不清楚您要对数据做什么,但由于您使用的是 SQL Server,我的建议是使用 UNPIVOT 函数将col1,col2col3列转换为行,这样可以更轻松地过滤数据:

select db, name, type, col, value
from foo
unpivot
(
  value
  for col in (Col1, Col2, Col3)
) unpiv;

请参阅SQL Fiddle with Demo。这将提供以下格式的数据:

| DB | NAME |  TYPE |  COL | VALUE |
------------------------------------
|  4 |  AC1 |    LO | Col1 |     1 |
|  4 |  AC1 |    LO | Col2 |    10 |
|  4 |  AC1 |    LO | Col3 |     2 |
|  4 |  AC1 |    HI | Col1 |     2 |

BAR一旦采用行格式,应用任何过滤器甚至连接到您的表应该会容易得多。

于 2013-04-19T20:40:23.147 回答
0

在第一次检查时,您的架构似乎不适合您正在执行的查询类型。似乎您想要一个具有类型和值的 FOOVAL 表,然后您的查询就变成了:

CREATE TABLE FOOVAL
{
    ID int, -- References FOO.ID
    TYPE char, -- A, B, C, D, E, F
    VAL int
}

SELECT * FROM FOO WHERE FOO.ID IN
(SELECT DISTINCT FOOVAL.ID WHERE FOOVAL.VAL IN ('2','3', '5', '7','11','13','17','19'))
于 2013-04-19T20:11:40.540 回答