2017-03-08 56 views
0

我有一些数据(约70,000行),它与下面的格式类似。在MySQL中一次总结多个列

+-----------+-----+-----+----+-----------+ 
| ID  | A | B | C | Whatever | 
+-----------+-----+-----+----+-----------+ 
| 1banana | 42 | 0 | 2 | Um  | 
| fhqwhgads | 514 | 6 | 9 | Nevermind | 
| 2banana | 69 | 42 | 0 | NULL  | 
| pears  | 18 | 96 | 2 | 8.8  | 
| zubat2 | 96 | 2 | 14 | "NULL" | 
+-----------+-----+-----+----+-----------+ 

我要作出这样的计算有多少次出现在任何三列的每一个数字,如输出表:

+--------+---------+---------+---------+-----+ 
| Number | A count | B count | C count | sum | 
+--------+---------+---------+---------+-----+ 
|  0 |  0 |  1 |  1 | 2 | 
|  2 |  0 |  1 |  2 | 3 | 
|  6 |  0 |  1 |  0 | 1 | 
|  9 |  0 |  0 |  1 | 1 | 
|  14 |  0 |  0 |  1 | 1 | 
|  18 |  1 |  0 |  0 | 1 | 
|  42 |  1 |  1 |  0 | 2 | 
|  69 |  1 |  0 |  0 | 1 | 
|  96 |  1 |  1 |  0 | 2 | 
| 514 |  1 |  0 |  0 | 1 | 
+--------+---------+---------+---------+-----+ 

(在我的现实世界中使用,就不会有在输入表中的行数至少是查询结果中的10倍)

查询是否返回这些3列中不在任何位置的数字的行不是那么重要,缺少一个明显的总和列(虽然我的偏好是它有确实的总和列和不包括任何列中的数字)。


目前,我使用下面的查询,以获得不分组数据:

SELECT * #Number, COUNT(DISTINCT A), COUNT(DISTINCT B), COUNT(DISTINCT C) 
FROM 
    (# Generate a list of numbers to try 
    SELECT @ROW := @ROW + 1 AS `Number` 
    FROM DataTable t 
    join (SELECT @ROW := -9) t2 
    LIMIT 777 # None of the numbers I am interested in should be greater than this 
    ) AS NumberList 
INNER JOIN DataTable ON 
    Number = A 
    OR Number = B 
    OR Number = C 
    #WHERE <filters on DataTable columns to speed things up> 
#WHERE NUMBER = 10 # speed things up 
#GROUP BY Number 

与保持原样返回类似数据表的代码注释的部分上面的查询表,但按照它匹配的条目的数量排序。我想将所有行以相同的Number开头,并将查询结果的“数据”列中的值作为Number发生在DataTable对应列中的次数。

当我取消分组报表(并删除从SELECT声明*),我能得到多少行,每行Number出现在(为所需的输出sum列有用)的计数。但是,它并没有给出我在Number匹配每个数据列的次数的实际总和:我只获得发现Number的行数的三个副本。 如何获得按每个实际列的分组而不是匹配行的总数


此外,你可能已经注意到,我有一些关于加快速度的评论。这个查询是slow,所以我添加了一对过滤器,所以测试运行速度更快。我非常希望能够使其运行速度更快,以便将查询结果从完整集发送到新表并不是重新使用此数据的唯一合理方式,因为我希望能够由于非性能原因,请使用DataTable上的过滤器。 有没有更好的方式来构建整个查询,以便运行速度更快?

回答

2

我想你想使用union all,然后聚集到逆透视:

select number, sum(a) as a, sum(b) as b, sum(c) as c, count(*) as `sum` 
from ((select a as number, 1 as a, 0 as b, 0 as c from t 
    ) union all 
     (select b, 0 as a, 1 as b, 0 as c from t 
    ) union all 
     (select c, 0 as a, 0 as b, 1 as c from t 
    ) 
    ) abc 
group by number 
order by number; 
+0

这个工程相当不错!它看起来像我需要包括我预先从't'过滤三次的任何列,但是我可以在分组和排序之上使用'WHERE'过滤器。有没有办法为有限但未知数量的列做到这一点,或者如果我遇到这种情况,非SQL数据库(可能是三维数据库)是否是一个更好的工具? – cjm