【问题标题】:MySQL column wise category counting [closed]MySQL按列分类计数[关闭]
【发布时间】:2012-09-03 21:36:05
【问题描述】:

我有一张这样的桌子:

id name center1    center2   cnter3
1  abc  baroda     bhopal    chennai
2  pqr  amhedabad  Surat     kolkata
3  nml  bhopal     chennai   Surat
4  fts  baroda     Surat     Baroda

我想要一个类似的结果:

         center1 center2  center3
Baroda     2       0        1   
Ahmedabad  1       0        0
bhopal     1       1        0
chennai    0       1        1
Kolkatta   0       0        1
Surat      0       2        1.

【问题讨论】:

标签: mysql sql


【解决方案1】:

我使用sqlfiddle 将表格的文本表示转换为一系列 CREATE TABLE 和 INSERT INTO 语句:

CREATE TABLE CenterCodes
    (`id` int, `name` varchar(3), `center1` varchar(9), `center2` varchar(7), `center3` varchar(7))
;

INSERT INTO CenterCodes
    (`id`, `name`, `center1`, `center2`, `center3`)
VALUES
    (1, 'abc', 'baroda', 'bhopal', 'chennai'),
    (2, 'pqr', 'amhedabad', 'Surat', 'kolkata'),
    (3, 'nml', 'bhopal', 'chennai', 'Surat'),
    (4, 'fts', 'baroda', 'Surat', 'Baroda')
;

尝试以下查询。内部 UNION 为每个字符串值生成多行,每组 3 列中的 2 列为 NULL。这些 NULL 然后被外部查询中的聚合 SUM()s 消除,将行集折叠为每个字符串值一行。

SELECT
  centername,
  SUM(CASE WHEN centername = center1 THEN 1 ELSE 0 END) AS center1,
  SUM(CASE WHEN centername = center2 THEN 1 ELSE 0 END) AS center2,
  SUM(CASE WHEN centername = center3 THEN 1 ELSE 0 END) AS center3
FROM (
  SELECT
    center1 AS centername,
    center1,
    NULL AS center2,
    NULL AS center3
  FROM CenterCodes
  UNION ALL
  SELECT
    center2 AS centername,
    NULL AS center1,
    center2,
    NULL AS center3
  FROM CenterCodes
  UNION ALL
  SELECT
    center3 AS centername,
    NULL AS center1,
    NULL AS center2,
    center3
  FROM CenterCodes
) AS Centers
GROUP BY centername;

【讨论】:

  • +1 棘手但有效的解决方案。
  • @MichaelBerkowski 我现在太累了,无法解释它为什么起作用。 NULL 技巧感觉特别模糊。我办公室的本地 SQL 大师教我这项技术,我很高兴在 SO 上尝试一下:)
  • 然后我将编辑它的工作原理。
  • 感谢您的编辑。这也很重要。我记得为什么我们使用空值而不是列值。如果将 center1 值包含在计算的 center1 中三次(每个联合查询的一组值),则 center1 的 sum 表达式返回的计数将是三倍。除了 NULL,您还可以使用 '' 作为占位符,或者您知道的任何值都不存在于基础数据中。
  • 对 - 聚合函数消除空值。
【解决方案2】:

这将需要一些子查询连接。首先,您需要从三列中获取所有不同的值,这将通过每列查询的UNION 来完成。

然后,该不同的列表必须针对三个子查询进行LEFT JOINed,这些子查询从三列中的每一列中提取每个值的计数。

最后,COALESCE() 将 NULL 替换为 0。

SELECT 
  allvalues.value,
  /* LEFT JOIN will result in NULL for non-existent values, so coalesce into 0 */
  COALESCE(c1.counts, 0) AS center1,
  COALESCE(c2.counts, 0) AS center2,
  COALESCE(c3.counts, 0) AS center3
FROM
  (
    /* UNIONs gets distinct vals from all columns */
    SELECT center1 AS value FROM yourtable
    UNION
    SELECT center2 AS value FROM yourtable
    UNION
    SELECT center3 AS value FROM yourtable
  ) AS allvalues
  /* LEFT JOIN the list of distinct possible values against a count per value for each column */
  LEFT JOIN (
    SELECT center1, COUNT(*) AS counts FROM yourtable GROUP BY center1
  ) c1 ON allvalues.value = c1.center1
  LEFT JOIN (
    SELECT center2, COUNT(*) AS counts FROM yourtable GROUP BY center2
  ) c2 ON allvalues.value = c2.center2
  LEFT JOIN (
    SELECT center3, COUNT(*) AS counts FROM yourtable GROUP BY center3
  ) c3 ON allvalues.value = c3.center3 

Here is a working demonstration,因为我想我今晚感觉特别慈善。

【讨论】:

  • +1 慈善?如果我发帖要 100 美元,我能指望你通过吗?
  • 使用与我的答案类似的联合技巧,但根据 sqlfiddle 执行计划的输出,连接使其变得更加复杂。尽管如此,我还是喜欢 COALESCE 的解释和使用。
  • @MichaelBerkowski 我通常不看支持率或声誉,只看问题的质量以及 OP 是否懒惰。
猜你喜欢
  • 2013-03-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多