SQL WHERE 匹配任何列中的任何值

Posted

技术标签:

【中文标题】SQL WHERE 匹配任何列中的任何值【英文标题】:SQL WHERE matching any value in any column 【发布时间】:2015-07-10 18:17:29 【问题描述】:

我需要一个包含 4 列订单号的表 A:Order1、Order2、Order3、Order4(我知道,这很糟糕,但这是给定的)。

我必须找到表 B 中的记录,其中匹配是表 A 中任何顺序列中的任何值都可以在 B 列中以任何顺序:

A.Order1 = B.Order1 OR
A.Order1 = B.Order2 OR
A.Order1 = B.Order3 OR
A.Order1 = B.Order4 OR
A.Order2 = B.Order1 etc

有没有更好的方法来写这个? 我害怕他们告诉我他们想要使用 5 或 6 列的那一刻。

对原始问题的编辑

这适用于 SQL Server 2008 R2 表 B 也有 4 个带有订单号的订单列 我正在查找表 A 中任何订单列中的任何订单号,以匹配表 B 中任何订单列中的任何订单号。 没有预期的最有可能的发现

【问题讨论】:

多个列可以同时包含值吗?还是总是只有一列被填满? 不,你被多个子句困住了。也就是说,您可以使用动态 SQL 方法根据可用列自动生成 SQL。如何执行此选项将取决于您使用的数据库,您没有指定(标记)。 那么,Table B 也有 4 个 Order 列?顺便说一句,您的 WHERE 正在使用表 A 中的每一列 什么数据库:mysql、MS-SQL、Oracle 等等? 是A中的4个订单必须匹配B中的4个订单,或者A中的至少一个订单匹配B中的至少一个订单的想法? 【参考方案1】:

您可以使用交叉应用取消透视一个表中的列,然后检查交叉应用的值是否在另一个表的任何列中。

如果您添加新列,它不会自动工作,但您只需将它们添加到一两个位置。

SQL Fiddle

MS SQL Server 2014 架构设置

create table A
(
  Order1 int,
  Order2 int,
  Order3 int,
  Order4 int
)

create table B
(
  Order1 int,
  Order2 int,
  Order3 int,
  Order4 int
)

insert into A values
(1, 1, 40, 10),
(2, 2, 2, 20)

insert into B values
(3, 3, 3, 30),
(4, 4, 4, 40)

查询 1

select *
from A
where exists (
             select *
             from B
               cross apply (values(B.Order1),(B.Order2),(B.Order3),(B.Order4)) as X(O)
             where X.O in (A.Order1, A.Order2, A.Order3, A.Order4)
             )       

Results

| Order1 | Order2 | Order3 | Order4 |
|--------|--------|--------|--------|
|      1 |      1 |     40 |     10 |

【讨论】:

Mikael,我不明白... X(0) 和 X.0 是什么? @Amarundo X 是从 B 的一行的值创建的派生表,O 是这些值的列名。 @Amarundo 这是一个动态创建的新临时表。表名X列名O。X.O引用表X中的O列 非常感谢!我相信你的解决方案是为硬汉准备的。我选择了另一个,因为它对我和未来查看代码的人(我的知识有限)来说更容易理解。【参考方案2】:

使用您拥有的模型设计执行此操作的唯一方法是(如@GordonLinoff 建议的那样):

where b.order1 in (a.order1, a.order2, a.order3, a.order4) or
      b.order2 in (a.order1, a.order2, a.order3, a.order4) or
      b.order3 in (a.order1, a.order2, a.order3, a.order4) or
      b.order4 in (a.order1, a.order2, a.order3, a.order4) 

您可能会遇到一个有趣的问题,即如何更改我的数据模型以使其更好地工作? ...方法如下:

首先,您有两个表 A 和 B。我将假设 A 和 B 都有唯一的索引 ID。

然后您可以使用以下列创建支持表 AOrder

AID 
ORDNUM
VALUE

如果您为 BOrder 制作了一个类似的表,那么要找出给定的订单是否相同,只需加入 Value 即可获得 AID、BID 和两个订单号。

有了这种设计,你就不用关心有多少订单号了。

