我做了一些研究,但似乎没有任何帮助我的个案
我有一张桌子(有40列和数百万行)
FirstName| LaseName | State |...100+ other columns|
aaa | bbb | CA
ccc | ddd | NY
abc | null | CA
null | ggg | AL
...150 million rows
我需要一个很长的查询来返回类似下面的内容
State | field | # of state pupulation | # of rows in state | % state population
__________________________________________________________________________
AL | firstName | 0 | 1 | 0%
| lastName | 1 | | 100%
__________________________________________________________________________
CA | firstName | 2 | 2 | 100%
| lastname | 1 | | 50%
__________________________________________________________________________
NY | firstName | 1 | 1 | 100%
| lastname | 1 | | 100%
这仅供内部使用,因此只要我能获得所需的数字,格式/顺序就不重要了
请注意,%是通过(状态= AL,CA等中的非空数#/状态= AL,CA等的总记录数)来计算的
而不是(非空的#/所有行的#)
我是sql的新手,我不知道该怎么做
答案 0 :(得分:0)
这是一种可能的查询模式。为了获得百分比,我们将选择列表中的第三个表达式除以第四个表达式。 (要在单个SELECT中执行此操作,我们必须重复这些表达式,由除法运算符分隔。
SELECT c.state
, f.field
, CASE f.field
WHEN 'firstname' THEN c.cnt_fn_nn
WHEN 'lastname' THEN c.cnt_ln_nn
WHEN 'somecol' THEN c.cnt_sc_nn
ELSE NULL
END AS `# populated`
, c.cnt_tot AS `# rows`
, CASE f.field
WHEN 'firstname' THEN c.cnt_fn_nn
WHEN 'lastname' THEN c.cnt_ln_nn
WHEN 'somecol' THEN c.cnt_sc_nn
ELSE NULL
END
/ c.cnt_tot * 100.0 AS `pct`
FROM ( SELECT 'firstname' AS `field`
UNION ALL SELECT 'lastname'
UNION ALL SELECT 'somecol'
) f
CROSS
JOIN ( SELECT a.state
, SUM(1) AS `cnt_tot`
, SUM(a.first_name IS NOT NULL) AS `cnt_fn_nn`
, SUM(a.last_name IS NOT NULL) AS `cnt_ln_nn`
, SUM(a.somecol IS NOT NULL) AS `cnt_sc_nn`
FROM atable a
GROUP BY a.state
) c
ORDER
BY c.state
, f.field
注意:
内联视图(派生表)f
返回我们要在第二列中显示的field
值。
内联视图(派生表)c
通过state
获取“计数”。
GROUP BY
子句会折叠state
具有相同值的所有行,因此我们会为state
的每个不同值返回一行。
对每一行计算表达式a.first_name IS NOT NULL
,作为布尔值,并为每一行返回FALSE(0)或TRUE(1)。我们可以使用SUM()
聚合函数来总计1和0。这使我们计算first_name的非null值的行数。
SUM(1)
会让我们和COUNT(*)
一样。这是每个state
的总行数。
我们对两个内联视图执行CROSS JOIN
操作,以生成笛卡尔(交叉)乘积。 f
的每一行都与c
的每一行匹配。如果我们有50个状态,来自c
的50行和来自f
的3行,则会得到总共50 * 3行。
搜索到的CASE
表达式是一种SQL语言...
if field = 'firstname' then return cnt_fn_nn
elsif field = 'lastname' then return cnt_ln_nn
...
我们使用它来“挑选”我们想要在每一行返回的计数,在firstname
字段的行上返回名字不为空的计数。
这可以扩展,使用somecol
复制行并将其替换为atable
中的有效列名,并为SELECT列表中的每个表达式分配唯一的列别名AS foo
此查询未向我们提供的是state
中未显示的任何atable
值。要获得零计数,我们需要state
的其他来源。
此查询不会抑制状态或# rows in state
的重复值。这些值在每一行都会返回,即使它们是重复的。
要让那些被压抑的人变得蠢,但我们可以做到。要在每个state
的“第一行”上获取它,我们需要知道哪个field
将是第一个。我们可以在外部查询的SELECT列表中的第一个和第四个表达式中进行条件测试。在开始使用它之前,首先使查询正常工作。 (重复值的抑制最好在处理结果的客户端中处理。但是如果规范要返回那个确切的结果集,那么就可以这样做......我很畏缩......)
SELECT IF(f.field='firstname',c.state,'') AS `state`
, f.field
, CASE f.field
WHEN 'firstname' THEN c.cnt_fn_nn
WHEN 'lastname' THEN c.cnt_ln_nn
WHEN 'somecol' THEN c.cnt_sc_nn
ELSE NULL
END AS `# populated`
, IF(f.field='firstname',c.cnt_tot,NULL) AS `# rows`