在值列表中查找值列表

时间:2013-04-19 19:48:32

标签: sql sql-server

我正在尝试使用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,name,type必须匹配,flag必须为1.计划从BAR构建IN列表,将它们与包含FOO的INFORMATION_SCHEMA.COLUMNS中的列名进行比较< / p>

FOO:

+--------+--------+---------+---------+--------+-------+
|   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     |
+--------+--------+---------+---------+--------+-------+

BAR:

+--------+--------+---------+---------+--------+
|   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     |
+--------+--------+---------+---------+--------+

3 个答案:

答案 0 :(得分: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数据库。

答案 1 :(得分: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'))

答案 2 :(得分:0)

虽然您不清楚要对数据做什么,但由于您使用的是SQL Server,我的建议是使用UNPIVOT函数来转换col1col2和{{ 1}}列成行,这样可以更轻松地过滤数据:

col3

SQL Fiddle with Demo。这将以下列格式提供数据:

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

一旦采用行格式,应用任何过滤器甚至加入| 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 | 表格应该会更加容易。