【问题标题】:How do I select non null unequal values across columns?如何跨列选择非空不相等值?
【发布时间】:2020-10-21 11:51:55
【问题描述】:

我想选择 5 列中的值(如果不为空)不相等的记录。任意数量的列都可以是非空的。

架构: 给定表

**Schema (SQLite v3.30)**

    CREATE TABLE test (
      id INT,
      col1 text,
      col2 text,
      col3 text,
      col4 text,
      col5 text
    );
    INSERT INTO test (id, col1, col2, col3, col4, col5) VALUES (1, 'EA', 'EA', null, null, null);
    INSERT INTO test (id, col1, col2, col3, col4, col5) VALUES (2, 'EA', 'MT', null, null, null);
    INSERT INTO test (id, col1, col2, col3, col4, col5) VALUES (3, null, 'EA', null, 'KG', null);
    INSERT INTO test (id, col1, col2, col3, col4, col5) VALUES (4, null, null, 'KG', 'MT', 'AB');
    INSERT INTO test (id, col1, col2, col3, col4, col5) VALUES (5, null, null, 'EA', 'MT', 'EA');

---

**Query #1**

    SELECT * FROM test;

| id  | col1 | col2 | col3 | col4 | col5 |
| --- | ---- | ---- | ---- | ---- | ---- |
| 1   | EA   | EA   |      |      |      |
| 2   | EA   | MT   |      |      |      |
| 3   |      | EA   |      | KG   |      |
| 4   |      |      | KG   | MT   | AB   |
| 5   |      |      | EA   | MT   | EA   |

---

期望的输出

| id  | col1 | col2 | col3 | col4 | col5 |
| --- | ---- | ---- | ---- | ---- | ---- |
| 2   | EA   | MT   |      |      |      |
| 3   |      | EA   |      | KG   |      |
| 4   |      |      | KG   | MT   | AB   |
| 5   |      |      | EA   | MT   | EA   |

编辑:为了澄清, id=5 包含在输出中,因为并非所有值都相同。当我声明所有列的值不相等时,我的意思是是否有任何值与其他非空值不同。换一种说法,我要求记录至少有 1 个与其他非空值不同的非空值。

【问题讨论】:

  • 您希望没有重复项或所有值都不相等吗?
  • 您能详细说明一下吗?我的意思是说如果 2 个或更多值不为 null,它们应该是不相等的。这就是我要查询的内容。

标签: sql sqlite


【解决方案1】:

嗯。 . .这很棘手。假设空值是 NULL 并且没有值是空白的并且您想要所有不同的值,您可以这样做:

select t.*
from test t
where (col1 is null or col1 not in (coalesce(col2, ''), coalesce(col3, ''), coalesce(col4, ''), coalesce(col5, ''))) and
      (col2 is null or col2 not in (coalesce(col3, ''), coalesce(col4, ''), coalesce(col5, ''))) and
      (col3 is null or col3 not in (coalesce(col4, ''), coalesce(col5, ''))) and
      (col4 is null or col4 not in (coalesce(col5, ''))) 

编辑:

如果您只想要多个不同的值,那么:

select t.*
from test t
where col1 not in (coalesce(col2, ''), coalesce(col3, ''), coalesce(col4, ''), coalesce(col5, '')) or
      col2 not in (coalesce(col1, ''), coalesce(col3, ''), coalesce(col4, ''), coalesce(col5, '')) or
      col3 not in (coalesce(col1, ''), coalesce(col2, ''), coalesce(col4, ''), coalesce(col5, '')) or
      col4 not in (coalesce(col1, ''), coalesce(col2, ''), coalesce(col3, ''), coalesce(col5, ''))

Here 是一个 dbfiddle。

注意:这不会返回只有一个值在技术上不符合您的规范的行。

【讨论】:

  • @scientific_explorer 此代码将非常适合超过 5 列。
  • @forpas 没关系,因为这对我来说是一种情况,即使我同意你的观点。
  • 这对于边缘情况(我目前面临的情况)失败,其中 3 个值中有 2 个匹配。例如。 col2=EA, col3=AB, col5=EA,那么这会失败。
  • @scientific_explorer 。 . .就查询的性能而言,这应该比使用聚合的解决方案具有更好的扩展性。当然,如果有更多的列,查询会变得更复杂。
  • @GordonLinoff 我对“规模”的理解是,当涉及更多列时,必须写更多的单词/行。现在可以处理我在 cmets 中提到的边缘情况吗?
【解决方案2】:

您可以聚合每个 id 与 1 列的并集,并在 having 子句中设置条件:

with cte as (
  select id from (
    select id, col1 col from test union all
    select id, col2 from test union all
    select id, col3 from test union all
    select id, col4 from test union all
    select id, col5 from test
  )
  where col is not null
  group by id
  having count(distinct col) > 1
)
select * from test where id in cte

请参阅demo
结果:

> id | col1 | col2 | col3 | col4 | col5
> -: | :--- | :--- | :--- | :--- | :---
>  2 | EA   | MT   | null | null | null
>  3 | null | EA   | null | KG   | null
>  4 | null | null | KG   | MT   | AB  
>  5 | null | null | EA   | MT   | EA 

【讨论】:

  • 感谢您的回答。我当然从中学到了一些东西:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-10-01
  • 2018-06-24
  • 2016-01-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-04
相关资源
最近更新 更多