I need to change one table datatype same as other in netezza, by just passing table name? - sql

I have one table named L0 which is created as:
create table L0 (
name varchar,
number varchar,
address varchar
);
The data type for all the columns present in L0 is varchar,
I have another table L1 which is created as:
create table L1 (
name varchar,
number int,
address char
);
I want to convert the data types of L0 table to be same as L1 table, by just passing the table name.
I want the final query look like this:
select cast(name as varchar), cast(number as int), cast(address as char) from L0
minus
select * from L1:
What is the way to do it?

If you have group_concat UDA installed in Netezza then you can get the desired output using columns metadata view
create table L0 (
name varchar(20),
number varchar(10),
address varchar(50)
);
create table L1 (
name varchar(50),
number int,
address char(20)
);
Query :
SELECT 'select ' || system..group_concat('cast (' || a.column_name || ' as ' || b.data_type || ')') || ' from ' || a.table_name || ' minus select ' || system..group_concat(b.column_name) || ' from ' || b.table_name || ' ;'
FROM columns a
,columns b
WHERE a.column_name = b.column_name
AND a.table_name = 'L0'
AND b.table_name = 'L1'
AND a.table_catalog = 'TEST' --- this is the current database name
GROUP BY a.table_name
,b.table_name;
Output:
SELECT cast(ADDRESS AS CHARACTER(20))
,cast(NAME AS CHARACTER VARYING(50))
,cast(NUMBER AS INTEGER)
FROM L0 minus
SELECT ADDRESS
,NAME
,NUMBER
FROM L1;
EDIT:
Alternate approach using stored procedure
CREATE OR REPLACE PROCEDURE GRP_CONCAT(varchar(50),varchar(50))
RETURNS VARCHAR(ANY)
EXECUTE AS OWNER
LANGUAGE NZPLSQL AS
BEGIN_PROC
DECLARE
TABLE_NAME1 ALIAS FOR $1;
TABLE_NAME2 ALIAS for $2;
return_text varchar(10000) := 'SELECT';
x record;
BEGIN
FOR x IN select a.column_name as colname,b.data_type datatype
FROM columns a
,columns b
WHERE a.column_name = b.column_name
AND a.table_name = TABLE_NAME1
AND b.table_name = TABLE_NAME2
order by b.ordinal_position
LOOP
return_text := return_text || ' CAST ('||x.colname ||' as '||x.datatype||') , ';
end loop;
return_text := trim(return_text,' , ')||' FROM '||TABLE_NAME1 || ' minus select * from '||TABLE_NAME2||';';
return return_text;
EXCEPTION WHEN OTHERS THEN
RAISE NOTICE 'ERROR: %', SQLERRM;
RETURN 1;
END;
END_PROC;
Output :
Call GRP_CONCAT('L0','L1') ;
SELECT CAST(NAME AS CHARACTER VARYING(50))
,CAST(NUMBER AS INTEGER)
,CAST(ADDRESS AS CHARACTER(20))
FROM L0 minus
SELECT *
FROM L1;

Related

Oracle insert data from another table without column names