您可以像这样即时将当前数据转换为此设计并获得您想要的结果:

 SELECT aord.ID as aID, bord.ID as bID, a.num as a_ordernum, b.num as b.ordernum, v 
 FROM (
   SELECT a.ID, 1 AS num, a.order1 as V FROM a
     UNION ALL
   SELECT a.ID, 2 AS num, a.order2 as V FROM a
     UNION ALL
   SELECT a.ID, 3 AS num, a.order3 as V FROM a
     UNION ALL
   SELECT a.ID, 4 AS num, a.order4 as V FROM a
 ) aord
 JOIN (
   SELECT b.ID, 1 AS num, b.order1 as V FROM b
     UNION ALL
   SELECT b.ID, 2 AS num, b.order2 as V FROM b
     UNION ALL
   SELECT b.ID, 3 AS num, b.order3 as V FROM b
     UNION ALL
   SELECT b.ID, 4 AS num, b.order4 as V FROM b
 ) bord on aord.v = bord.v

【讨论】:

【参考方案3】:

你能把它们标准化吗?我假设您有一个 SetID 字段对 A 和 B 中的 4 个(或更多)订单进行分组,因此您可以有一个表格/视图,例如:

    select ID, srctbl, seq, order
    from (
    select AID as ID, 'A' as srctbl, 1 as seq, order1 as order from tblA union all
    select AID, 'A' as srctbl, 2, order2 from tblA union all
    select AID, 'A' as srctbl, 3, order3 from tblA union all
    select AID, 'A' as srctbl, 4, order4 from tblA union all
    select BID, 'B' as srctbl, 1, order1 from tblB union all
    select BID, 'B' as srctbl, 2, order2 from tblB union all
    select BID, 'B' as srctbl, 3, order3 from tblB union all
    select BID, 'B' as srctbl, 4, order4 from tblB )

那你可以说

select ID, srctbl, seq, order 
from (select ID, srctbl, seq, order from tbl where srctbl = 'a') ta inner join
((select ID, srctbl, seq, order from tbl where srctbl = 'b') tb on
ta.order = tb.order

或者,作为 CTE:

WITH orders (ID, srctbl, SEQ, orderVal)
AS (
   SELECT ID, srctbl, SEQ, orderVal
    FROM (
    SELECT AID AS ID, 'A' AS srctbl, 1 AS SEQ, order1 AS orderVal FROM tblA UNION ALL
    SELECT AID, 'A' AS srctbl, 2, order2 FROM tblA UNION ALL
    SELECT AID, 'A' AS srctbl, 3, order3 FROM tblA UNION ALL
    SELECT AID, 'A' AS srctbl, 4, order4 FROM tblA UNION ALL
    SELECT BID, 'B' AS srctbl, 1, order1 FROM tblB UNION ALL
    SELECT BID, 'B' AS srctbl, 2, order2 FROM tblB UNION ALL
    SELECT BID, 'B' AS srctbl, 3, order3 FROM tblB UNION ALL
    SELECT BID, 'B' AS srctbl, 4, order4 FROM tblB )
)

SELECT ta.ID AS a_id, tb.ID AS b_ID, ta.SEQ AS a_seq, tb.SEQ AS b_seq, ta.orderVal 
FROM 
 (SELECT ID, SEQ, orderVal FROM orders WHERE srctbl = 'a') ta INNER JOIN
 (SELECT ID, SEQ, orderVal FROM orders WHERE srctbl = 'b') tb ON
ta.orderVal = tb.orderVal

【讨论】:

我无法触及这些表格的规格。 不,您不会更改架构,请使用 from 子句中的 select/union 集的结果代替“tbl”。您从 Hogan 那里接受的答案也是如此。

以上是关于SQL WHERE 匹配任何列中的任何值的主要内容,如果未能解决你的问题,请参考以下文章

SqlAlchemy:过滤以匹配所有而不是列表中的任何值?

如何在 SQL Server 中的 OR 条件中确定优先级

我需要使用索引和匹配从另一列中的条件匹配的一列中提取数据

SQL如何使用同一列中的值匹配2个表

如何为'where'子句中的项目返回一些默认值,这些项目在数据库表列中不匹配(不存在)

返回查询的所有行,其中一列中的字符串值与另一列中的字符串值匹配