Bha*_*ani 2 database postgresql function dynamic
我有表数据
select * from tbltaxamount ;
id | taxname | taxinfoid | taxvalue | taxamt | zoneid | invoiceid | transid
----+-------------+-----------+----------+--------+--------+-----------+---------
1 | Service Tax | 0 | 0.00 | 28.69 | 2 | 119 | -1
2 | ABC Tax | 0 | 0.00 | 25.78 | 2 | 119 | -1
Run Code Online (Sandbox Code Playgroud)
现在,如何使用PostgreSQL的任何功能获得以下结果?
invoiceid | Service Tax | ABC Tax
----------+-------------+--------
119 | 28.69 | 25.78
Run Code Online (Sandbox Code Playgroud)
经过如此多的尝试后,我创建了以下函数来动态创建表格,它将显示如上所述的记录。
CREATE OR REPLACE FUNCTION taxamount() RETURNS void as $$
DECLARE
columnNames RECORD;
invoiceids RECORD;
BEGIN
FOR columnNames IN SELECT * from pg_tables where tablename = 'tmptable'
LOOP
DROP TABLE tmptable ;
END LOOP;
CREATE TABLE tmptable (invoiceid integer PRIMARY KEY);
FOR columnNames IN SELECT distinct(replace(taxname,' ','')) as taxnames from tbltaxamount
LOOP
EXECUTE 'ALTER TABLE tmptable ADD ' || columnNames.taxnames || ' numeric(9,2) DEFAULT 0';
END LOOP;
FOR invoiceids IN SELECT distinct(invoiceid) from tbltaxamount
LOOP
EXECUTE 'INSERT INTO tmptable (invoiceid) VALUES (' || invoiceids.invoiceid || ')';
END LOOP;
FOR invoiceids IN SELECT * from tbltaxamount
LOOP
EXECUTE 'UPDATE tmptable SET ' || replace(invoiceids.taxname,' ','') || ' = ' || invoiceids.taxamt || ' WHERE invoiceid = ' || invoiceids.invoiceid;
END LOOP ;
RETURN;
END;
$$ LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)
Your solution is a viable way. I largely rewrote your plpgsql function for simplification / performance / readability / security.
CREATE OR REPLACE FUNCTION f_taxamount()
RETURNS void AS
$BODY$
DECLARE
rec record;
BEGIN
DROP TABLE IF EXISTS tmptable;
EXECUTE 'CREATE TABLE tmptable (invoiceid integer PRIMARY KEY, '
|| (
SELECT string_agg(col || ' numeric(9,2) DEFAULT 0', ', ')
FROM (
SELECT quote_ident(lower(replace(taxname,' ','_'))) AS col
FROM tbltaxamount
GROUP BY 1
ORDER BY 1
) x
)
|| ')';
EXECUTE '
INSERT INTO tmptable (invoiceid)
SELECT DISTINCT invoiceid FROM tbltaxamount';
FOR rec IN
SELECT taxname, taxamt, invoiceid FROM tbltaxamount ORDER BY invoiceid
LOOP
EXECUTE '
UPDATE tmptable
SET ' || quote_ident(lower(replace(rec.taxname,' ','_')))
|| ' = '|| rec.taxamt || '
WHERE invoiceid = ' || rec.invoiceid;
END LOOP;
END;
$BODY$ LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)
This works for PostgreSQL 9.1 or later.
For pg 8.4 or later replace
SELECT string_agg(col || ' numeric(9,2) DEFAULT 0', ', ')
Run Code Online (Sandbox Code Playgroud)
with:
SELECT array_to_string(array_agg(col || ' numeric(9,2) DEFAULT 0'), ', ')
Run Code Online (Sandbox Code Playgroud)
For versions even older than that create an aggregate function like this:
CREATE OR REPLACE FUNCTION f_concat_comma(text, text)
RETURNS text AS
$BODY$
BEGIN
RETURN ($1 || ', '::text) || $2;
END;
$BODY$
LANGUAGE plpgsql IMMUTABLE;
CREATE AGGREGATE concat_comma(text) (
SFUNC=f_concat_comma,
STYPE=text
);
Run Code Online (Sandbox Code Playgroud)
And then write:
SELECT concat_comma(col || ' numeric(9,2) DEFAULT 0')
Run Code Online (Sandbox Code Playgroud)
Also:
DROP TABLE IF EXISTS tmptable;
Run Code Online (Sandbox Code Playgroud)
The clause "IF EXISTS" was introduced with version 8.2.
If you should use a version even older than that you should you can:
IF EXISTS (
SELECT *
FROM pg_catalog.pg_class
WHERE oid = 'tmptable'::regclass
AND relkind = 'r')
THEN
DROP TABLE tmptable;
END IF;
*/
Run Code Online (Sandbox Code Playgroud)
看一下PostgreSQL项目的版本控制策略。版本8.0.1是一个特别有问题的版本。我强烈建议您升级。如果您不能升级到较新的主版本,则出于安全原因,至少应升级到最新的点发行版(以您的情况为8.0.26)。这可以就地完成,而无需进行其他任何更改。
| 归档时间: |
|
| 查看次数: |
13749 次 |
| 最近记录: |