I have two tables. They differ only columns order.
First
Table1
(
name,
surname,
age
)
Second
Table2
(
age
surname,
name
)
I want insert data to Table2 from Table1.
If tables column order is the same I can use
insert into Table2
select * from Table1
I know that I can solve this problem with
insert into table2
select age,surname,name from table1
But I don't use it because there are many column in my real table.
is there good idea for it?
The only way is with some dynamic SQL, by relying on column names; for example, say you have the tables
CREATE TABLE Table1
(
name VARCHAR2(100),
surname VARCHAR2(100),
age NUMBER
);
CREATE TABLE Table2
(
name VARCHAR2(100),
age NUMBER,
oneMoreColumn NUMBER,
surname VARCHAR2(100)
);
you can do:
declare
vSQL varchar2(1000);
vCols varchar2(1000);
begin
select listagg(tc1.column_name, ', ') within group (order by tc1.column_name)
into vCols
from user_tab_columns tc1
inner join user_tab_columns tc2
on(tc1.column_name = tc2.column_name)
where tc1.table_name = 'TABLE1'
and tc2.table_name = 'TABLE2';
--
vSQL := 'insert into table2( ' || vCols || ') select ' || vCols || ' from table1';
--
dbms_output.put_line(vSQL);
--
execute immediate vSQL;
end;
this will build and execute the statement:
insert into table2( AGE, NAME, SURNAME) select AGE, NAME, SURNAME from table1
you can do like this
create table EX_EMPLOYEE
(
NAME VARCHAR2(100),
PATH VARCHAR2(1000)
)
SET serveroutput ON size 2000
/
declare T_COL varchar2(50);
CURSOR c1 IS SELECT column_name name FROM user_tab_cols where table_name='EX_EMPLOYEE';
BEGIN
FOR rec IN c1 LOOP
if T_COL is null then
T_COL := T_COL || rec.name;
else
T_COL := T_COL ||' ,' || rec.name;
end if;
END LOOP;
dbms_output.put_line('select '|| T_COL ||' FROM EX_EMPLOYEE');
END;
/
select NAME ,PATH FROM EX_EMPLOYEE
PL/SQL procedure successfully completed
you could do something like this:
create table new_table as
select * from old_table

Oracle get table names based on column value

