new*_*irl 7 postgresql dynamic-sql crosstab plpgsql postgresql-9.3
我已经看到有一些类似的问题已经退出,但是我还不了解如何自己编写代码。请记住,我只是该领域的初学者。
基本上我想像这样旋转表:
zoom | day | point zoom | 2015-10-01 | 2015-10-02 | ......
------+-----------+------- ---> ------+------------+-------------+
1 | 2015-10-01 | 201 1 | 201 | 685 |
2 | 2015-10-01 | 43 2 | 43 | 346 |
3 | 2015-10-01 | 80 3 | 80 | 534 |
4 | 2015-10-01 | 324 4 | 324 | 786 |
5 | 2015-10-01 | 25 5 | 25 | 685 |
1 | 2015-10-02 | 685
2 | 2015-10-02 | 346
3 | 2015-10-02 | 534
4 | 2015-10-02 | 555
5 | 2015-10-02 | 786
:
:
:
Run Code Online (Sandbox Code Playgroud)
时间会有所不同。
我得到的结果在左侧:
SELECT
zoom,
to_char(date_trunc('day', time), 'YYYY-MM-DD') AS day,
count(*) as point
FROM province
WHERE time >= '2015-05-01' AND time < '2015-06-01'
GROUP BY to_char(date_trunc('day', time), 'YYYY-MM-DD'), zoom;
Run Code Online (Sandbox Code Playgroud)
我已阅读,有一些问题,如果我使用count,也在于它会更好,如果我用CASE和GROUP BY,但是我不知道如何来CASE此。
Crosstab本身不支持动态创建列名,但是crosstab_hash如果我理解正确的话,可以使用来实现。
这可能是一个不错的解决方案:http ://okbob.blogspot.ca/2008/08/using-cursors-for-generating-cross.html,但是我坚持尝试自己编程。
我必须经常使用这种旋转,因此我会在其背后提供任何帮助和其他说明。
编辑1
我试图弄清楚交叉表如何与日期一起使用,当前不返回列的动态名称。稍后我将解释原因。这是针对主要问题的。对于此示例,我仅使用2个日期的期间。
基于@Erwin Brandstetter的答案:
SELECT * FROM crosstab(
'SELECT zoom, day, point
FROM province
ORDER BY 1, 2'
, $$VALUES ('2015-10-01'::date), ('2015-10-02')$$)
AS ct (zoom text, day1 int, day2 int);
Run Code Online (Sandbox Code Playgroud)
返回的结果是:
zoom | day1 | day2 |
-----+------------+-------------+
1 | 201 | 685 |
2 | 43 | 346 |
3 | 80 | 534 |
4 | 324 | 786 |
Run Code Online (Sandbox Code Playgroud)
我试图得到这个
zoom | 2015-10-01 | 2015-10-02 |
-----+------------+-------------+
1 | 201 | 685 |
2 | 43 | 346 |
3 | 80 | 534 |
4 | 324 | 786 |
Run Code Online (Sandbox Code Playgroud)
但我的查询不起作用:
SELECT *
FROM crosstab(
'SELECT *
FROM province
ORDER BY 1,2')
AS ct (zoom text, "2015-10-01" date, "2015-10-02" date);
ERROR: return and sql tuple descriptions are incompatible
Run Code Online (Sandbox Code Playgroud)
编辑1,Q1。为什么这不起作用,如何返回这样的结果?
我已阅读@Erwin Brandstetter提供给我的链接,尤其是以下链接:执行动态交叉表查询。我已经复制/粘贴了他的功能:
CREATE OR REPLACE FUNCTION pivottab(_tbl regclass,
_row text, _cat text,
_expr text,
_type regtype)
RETURNS text AS
$func$
DECLARE
_cat_list text;
_col_list text;
BEGIN
-- generate categories for xtab param and col definition list
EXECUTE format(
$$SELECT string_agg(quote_literal(x.cat), '), (')
, string_agg(quote_ident (x.cat), %L)
FROM (SELECT DISTINCT %I AS cat FROM %s ORDER BY 1) x$$
, ' ' || _type || ', ', _cat, _tbl)
INTO _cat_list, _col_list;
-- generate query string
RETURN format(
'SELECT * FROM crosstab(
$q$SELECT %I, %I, %s
FROM %I
GROUP BY 1, 2
ORDER BY 1, 2$q$
, $c$VALUES (%5$s)$c$
) ct(%1$I text, %6$s %7$s)'
, _row, _cat, _expr, _tbl, _cat_list, _col_list, _type
);
END
$func$ LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)
并用查询调用它
SELECT pivottab('province','zoom','day','point','date');
Run Code Online (Sandbox Code Playgroud)
函数返回了我:
pivottab
----------------------------------------------------------
SELECT * FROM crosstab( +
$q$SELECT zoom, day, point +
FROM province +
GROUP BY 1, 2 +
ORDER BY 1, 2$q$ +
, $c$VALUES ('2015-10-01'), ('2015-10-02')$c$ +
) ct(zoom text, "2015-10-01" date, "2015-10-02" date)
(1 row)
Run Code Online (Sandbox Code Playgroud)
因此,当我编辑查询并添加时;(那已经很好了;已经在那里)我得到了:
ERROR: column "province.point" must appear in the GROUP BY clause or be used in an aggregate function
Run Code Online (Sandbox Code Playgroud)
问题1,问题2。任何想法如何爱这个吗?
问题1,问题3。我想下一个问题将是如何自动执行功能,在同一链接上也提到了这一点,但是在前面的步骤中却遇到了麻烦。
您的示例的基本交叉表查询很简单:
SELECT * FROM crosstab(
'SELECT zoom, day, point
FROM province
ORDER BY 1, 2'
, $$VALUES ('2015-10-01'::date), ('2015-10-02')$$)
AS ct (zoom text, day1 int, day2 int);
Run Code Online (Sandbox Code Playgroud)
但不适用于动态列名或动态列数。作为折衷方案,您可以拥有固定数量的列,并且只填充前导列。基本:
crosstab_hash不会帮助您处理动态列名称。它可以重复使用而无需键入列定义列表,但不适用于动态列名称。例子:
对于真正的动态列名,您需要两次往返服务器。无论您是使用第一个查询检索列名来构建第二个查询,还是创建游标、临时表或准备好的语句。无论您尝试什么,都需要两次往返。SQL 希望在调用时知道返回类型。
我最接近的“动态”调用是使用crosstab_n()此相关答案中定义的自定义函数:
或者您放弃完全动态交叉表查询的想法(因为,您知道,这是不可能的)并使用两步工作流程,如上所述。
让函数生成交叉表查询文本。您可以使用此处提供的功能(并根据您的需要进行调整!):
特别是,删除GROUP BY 1, 2,因为您在交叉制表之前不聚合行。
执行生成的函数。
为了完整起见, Postgres 9.6 (刚刚发布)中\crosstabview的 psql 中也有新的元命令- 具有类似的功能,并且它可以显示动态列名称(附加动态名称发生在 psql 客户端中,而不是在 Postgres 服务器中)。
| 归档时间: |
|
| 查看次数: |
7692 次 |
| 最近记录: |