【问题标题】:SQL Select cases from a long table where ID is not duplicatedSQL 从 ID 不重复的长表中选择案例
【发布时间】:2021-01-11 06:31:23
【问题描述】:

我有一张如下表:

id | ncode | code
=================
1      1     ABC
1      2     DEF
2      1     ABC
3      1     ABC
4      1     ABC
4      2     DEF

我有两个要求:

  1. ncode == 1 和 code == ABC 的所有记录
  2. 但前提是id 没有在表中的某处重复(即,我不想要code == ABC 的记录,如果相同的id 在某处也有ncode > 1在表格中。

select * from table where code == "ABC" and ncode == 1 将满足第一个要求,但我不知道如何满足第二个要求。

给定上面的示例表,我想要的输出是:

id | ncode | code
=================
2      1     ABC
3      1     ABC

根据下面的答案,我使用了窗口函数:

select *
from (
   select *,
    sum(case when ncode > 1 then 1 else 0 end) over(partition by id) cnt
   from mytable
)
where code = 'ABC' and ncode = 1 and cnt = 0 order by id

然后我实现了接受的答案提供的 Google BiqQuery 特定语法:

select id, ANY_VALUE(ncode) ncode, ANY_VALUE(code) code
from mytable
group by id
having count(1) = 1
and (cpt, ncode) = ('ABC', 1)

【问题讨论】:

  • 请用您正在运行的数据库标记您的问题:postgresql、oracle、mysql...?
  • 我已标记google-bigquery

标签: sql count google-bigquery subquery window-functions


【解决方案1】:

以下也应该可以工作(BigQuery 标准 SQL)

#standardSQL
SELECT id, 
  ANY_VALUE(ncode) ncode, 
  ANY_VALUE(code) code
FROM `project.dataset.table`
GROUP BY id
HAVING COUNT(1) = 1
AND (code, ncode) = ('ABC', 1)   

【讨论】:

  • 谢谢!你能解释一下count(1)到底在做什么吗?我了解count 函数,我看到您按id 分组,但为什么命令不是having count(id) = 1 而不是having count(1) = 1?我一定是误会了什么。
  • 在这种情况下,count(1) 和 count(id) 执行相同的操作 - 它们只是简单地计算每个 Id 的行数并过滤掉具有重复数据的行
  • 好的,所以我正确理解了这些命令。谢谢你的澄清。
  • 如果有帮助,请考虑对答案进行投票:o)
【解决方案2】:

你可以使用窗口函数:

select *
from (select t.*, count(*) over(partition by id, code) cnt from mytable) t
where code = 'ABC' and ncode = 1 and cnt = 1

这假定每个 code 没有重复的 ncode,并且没有低于 1 的值。否则,我们可以在窗口函数中更具体:

select *
from (
    select t.*, 
        sum(case when ncode > 1 then 1 else 0 end) over(partition by id, code) cnt 
    from mytable 
) t
where code = 'ABC' and ncode = 1 and cnt = 0

【讨论】:

  • 我必须稍微修改您的代码,请参阅对我的原始问题的编辑。
【解决方案3】:

最简单的方法可能是使用 NOT EXISTS 条件 - 应该是这样的:

SELECT  t.*
FROM    TABLE t
WHERE   t.code = "ABC"
        AND t.ncode = 1
        AND NOT EXISTS
        (
        SELECT  NULL
        FROM    TABLE ti
        WHERE   ti.id = t.id
                AND ti.ncode > 1
        );
        

【讨论】:

    【解决方案4】:

    您可以使用NOT EXISTS 和相关子查询,在表中搜索具有相同id 但较大ncode 的记录。

    SELECT t1.*
           FROM elbat t1
           WHERE t1.code = 'ABC'
                 AND t1.ncode = 1
                 AND NOT EXISTS (SELECT *
                                        FROM elbat t2
                                        WHERE t2.id = t1.id
                                              AND t2.ncode > t1.ncode);
    

    顺便说一句:停止对字符串文字使用双引号。尽管您的 DBMS 可能会接受这一点,但标准双引号用于标识符,单引号用于字符串文字。通过遵循这一点,您的代码将变得更加可移植。 == 作为比较运算符也是如此。最好使用=

    为了提高性能,您需要在(id, ncode) 上建立索引。

    【讨论】:

    • 感谢您的建议,我只做了很少的 SQL 并且来自 R。将切换它。
    猜你喜欢
    • 1970-01-01
    • 2020-10-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多