I have table like this:
Table-1
Table-2
Table-3
Table-4
Table-5
each table is having many columns and one of the column name is employee_id.
Now, I want to write a query which will
1) return all the tables which is having this columns and
2) results should show the tables if the column is having values or empty values by passing employee_id.
e.g. show table name, column name from Table-1, Table-2,Table-3,... where employee_id='1234'.
If one of the table doesn't have this column, then it is not required to show.
I have verified with link, but it shows only table name and column name and not by passing some column values to it.
Also verified this, but here verifies from entire schema which I dont want to do it.
UPDATE:
Found a solution, but by using xmlsequence which is deprecated,
1)how do I make this code as xmltable?
2) If there are no values in the table, then output should have empty/null. or default as "YES" value
WITH char_cols AS
(SELECT /*+materialize */ table_name, column_name
FROM cols
WHERE data_type IN ('CHAR', 'VARCHAR2') and table_name in ('Table-1','Table-2','Table-3','Table-4','Table-5'))
SELECT DISTINCT SUBSTR (:val, 1, 11) "Employee_ID",
SUBSTR (table_name, 1, 14) "Table",
SUBSTR (column_name, 1, 14) "Column"
FROM char_cols,
TABLE (xmlsequence (dbms_xmlgen.getxmltype ('select "'
|| column_name
|| '" from "'
|| table_name
|| '" where upper("'
|| column_name
|| '") like upper(''%'
|| :val
|| '%'')' ).extract ('ROWSET/ROW/*') ) ) t ORDER BY "Table"
/
This query can be done in one step using the (non-deprecated) XMLTABLE.
Sample Schema
--Table-1 and Table-2 match the criteria.
--Table-3 has the right column but not the right value.
--Table-4 does not have the right column.
create table "Table-1" as select '1234' employee_id from dual;
create table "Table-2" as select '1234' employee_id from dual;
create table "Table-3" as select '4321' employee_id from dual;
create table "Table-4" as select 1 id from dual;
Query
--All tables with the column EMPLOYEE_ID, and the number of rows where EMPLOYEE_ID = '1234'.
select table_name, total
from
(
--Get XML results of dynamic query on relevant tables and columns.
select
dbms_xmlgen.getXMLType(
(
--Create a SELECT statement on each table, UNION ALL'ed together.
select listagg(
'select '''||table_name||''' table_name, count(*) total
from "'||table_name||'" where employee_id = ''1234'''
,' union all'||chr(10)) within group (order by table_name) v_sql
from user_tab_columns
where column_name = 'EMPLOYEE_ID'
)
) xml
from dual
) x
cross join
--Convert the XML data to relational.
xmltable('/ROWSET/ROW'
passing x.xml
columns
table_name varchar2(128) path 'TABLE_NAME',
total number path 'TOTAL'
);
Results
TABLE_NAME TOTAL
---------- -----
Table-1 1
Table-2 1
Table-3 0
Just try to use code below.
Pay your attention that may be nessecery clarify scheme name in loop.
This code works for my local db.
set serveroutput on;
DECLARE
ex_query VARCHAR(300);
num NUMBER;
emp_id number;
BEGIN
emp_id := <put your value>;
FOR rec IN
(SELECT table_name
FROM all_tab_columns
WHERE column_name LIKE upper('employee_id')
)
LOOP
num :=0;
ex_query := 'select count(*) from ' || rec.table_name || ' where employee_id = ' || emp_id;
EXECUTE IMMEDIATE ex_query into num;
if (num>0) then
DBMS_OUTPUT.PUT_LINE(rec.table_name);
end if;
END LOOP;
END;
I tried with the xml thing, but I get an error I cannot solve. Something about a zero size result. How difficult is it to solve this instead of raising exception?! Ask Oracle.
Anyway.
What you can do is use the COLS table to know what table has the employee_id column.
1) what table from table TABLE_LIKE_THIS (I assume column with table names is C) has this column?
select *
from COLS, TABLE_LIKE_THIS t
where cols.table_name = t
and cols.column_name = 'EMPLOYEE_ID'
-- think Oracle metadata/ think upper case
2) Which one has the value you are looking for: write a little chunk of Dynamic PL/SQL with EXECUTE IMMEDIATE to count the tables matching above condition
declare
v_id varchar2(10) := 'JP1829'; -- value you are looking for
v_col varchar2(20) := 'EMPLOYEE_ID'; -- column
n_c number := 0;
begin
for x in (
select table_name
from all_tab_columns cols
, TABLE_LIKE_THIS t
where cols.table_name = t.c
and cols.column_name = v_col
) loop
EXECUTE IMMEDIATE
'select count(1) from '||x.table_name
||' where Nvl('||v_col||', ''##'') = ''' ||v_id||'''' -- adding quotes around string is a little specific
INTO n_c;
if n_c > 0 then
dbms_output.put_line(n_C|| ' in ' ||x.table_name||' has '||v_col||'='||v_id);
end if;
-- idem for null values
-- ... ||' where '||v_col||' is null '
-- or
-- ... ||' where Nvl('||v_col||', ''##'') = ''##'' '
end loop;
dbms_output.put_line('done.');
end;
/
Hope this helps

postgres: find all integer columns with its current max value in it

How to find all integer typed primary key columns with its current max value in it from all tables from all databases in Postgres instance?
I want to find all the int typed primary key columns from all tables which are nearing to overflow its max value 2147483647.
CREATE OR REPLACE FUNCTION intpkmax() RETURNS
TABLE(schema_name name, table_name name, column_name name, max_value integer)
LANGUAGE plpgsql STABLE AS
$$BEGIN
/* loop through tables with a simgle integer column as primary key */
FOR schema_name, table_name, column_name IN
SELECT sch.nspname, tab.relname, col.attname
FROM pg_class tab
JOIN pg_constraint con ON con.conrelid = tab.oid
JOIN pg_attribute col ON col.attrelid = tab.oid
JOIN pg_namespace sch ON sch.oid = tab.relnamespace
WHERE con.contype = 'p'
AND array_length(con.conkey, 1) = 1
AND col.atttypid = 'integer'::regtype
AND NOT col.attisdropped
LOOP
/* get the maximum value of the primary key column */
EXECUTE 'SELECT max(' || quote_ident(column_name) ||
') FROM ' || quote_ident(schema_name) ||
'.' || quote_ident(table_name) || ''
INTO max_value;
/* return the next result */
RETURN NEXT;
END LOOP;
END;$$;
Then you can get a list with
SELECT * FROM intpkmax();

A more efficient way to do a select insert that involves over 300 columns?

I am trying to find a more efficient way to write PL/SQL Query to
to select insert from a table with 300+ columns, to the back up version of that table (same column names + 2 extra columns).
I could simply type out all the column names in the script (example below), but with that many names, it will bother me... :(
INSERT INTO
TABLE_TEMP
(column1, column2, column3, etc)
(SELECT column1, column2, column3, etc FROM TABLE WHERE id = USER_ID);
Thanks in advance
Specify literals/null for those two extra columns.
INSERT INTO
TABLE_TEMP
SELECT t1.*, null, null FROM TABLE t1 WHERE id = USER_ID
You can pretty easily build a column list for any given table:
select table_catalog
,table_schema
,table_name
,string_agg(column_name, ', ' order by ordinal_position)
from information_schema.columns
where table_catalog = 'catalog_name'
and table_schema = 'schema_name'
and table_name = 'table_name'
group by table_catalog
,table_schema
,table_name
That should get you nearly where you need to be.
The question tag says plsql, which is Oracle or one of its variants. Here is an example of doing it in Oracle:
drop table brianl.deleteme1;
drop table brianl.deleteme2;
CREATE TABLE brianl.deleteme1
(
a INTEGER
, b INTEGER
, c INTEGER
, efg INTEGER
);
CREATE TABLE brianl.deleteme2
(
b INTEGER
, c INTEGER
, d INTEGER
, efg INTEGER
);
DECLARE
l_ownerfrom VARCHAR2 (30) := 'BRIANL';
l_tablefrom VARCHAR2 (30) := 'DELETEME1';
l_ownerto VARCHAR2 (30) := 'BRIANL';
l_tableto VARCHAR2 (30) := 'DELETEME2';
l_comma VARCHAR2 (1) := NULL;
BEGIN
DBMS_OUTPUT.put_line ('insert into ' || l_ownerto || '.' || l_tableto || '(');
FOR eachrec IN ( SELECT f.column_name
FROM all_tab_cols f INNER JOIN all_tab_cols t ON (f.column_name = t.column_name)
WHERE f.owner = l_ownerfrom
AND f.table_name = l_tablefrom
AND t.owner = l_ownerto
AND t.table_name = l_tableto
ORDER BY f.column_name)
LOOP
DBMS_OUTPUT.put_line (l_comma || eachrec.column_name);
l_comma := ',';
END LOOP;
DBMS_OUTPUT.put_line (') select ');
l_comma := NULL;
FOR eachrec IN ( SELECT f.column_name
FROM all_tab_cols f INNER JOIN all_tab_cols t ON (f.column_name = t.column_name)
WHERE f.owner = l_ownerfrom
AND f.table_name = l_tablefrom
AND t.owner = l_ownerto
AND t.table_name = l_tableto
ORDER BY f.column_name)
LOOP
DBMS_OUTPUT.put_line (l_comma || eachrec.column_name);
l_comma := ',';
END LOOP;
DBMS_OUTPUT.put_line (' from ' || l_ownerfrom || '.' || l_tablefrom || ';');
END;
This results in this output:
insert into BRIANL.DELETEME2(
B
,C
,EFG
) select
B
,C
,EFG
from BRIANL.DELETEME1;
Nicely formatted:
INSERT INTO brianl.deleteme2 (b, c, efg)
SELECT b, c, efg
FROM brianl.deleteme1;

Postgres dynamic column headers (from another table)

Just a silly example:
Table A:
eggs
bread
cheese
Table B (when they are eaten):
Egg | date
Bread | date
Egg | date
cheese | date
Bread | date
For statistics purpouses, i need to have statistics per date per food type in a look like this:
Table Statistics:
egg | bread | cheese
date1 2 1 0
date2 6 4 2
date3 2 0 0
I need the column headers to be dynamic in the report (if new ones are added, it should automatically appear).
Any idea how to make this in postgres?
Thanks.
based on answer Postgres dynamic column headers (from another table) (the work of Eric Vallabh Minikel) i improved the function to be more flexible and convenient. I think it might be useful for others too, especially as it only relies on pg/plsql and does not need installation of extentions as other derivations of erics work (i.e. plpython) do. Testet with 9.3.5 but should also work at least down to 9.2.
Improvements:
deal with pivoted column names containing spaces
deal with multiple row header columns
deal with aggregate function in pivot cell as well as non-aggregated pivot cell (last parameter might be 'sum(cellval)' as well as 'cellval' in case the underlying table/view already does aggregation)
auto detect data type of pivot cell (no need to pass it to the function any more)
Useage:
SELECT get_crosstab_statement('table_to_pivot', ARRAY['rowname' [, <other_row_header_columns_as_well>], 'colname', 'max(cellval)');
Code:
CREATE OR REPLACE FUNCTION get_crosstab_statement(tablename character varying, row_header_columns character varying[], pivot_headers_column character varying, pivot_values character varying)
RETURNS character varying AS
$BODY$
--returns the sql statement to use for pivoting the table
--based on: http://www.cureffi.org/2013/03/19/automatically-creating-pivot-table-column-names-in-postgresql/
--based on: https://stackoverflow.com/questions/4104508/postgres-dynamic-column-headers-from-another-table
--based on: http://www.postgresonline.com/journal/categories/24-tablefunc
DECLARE
arrayname CONSTANT character varying := 'r';
row_headers_simple character varying;
row_headers_quoted character varying;
row_headers_castdown character varying;
row_headers_castup character varying;
row_header_count smallint;
row_header record;
pivot_values_columnname character varying;
pivot_values_datatype character varying;
pivot_headers_definition character varying;
pivot_headers_simple character varying;
sql_row_headers character varying;
sql_pivot_headers character varying;
sql_crosstab_result character varying;
BEGIN
-- 1. create row header definitions
row_headers_simple := array_to_string(row_header_columns, ', ');
row_headers_quoted := '''' || array_to_string(row_header_columns, ''', ''') || '''';
row_headers_castdown := array_to_string(row_header_columns, '::text, ') || '::text';
row_header_count := 0;
sql_row_headers := 'SELECT column_name, data_type
FROM information_schema.columns
WHERE table_name = ''' || tablename || ''' AND column_name IN (' || row_headers_quoted || ')';
FOR row_header IN EXECUTE sql_row_headers LOOP
row_header_count := row_header_count + 1;
row_headers_castup := COALESCE(row_headers_castup || ', ', '') || arrayname || '[' || row_header_count || ']::' || row_header.data_type || ' AS ' || row_header.column_name;
END LOOP;
-- 2. retrieve basic column name in case an aggregate function is used
SELECT coalesce(substring(pivot_values FROM '.*\((.*)\)'), pivot_values)
INTO pivot_values_columnname;
-- 3. retrieve pivot values datatype
SELECT data_type
FROM information_schema.columns
WHERE table_name = tablename AND column_name = pivot_values_columnname
INTO pivot_values_datatype;
-- 4. retrieve list of pivot column names.
sql_pivot_headers := 'SELECT string_agg(DISTINCT quote_ident(' || pivot_headers_column || '), '', '' ORDER BY quote_ident(' || pivot_headers_column || ')) as names, string_agg(DISTINCT quote_ident(' || pivot_headers_column || ') || '' ' || pivot_values_datatype || ''', '', '' ORDER BY quote_ident(' || pivot_headers_column || ') || '' ' || pivot_values_datatype || ''') as definitions FROM ' || tablename || ';';
EXECUTE sql_pivot_headers INTO pivot_headers_simple, pivot_headers_definition;
-- 5. set up the crosstab query
sql_crosstab_result := 'SELECT ' || replace (row_headers_castup || ', ' || pivot_headers_simple, ', ', ',
') || '
FROM crosstab (
''SELECT ARRAY[' || row_headers_castdown || '] AS ' || arrayname || ', ' || pivot_headers_column || ', ' || pivot_values || '
FROM ' || tablename || '
GROUP BY ' || row_headers_simple || ', ' || pivot_headers_column || (CASE pivot_values_columnname=pivot_values WHEN true THEN ', ' || pivot_values ELSE '' END) || '
ORDER BY ' || row_headers_simple || '''
,
''SELECT DISTINCT ' || pivot_headers_column || '
FROM ' || tablename || '
ORDER BY ' || pivot_headers_column || '''
) AS newtable (
' || arrayname || ' varchar[]' || ',
' || replace(pivot_headers_definition, ', ', ',
') || '
);';
RETURN sql_crosstab_result;
END
$BODY$
LANGUAGE plpgsql STABLE
COST 100;
I came across the same problem, and found an alternative solution. I'd like to ask for comments here.
The idea is to create the "output type" string for crosstab dynamically. The end result can't be returned by a plpgsql function, because that function would either need to have a static return type (which we don't have) or return setof record, thus having no advantage over the original crosstab function. Therefore my function saves the output cross-table in a view. Likewise, the input table of "pivot" data not yet in cross-table format is taken from an existing view or table.
The usage would be like this, using your example (I added the "fat" field to illustrate the sorting feature):
CREATE TABLE food_fat (name character varying(20) NOT NULL, fat integer);
CREATE TABLE eaten (food character varying(20) NOT NULL, day date NOT NULL);
-- This view will be formatted as cross-table.
-- ORDER BY is important, otherwise crosstab won't merge rows
CREATE TEMPORARY VIEW mymeals AS
SELECT day,food,COUNT(*) AS meals FROM eaten
GROUP BY day, food ORDER BY day;
SELECT auto_crosstab_ordered('mymeals_cross',
'mymeals', 'day', 'food', 'meals', -- what table to convert to cross-table
'food_fat', 'name', 'fat'); -- where to take the columns from
The last statement creates a view mymeals_cross that looks like this:
SELECT * FROM mymeals_cross;
day | bread | cheese | eggs
------------+-------+--------+------
2012-06-01 | 3 | 3 | 2
2012-06-02 | 2 | 1 | 3
(2 rows)
Here comes my implementation:
-- FUNCTION get_col_type(tab, col)
-- returns the data type of column <col> in table <tab> as string
DROP FUNCTION get_col_type(TEXT, TEXT);
CREATE FUNCTION get_col_type(tab TEXT, col TEXT, OUT ret TEXT)
AS $BODY$ BEGIN
EXECUTE $f$
SELECT atttypid::regtype::text
FROM pg_catalog.pg_attribute
WHERE attrelid='$f$||quote_ident(tab)||$f$'::regclass
AND attname='$f$||quote_ident(col)||$f$'
$f$ INTO ret;
END;
$BODY$ LANGUAGE plpgsql;
-- FUNCTION get_crosstab_type(tab, row, val, cattab, catcol, catord)
--
-- This function generates the output type expression for the crosstab(text, text)
-- function from the PostgreSQL tablefunc module when the "categories"
-- (cross table column labels) can be looked up in some view or table.
--
-- See auto_crosstab below for parameters
DROP FUNCTION get_crosstab_type(TEXT, TEXT, TEXT, TEXT, TEXT, TEXT);
CREATE FUNCTION get_crosstab_type(tab TEXT, rw TEXT, val TEXT, cattab TEXT,
catcol TEXT, catord TEXT, OUT ret TEXT)
AS $BODY$ BEGIN
EXECUTE $f$
SELECT '"$f$||quote_ident(rw)||$f$" $f$
||get_col_type(quote_ident(tab), quote_ident(rw))||$f$'
|| string_agg(',"'||_values._v||'" $f$
||get_col_type(quote_ident(tab), quote_ident(val))||$f$')
FROM (SELECT DISTINCT ON(_t.$f$||quote_ident(catord)||$f$) _t.$f$||quote_ident(catcol)||$f$ AS _v
FROM $f$||quote_ident(cattab)||$f$ _t
ORDER BY _t.$f$||quote_ident(catord)||$f$) _values
$f$ INTO ret;
END; $BODY$ LANGUAGE plpgsql;
-- FUNCTION auto_crosstab_ordered(view_name, tab, row, cat, val, cattab, catcol, catord)
--
-- This function creates a VIEW containing a cross-table of input table.
-- It fetches the column names of the cross table ("categories") from
-- another table.
--
-- view_name - name of VIEW to be created
-- tab - input table. This table / view must have 3 columns:
-- "row", "category", "value".
-- row - column name of the "row" column
-- cat - column name of the "category" column
-- val - column name of the "value" column
-- cattab - another table holding the possible categories
-- catcol - column name in cattab to use as column label in the cross table
-- catord - column name in cattab to sort columns in the cross table
DROP FUNCTION auto_crosstab_ordered(TEXT, TEXT, TEXT, TEXT, TEXT, TEXT, TEXT, TEXT);
CREATE FUNCTION auto_crosstab_ordered(view_name TEXT, tab TEXT, rw TEXT,
cat TEXT, val TEXT, cattab TEXT, catcol TEXT, catord TEXT) RETURNS void
AS $BODY$ BEGIN
EXECUTE $f$
CREATE VIEW $f$||quote_ident(view_name)||$f$ AS
SELECT * FROM crosstab(
'SELECT $f$||quote_ident(rw)||$f$,
$f$||quote_ident(cat)||$f$,
$f$||quote_ident(val)||$f$
FROM $f$||quote_ident(tab)||$f$',
'SELECT DISTINCT ON($f$||quote_ident(catord)||$f$) $f$||quote_ident(catcol)||$f$
FROM $f$||quote_ident(cattab)||$f$ m
ORDER BY $f$||quote_ident(catord)||$f$'
) AS ($f$||get_crosstab_type(tab, rw, val, cattab, catcol, catord)||$f$)$f$;
END; $BODY$ LANGUAGE plpgsql;
-- FUNCTION auto_crosstab(view_name, tab, row, cat, val)
--
-- This function creates a VIEW containing a cross-table of input table.
-- It fetches the column names of the cross table ("categories") from
-- DISTINCT values of the 2nd column of the input table.
--
-- view_name - name of VIEW to be created
-- tab - input table. This table / view must have 3 columns:
-- "row", "category", "value".
-- row - column name of the "row" column
-- cat - column name of the "category" column
-- val - column name of the "value" column
DROP FUNCTION auto_crosstab(TEXT, TEXT, TEXT, TEXT, TEXT);
CREATE FUNCTION auto_crosstab(view_name TEXT, tab TEXT, rw TEXT, cat TEXT, val TEXT) RETURNS void
AS $$ BEGIN
PERFORM auto_crosstab_ordered(view_name, tab, rw, cat, val, tab, cat, cat);
END; $$ LANGUAGE plpgsql;
The code is working fine. you will receive output as dynamic query.
CREATE OR REPLACE FUNCTION public.pivotcode(tablename character varying, rowc character varying, colc character varying, cellc character varying, celldatatype character varying)
RETURNS character varying AS
$BODY$
declare
dynsql1 varchar;
dynsql2 varchar;
columnlist varchar;
begin
-- 1. retrieve list of column names.
dynsql1 = 'select string_agg(distinct ''_''||'||colc||'||'' '||celldatatype||''','','' order by ''_''||'||colc||'||'' '||celldatatype||''') from '||tablename||';';
execute dynsql1 into columnlist;
-- 2. set up the crosstab query
--create temp table temp as
dynsql2 = 'select * from crosstab ( ''select '||rowc||','||colc||','||cellc||' from '||tablename||' group by 1,2 order by 1,2'', ''select distinct '||colc||' from '||tablename||' order by 1'' ) as newtable ( '||rowc||' varchar,'||columnlist||' );';
return dynsql2;
end
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
This is an example of pivoting data - in postgreSQL 9 there is a crosstab function to do this: http://www.postgresql.org/docs/current/static/tablefunc.html
I solved it folowing this article:
http://okbob.blogspot.com/2008/08/using-cursors-for-generating-cross.html
In short, i used function that for every result in a query dynamically creates the values for the next query, and returns the result needed as a refcursor. This solved my sql result part, now i need to figure out the java part, but that isnt connected much to the question :)