如何旋转两列表格?
这可能是一个新手问题——我还在学习。我在 PostgreSQL 9.6 上使用以下查询:
SELECT locales, count(locales) FROM (
SELECT lower((regexp_matches(locale, '([a-z]{2,3}(-[a-z]{2,3})?)', 'i'))[1])
AS locales FROM users)
AS _ GROUP BY locales
我的查询返回以下动态行:
locales | count |
---|---|
en | 10 |
fr | 7 |
de | 3 |
n extra locales (~300)... | n-count |
我正在尝试旋转它以便区域设置值最终作为单行的列,如下所示:
en | fr | de | n extra locales (~300)... |
---|---|---|---|
10 | 7 | 3 | n-count |
我必须这样做才能很好地处理时间序列db/app
我尝试过使用 crosstab(),但所有示例都显示具有 3 列或更多列的更好定义的表。
我查看了使用 join
的示例,但我不知道如何动态地执行此操作。
This might be a novice question – I'm still learning. I'm on PostgreSQL 9.6 with the following query:
SELECT locales, count(locales) FROM (
SELECT lower((regexp_matches(locale, '([a-z]{2,3}(-[a-z]{2,3})?)', 'i'))[1])
AS locales FROM users)
AS _ GROUP BY locales
My query returns the following dynamic rows:
locales | count |
---|---|
en | 10 |
fr | 7 |
de | 3 |
n additional locales (~300)... | n-count |
I'm trying to rotate it so that locale values end up as columns with a single row, like this:
en | fr | de | n additional locales (~300)... |
---|---|---|---|
10 | 7 | 3 | n-count |
I'm having to do this to play nice with a time-series db/app
I've tried using crosstab()
, but all the examples show better defined tables with 3 or more columns.
I've looked at examples using join
, but I can't figure out how to do it dynamically.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
基本查询
在 Postgres 10 或更高版本中,您可以使用更简单、更快的
regexp_match()
而不是regexp_matches()
。 (因为无论如何,您只获取每行的第一个匹配项。)但是不必费心,可以使用更简单的substring()
来代替:比原始基本查询更简单、更快。
关于
GROUP BY
和ORDER BY
中的序数:细微差别:
regexp_matches()
不匹配则返回无行,而substring()
返回null
。我添加了一个WHERE
子句来消除先验不匹配 - 并允许索引支持(如果适用),但我不希望索引在这里提供帮助。请注意前缀
(?i)
,这是所谓的 "嵌入选项" 使用不区分大小写的匹配。添加了确定性
ORDER BY
子句。您需要它来实现简单的crosstab()
。另外:对于“en_US”等区域设置,您可能需要在模式中使用
_
而不是-
。尽管您可能会尝试
,但 SQL 不允许在单个查询中使用动态结果列。您需要两次往返服务器。看;
您可以 使用动态生成的
crosstab()
查询。基础知识:动态查询:
但是由于您生成单行纯整数值,我建议采用一种简单的方法:
生成以下形式的查询:
执行它以生成您的期望的结果。
在 psql 中,您可以将
\gexec
附加到生成的查询中,以将生成的 SQL 字符串立即反馈给服务器。请参阅:Base query
In Postgres 10 or later you could use the simpler and faster
regexp_match()
instead ofregexp_matches()
. (Since you only take the first match per row anyway.) But don't bother and use the even simplersubstring()
instead:Simpler and faster than your original base query.
About those ordinal numbers in
GROUP BY
andORDER BY
:Subtle difference:
regexp_matches()
returns no row for no match, whilesubstring()
returnsnull
. I added aWHERE
clause to eliminate non-matches a-priori - and allow index support if applicable, but I don't expect indexes to help here.Note the prefixed
(?i)
, that's a so-called "embedded option" to use case-insensitive matching.Added a deterministic
ORDER BY
clause. You'd need that for a simplecrosstab()
.Aside: you might need
_
in the pattern instead of-
for locales like "en_US".Pivot
Try as you might, SQL does not allow dynamic result columns in a single query. You need two round trips to the server. See;
You can use a dynamically generated
crosstab()
query. Basics:Dynamic query:
But since you generate a single row of plain integer values, I suggest a simple approach:
Generates a query of the form:
Execute it to produce your desired result.
In psql you can append
\gexec
to the generating query to feed the generated SQL string back to the server immediately. See: