【发布时间】:2012-05-10 16:07:54
【问题描述】:
我想要实现的目标很简单,但是有点难以解释,我不知道它是否真的可以在 postgres 中实现。我处于相当基本的水平。 SELECT, FROM, WHERE, LEFT JOIN ON, HAVING,等等基本的东西。
我正在尝试计算包含特定字母/数字的行数,并根据字母/数字显示该计数。
即有多少行包含“a/A”(不区分大小写)的条目
我要查询的表是电影名称列表。我要做的就是对“a-z”和“0-9”进行分组和计数,然后输出总数。我可以按顺序运行 36 个查询:
SELECT filmname FROM films WHERE filmname ilike '%a%'
SELECT filmname FROM films WHERE filmname ilike '%b%'
SELECT filmname FROM films WHERE filmname ilike '%c%'
然后在结果上运行 pg_num_rows 以找到我需要的数字,依此类推。
我知道喜欢是多么强烈,而且我更喜欢,所以我宁愿避免这种情况。尽管数据(如下)在数据中有大写和小写,但我希望结果集不区分大小写。即“盯着山羊的男人” a/A、t/T 和 s/S 不会对结果集计算两次。如果它使查询更简单或更易于构造,我可以将表复制到辅助工作表,所有数据都在 strtolower 并处理该组数据以进行查询。
另一种可能是 SELECT sum(length(regexp_replace(filmname, '[^X|^x]', '', 'g'))) FROM films;
对于每个字母组合,但又是 36 个查询、36 个数据集,我希望能在单个查询中获取数据。
这是我的一组 14 部电影的简短数据集(实际上包含 275 行)
District 9
Surrogates
The Invention Of Lying
Pandorum
UP
The Soloist
Cloudy With A Chance Of Meatballs
The Imaginarium of Doctor Parnassus
Cirque du Freak: The Vampires Assistant
Zombieland
9
The Men Who Stare At Goats
A Christmas Carol
Paranormal Activity
如果我手动将每个字母和数字排列在一列中,然后通过在该列中给它一个 x 来注册该字母是否出现在电影标题中,然后将它们计数以产生总数,我会在下面得到这样的结果. x 的每个垂直列都是该电影名称中的字母列表,无论该字母出现多少次或大小写。
上述短集的结果是:
A x x xxxx xxx 9
B x x 2
C x xxx xx 6
D x x xxxx 6
E xx xxxxx x 8
F x xxx 4
G xx x x 4
H x xxxx xx 7
I x x xxxxx xx 9
J 0
K x 0
L x xx x xx 6
M x xxxx xxx 8
N xx xxxx x x 8
O xxx xxx x xxx 10
P xx xx x 5
Q x 1
R xx x xx xxx 7
S xx xxxx xx 8
T xxx xxxx xxx 10
U x xx xxx 6
V x x x 3
W x x 2
X 0
Y x x x 3
Z x 1
0 0
1 0
2 0
3 0
4 0
5 0
6 0
7 0
8 0
9 x x 1
在上面的例子中,每一列都是一个“电影名” 正如你所看到的,第 5 列只标记了一个“u”和一个“p”,而第 11 列只标记了一个“9”。最后一列是每个字母的计数。
我想以某种方式构建一个查询,以某种方式为我提供结果行:A 9、B 2、C 6、D 6、E 8 等,同时考虑到从我的电影列中提取的每个行条目。如果该字母没有出现在任何行中,我想要一个零。
我不知道这是否可能,或者是否在 php 中系统地进行 36 个查询是唯一的可能性。
在当前数据集中有 275 个条目,并且每月增长约 8.33 个(每年 100 个)。我预测到 2019 年它将达到大约 1000 行,届时我无疑将使用一个完全不同的系统,因此我无需担心使用庞大的数据集进行拖网。
目前最长的标题是 50 个字符的“Percy Jackson & the Olympians: The Lightning Thief”(是的,我知道这部电影很烂;-),最短的是 1,“9”。
我正在运行 9.0.0 版的 Postgres。
抱歉,如果我以多种方式多次说过同一件事,我会尽量提供尽可能多的信息,以便您知道我想要达到的目标。
如果您需要任何说明或更大的数据集进行测试,请直接询问,我会根据需要进行编辑。
非常欢迎提出建议。
编辑 1
Erwin 感谢您的编辑/标签/建议。全部同意。
修复了 Erwin 建议的缺失的“9”错字。我的手动转录错误。
kgrittn,感谢您的建议,但我无法从 9.0.0 更新版本。我已询问我的提供商是否会尝试更新。
回应
感谢您的出色回复欧文
对于延迟回复深表歉意,但我一直在努力让您的查询正常工作并学习新关键字以理解您创建的查询。
我调整了查询以适应我的表结构,但结果集与预期不符(全为零),因此我直接复制了您的行并得到了相同的结果。
虽然两种情况下的结果集都列出了所有 36 行并带有适当的字母/数字,但所有行都显示为零作为计数 (ct)。
我试图解构查询以查看它可能在哪里崩溃。
的结果
SELECT DISTINCT id, unnest(string_to_array(lower(film), NULL)) AS letter
FROM films
是“未找到行”。也许从更广泛的查询中提取它应该是,我不确定。
当我删除 unnest 函数时,结果是 14 行都带有“NULL”
如果我调整功能
COALESCE(y.ct, 0) to COALESCE(y.ct, 4)<br />
然后我的数据集对每个字母都以 4 来响应,而不是前面解释的零。
在 COALESCE 上简要阅读了“4”作为替代值,我猜测 y.ct 是 NULL 并被第二个值替换(这是为了覆盖序列中字母不匹配的行,即如果没有电影包含“q”,那么“q”列将具有零值而不是 NULL?)
我尝试使用的数据库是 SQL_ASCII,我想知道这是否是个问题,但我在一个运行 UTF-8 的 8.4.0 版本上得到了相同的结果。
如果我犯了一个明显的错误,但我无法返回我需要的数据集,我们深表歉意。
有什么想法吗?
再次感谢您的详细回复和解释。
【问题讨论】:
-
你的结果表明显错了,'9'出现在两部电影中,但只有一个被标记为'x'。
-
@George:请阅读此页面,然后更新到更新的错误修复级别 9.0:postgresql.org/support/versioning
标签: sql postgresql count aggregate-functions