如果您的数据库中没有可用的分析函数,我会计算几个子查询。我通常避免在选择列表中进行相关查询:
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 和原始版本不使用 - 对这些使用加入的分组总计形式