【问题标题】:Count number of certain value that shows per ID计算每个 ID 显示的特定值的数量
【发布时间】:2020-01-15 17:14:29
【问题描述】:

我希望此查询在每个 ID 的两个单独列中显示是和否答案的数量(每个 ID 将有多个条目)。我怎样才能做到这一点?

感谢您的帮助!

select 
    id, 
    Yes_No,
    (select count(Yes_No) from Survey where Yes_No = 'Y') as '# of Yes',
    (select count(Yes_No) from Survey where Yes_No ='N') as '# of No'
from Survey;

【问题讨论】:

  • 您使用的是哪个 RDBMS?

标签: sql database group-by count window-functions


【解决方案1】:

你很接近。您只需要将SELECT子句中的内联查询关联到当前的id,例如:

select 
    id, 
    Yes_No,
    (select count(Yes_No) from Survey where Yes_No = 'Y' and id = s.id) as '# of Yes',
    (select count(Yes_No) from Survey where Yes_No ='N' and id = s.id) as '# of No'
from Survey s;

注意:如果您的 RDBMS 支持 windows 函数,则有一个更简单的选项来使用条件窗口和:

select 
    id, 
    Yes_No,
    SUM(CASE WHEN Yes_No = 'Y' THEN 1 ELSE 0 END) OVER(PARTITION BY id) as '# of Yes',
    SUM(CASE WHEN Yes_No = 'N' THEN 1 ELSE 0 END) OVER(PARTITION BY id) as '# of No'
from Survey;

【讨论】:

  • 欢迎@DanielViolante!乐于助人。
【解决方案2】:

如果您的数据库中没有可用的分析函数,我会计算几个子查询。我通常避免在选择列表中进行相关查询:

SELECT 
  s.id, 
  s.Yes_No,
  COALESCE(y.countYes, 0) as countYes,
  COALESCE(n.countNo, 0) as countNo
FROM
  Survey s
  LEFT JOIN
  (SELECT id, COUNT(*) as countYes from Survey WHERE Yes_No = 'Y' GROUP BY id ) y
  ON y.id = s.id

  LEFT JOIN
  (SELECT id, COUNT(*) as countNo from Survey WHERE Yes_No = 'N' GROUP BY id ) n
  ON n.id = s.id;

这很容易理解 - 计数和组已完成并重新加入。如果特定 ID 没有 Y 或 N,我们离开了连接,因此行不会从结果中消失。这样做可能会更高效,所以我们不会对表进行两次分组和计数(一个用于 Y,一个用于 N

SELECT 
  s.id, 
  s.Yes_No,
  c.countYes,
  c.countNo
FROM
  Survey s
  INNER JOIN
  (
    SELECT 
      id, 
      COUNT(CASE WHEN Yes_No = 'Y' THEN 1 END) as countYes,
      COUNT(CASE WHEN Yes_No = 'N' THEN 1 END) as countNo
    FROM Survey  
    GROUP BY id
   ) c
  ON c.id = s.id

这个和下面的一个使用条件计数技术,稍后将详细解释。这个可以安全地进行内部连接,因为调查中的每个 ID 在子查询中都会有匹配的内容。由于单一的聚合操作,它可能会表现得更好

如果您的数据库支持分析/窗口函数,它会变得更容易:

SELECT 
  s.id, 
  s.Yes_No,
  COUNT(CASE WHEN s.Yes_No = 'Y' THEN 1 END) OVER(PARTITION BY s.id) as countYes,
  COUNT(CASE WHEN Yes_No = 'N' THEN 1 END) OVER(PARTITION BY s.id) as countNo
FROM
  Survey s

(在我开始写这篇文章时,Gordon 的查询正在使用条件聚合并折叠行;它已经被更改为或多或少相同的东西)

此方法的工作方式是使用一种将 Yes_No 值转换为 1 或 NULL 的情况。然后 Count 将 1 计为 1(它将任何非 null 计为 1)并将 null 计为 0。 over/partition by 子句导致按 id 重新开始计数。

SQL server、oracle、Postgres、MariaDB 10 和 mysql 8 支持这些。 SQLite 可能支持它。 mysql 的 Access 和原始版本不使用 - 对这些使用加入的分组总计形式

【讨论】:

    【解决方案3】:

    对窗口函数使用条件聚合:

    select id, Yes_No,
           sum(case when Yes_No = 'Y' then 1 else 0 end) over (partition by id) as yes_cnt,
           sum(case when Yes_No = 'N' then 1 else 0 end) over (partition by id) as no_cnt
    from Survey;
    

    【讨论】:

    • 执行此操作时出现错误。在这里看到了这个解决方案,它对我不起作用。你还能想到什么其他方法?
    • “我遇到错误”不会帮助我们帮助您解决该错误。在 SO 上发布时,请始终说出确切的错误消息,包括行号
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-09
    • 1970-01-01
    相关资源
    最近更新 更多