I am having difficulties writing a Postgres function, as I am not familiar with it. I have multiple tables to import into Postgres with this format:
id | 1960 | 1961 | 1962 | 1963 | ...
____________________________________
1 23 45 87 99
2 12 31 ...
which I need to convert into this format:
id | year | value
_________________
1 1960 23
1 1961 45
1 1962 87
...
2 1960 12
2 1961 31
...
I would imagine the function too to read like this:
SELECT all-years FROM imported_table;
CREATE a new_table;
FROM min-year TO max-year LOOP
EXECUTE "INSERT INTO new_table (id, year, value) VALUES (id, year, value)";
END LOOP;
However, I'm having real trouble writing the nitty-gritty details for this. Would be easier for me to do that in PHP, but I am convinced that it's cleaner to do it directly in a Postgres-function.
The years (start and end) vary from table to table. And sometimes, I can even have years only for every fifth year or so ...
5条答案
按热度按时间zvokhttg1#
PostgreSQL 9.3
提供了简洁的JSON functions,它可以用于这样的任务,而不需要定义新的函数或知道列的数量。http://sqlfiddle.com/#!15/1714b/13
cwtwac6a2#
并行取消嵌套可能更容易
9rbhqvlz3#
A completely dynamic version requires dynamic SQL. Use a plpgsql function with
EXECUTE
:For Postgres 9.2 or older (before
LATERAL
was implemented):For Postgres 9.3 or later (with
LATERAL
):About
VARIADIC
:Call for arbitrary years:
Same, passing an actual array:
For a long list of sequential years:
For a long list with regular intervals (example for every 5 years):
Output as requested.
The function takes:
'"CaMeL"'
). Using the object identifier typeregclass
to assert correctness and defend against SQL injection. You may want to schema-qualify the tale name to be unambiguous (like'public."CaMeL"'
). More:Or an actual array, prefixed with the keyword
VARIADIC
.The array of columns does not have to be sorted in any way, but table and columns must exist or an exception is raised.
Output is sorted by
id
andyear
(asinteger
). If you want years to be sorted according to the sort order of the input array, make it justORDER BY 1
. Sort order according to array is not strictly guaranteed, but works in the current implementation. More about that:Also works for
NULL
values.SQL Fiddle for both with examples.
References:
sq1bmfud4#
The simplest way is a
union all
:A somewhat more sophisticated way would be:
You can put this into another table using
insert
orcreate table as
.tez616oj5#
Here's a way that's based on the method at https://blog.sql-workbench.eu/post/dynamic-unpivot/ and another answer to this question , but uses the hstore extension
It has a few benefits over other solutions: