【问题标题】:Checking whether any two of ten fields are different (not NULL or equal)检查十个字段中的任何两个是否不同(不为 NULL 或等于)
【发布时间】:2019-08-14 16:18:20
【问题描述】:

我有一个包含(除其他外)十个字段的 SQL 查询,称它们为 v1、...、v10,我想对其进行测试。预期的情况是大多数为 NULL,其余的值都相等。我正在寻找的有趣(错误?)情况是至少有两个不相等的非 NULL 值。

有没有比这个更好的方法

v1 != v2 or v1 != v3 or ... v8 != v9 or v8 != v10 or v9 != v10

二项式 (10, 2) = 总共 45 个条件?

除了不优雅之外,它似乎很脆弱——而且刚刚调试了一个问题,即长列表中的一个变量有错字,而不仅仅是学术问题。但如果这是唯一可行的方法……虽然如果列表扩展到 20 则就不那么好了。

【问题讨论】:

  • 一定要用SQL写吗?
  • 每列有唯一的 id 吗?
  • @mkRabbani 是的——在我的例子中实际上是一个复合 id,但你可以假设一个字段 unique_id 存在。
  • 我有一个想法,但我不确定是否可行,我现在不能自己尝试。你可以写类似v1 NOT IN (v2, v3, v4 ...) or v2 NOT IN (v1, v3, ...)
  • @ArnaudClaudel NOT IN 不是 NULL safe

标签: sql oracle dry maintainability


【解决方案1】:

UNPIVOT 列到行,然后GROUP BY 您的主键和COUNT 未透视列中的DISTINCT 值,以查看是否存在多个唯一值:

Oracle 11 设置:

CREATE TABLE table_name ( id, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10 ) AS
  SELECT 1, 'A', 'A',  NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL FROM DUAL UNION ALL
  SELECT 2, 'A', NULL, 'B',  NULL, NULL, NULL, NULL, NULL, NULL, NULL FROM DUAL UNION ALL
  SELECT 3, 'A', NULL, 'A',  'A',  NULL, 'A',  'A',  'A',  'A',  'A'  FROM DUAL UNION ALL
  SELECT 4, 'A', NULL, 'A',  'A',  'B',  NULL, NULL, NULL, NULL, NULL FROM DUAL;

查询:

SELECT id
FROM   table_name
UNPIVOT ( value FOR name IN ( c1, c2, c3, c4, c5, c6, c7, c8, c9, c10 ) )
GROUP BY id
HAVING COUNT( DISTINCT value ) > 1

输出:

|身份证 | | -: | | 2 | | 4 |

db小提琴here

【讨论】:

    【解决方案2】:

    在 Oracle 12c+ 中,您可以使用横向连接:

    select t.*
    from t cross join lateral
         (select count(distinct field) as cnt
          from (select t.field1 as field from dual union all
                select t.field2 as field from dual union all
                select t.field3 as field from dual union all
                select t.field4 as field from dual union all
                select t.field5 as field from dual union all
                select t.field6 as field from dual union all
                select t.field7 as field from dual union all
                select t.field8 as field from dual union all
                select t.field9 as field from dual union all
                select t.field10 as field from dual 
               ) x
         ) x
    where cnt > 1;
    

    这在早期版本中很痛苦。

    这是一种不太令人沮丧的方法:

    select t.*
    from (select t.*,
                 (field1 || ',' || field2 || ',' || . . . || field10) as fields
          from t
         ) t
    where replace(replace(fields, regexp_substr(fields, '[^,]+', 1), ''), ',', '') is not null;
    

    这假设字段本身不包含逗号;如果是这样,请使用不同的分隔符。

    这个想法是返回一些值;然后替换那个值和逗号,看看你是否留下了一个NULL/空字符串。

    【讨论】:

      【解决方案3】:

      以下脚本将允许您检查所有 10 个值是否不同。仅当所有 10 个值都不同时,该行才会返回-

      您可以查看DEMO HERE

      WITH CTE(id,v1,v2,v3,v4,v5,v6,v7,v8,v9,v10)
      AS
      (
          SELECT 1,10,20,30,505,50,60,70,80,90,100 FROM DUAL
      ),
      CTE2 AS
      (
          SELECT A.ID,A.Value, 
          DENSE_RANK() OVER (PARTITION BY ID ORDER BY VALUE ) AS D_RANK_NUM
          -- As you said you have composit unique column, 
          -- you can add those columns here for PARTITION BY
          -- I have used ID as sample Unique column
          FROM
          (
              SELECT *
              FROM   CTE
              UNPIVOT (value FOR V IN (v1,v2,v3,v4,v5,v6,v7,v8,v9,v10))
          )A
      )
      
      SELECT * FROM CTE WHERE ID IN(
          SELECT ID FROM CTE2 WHERE D_RANK_NUM = 10
      )
      

      【讨论】:

        猜你喜欢
        • 2015-06-02
        • 1970-01-01
        • 2019-03-24
        • 2014-06-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-10-15
        • 2019-10-28
        相关资源
        最近更新 更多