【发布时间】:2017-02-08 08:04:11
【问题描述】:
我已经看到有一些类似的问题像这个一样,但我还没有理解如何自己编写代码。请记住,我只是这个领域的初学者。
基本上我想像这样旋转表格:
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
:
:
:
时间可能会有所不同。
我得到的左侧结果:
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;
我读到如果我使用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);
返回的结果是:
zoom | day1 | day2 |
-----+------------+-------------+
1 | 201 | 685 |
2 | 43 | 346 |
3 | 80 | 534 |
4 | 324 | 786 |
我正在努力解决这个问题
zoom | 2015-10-01 | 2015-10-02 |
-----+------------+-------------+
1 | 201 | 685 |
2 | 43 | 346 |
3 | 80 | 534 |
4 | 324 | 786 |
但我的查询不起作用:
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
Edit1,Q1。为什么这不起作用,我怎样才能返回这样的结果?
我已经阅读了@Erwin Brandstetter 提供给我的链接,尤其是这个:Execute a dynamic crosstab query。我已经复制/粘贴了他的功能:
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;
并通过查询调用它
SELECT pivottab('province','zoom','day','point','date');
函数返回给我:
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)
所以当我编辑查询并添加时; (如果 ; 已经在那里就好了)我得到了:
ERROR: column "province.point" must appear in the GROUP BY clause or be used in an aggregate function
Edit1,Q2。任何想法如何解决这个问题?
Edit1,Q3。我想下一个问题将是如何自动执行函数,在同一个链接上也提到过,但是卡在前面的步骤上。
【问题讨论】:
-
通过循环记录并附加到支持查询的字符串来构建动态 SQL。这可以使用
plpgsql来实现。然后从函数中返回一个表,你就可以开始了:-) -
什么应该是动态的?结果列数?结果列的名称或数据类型?
-
@ErwinBrandstetter 抱歉,我刚刚在表格中添加了点。所以我需要动态添加列的名称......它就像 2015-10-01, 2015-10-02, 2015-10-03, 2015-10-04 ......取决于首先的 WHERE 部分询问。这应该是在不手动列出它们的情况下生成的,因为有时我可能有 75 天的间隔
标签: postgresql plpgsql dynamic-sql postgresql-9.3 crosstab