简体   繁体   中英

Use query for SQL alias OR join column names to row values?

I'm working with data in PostgreSQL that uses a data dictionary table to provide descriptions for the column (variable) names of other tables in the dataset. For example:

Table 1:

a00600 | a00900
-------+-------
row 1  | row 1
row 2  | row 2

Data Dictionary (Key) columns:

Variable | Description
---------+------------
a00600   | Total population
a00900   | Zipcode

For reporting purposes, how do I write SQL to perform the following dynamically (without specifying each column name)?

SELECT 'a00600' AS (SELECT Key.Description
WHERE Key.Variable = 'a00600')
FROM Table 1;

I realize there's likely a better way to parse this question/problem and am open to any ideas for what I need to accomplish.

You need to use dynamic SQL with a procedural language function. Usually plpgsql and use EXECUTE with it.

The tricky part is to define the return type at creation time.

I have compiled a number of solutions in this related answer .
There are lots of related answer on SO already. Search for combinations of terms like [plpgsql] EXECUTE RETURN QUERY [dynamic-sql] quote_ident .


Your approach is commonly frowned upon among database designers.
My personal opinion: I wouldn't go that route. I always use basic, descriptive names. You can always add more décor in your application if needed.

Another way to get the descriptions instead of the actual column names would be to create views (one for every table). This can be automated by generating the views automatically. This looks rather clumsy, but it has the huge advantage that for "complex* queries the resulting queryplans will be axactly the same as for the original columns names. (functions joined into complex queries will perform badly: the optimiser cannot take them apart, so the resulting behavior will be equivalent to "row at a time") Example:

-- tmp schema is only for testing
DROP SCHEMA tmp CASCADE;
CREATE SCHEMA tmp ;
SET search_path=tmp;

CREATE TABLE thedata
        ( a00600 varchar
        , a00900 varchar
        );
INSERT INTO thedata(a00600 , a00900) VALUES
 ('key1', 'data1')
,('key2', 'data2');

CREATE TABLE thedict
        ( variable varchar
        , description varchar
        );

INSERT INTO thedict(variable , description) VALUES
 ('a00600'   , 'Total population')
,('a00900'   , 'Zipcode' );

CREATE OR REPLACE FUNCTION create_view_definition(zname varchar)
  RETURNS varchar AS
$BODY$
DECLARE
   thestring varchar;
   therecord RECORD;
   iter INTEGER ;
   thecurs cursor for
        SELECT co.attname AS zname, d.description AS zdesc
        FROM pg_class ct
        JOIN pg_namespace cs ON cs.oid=ct.relnamespace
        JOIN pg_attribute co ON co.attrelid = ct.oid AND co.attnum > 0
        LEFT JOIN thedict d ON d.variable = co.attname
        WHERE ct.relname = 'thedata'
        AND cs.nspname = 'tmp'
        ;
BEGIN
        thestring = '' ;
        iter = 0;
        FOR therecord IN thecurs LOOP
                IF (iter = 0) THEN
                        thestring = 'CREATE VIEW ' || quote_ident('v'||zname) || ' AS ( SELECT ' ;
                ELSE
                        thestring = thestring || ', ';
                END IF;
                iter=iter+1;

                thestring = thestring || quote_ident(therecord.zname);

                IF (therecord.zdesc IS NOT NULL) THEN
                        thestring = thestring || ' AS ' || quote_ident(therecord.zdesc);
                END IF;

        END LOOP;
        IF (iter > 0) THEN
                thestring = thestring || ' FROM ' || quote_ident(zname) || ' )' ;
        END IF;

RETURN thestring;

END;
$BODY$ LANGUAGE plpgsql;

CREATE OR REPLACE FUNCTION execute_view_definition(zname varchar)
  RETURNS INTEGER AS
$BODY$
DECLARE
   meat varchar;
BEGIN
   meat = create_view_definition(zname);
   EXECUTE meat;
RETURN 0;

END;
$BODY$ LANGUAGE plpgsql;

SELECT create_view_definition('thedata');
SELECT execute_view_definition('thedata');

SELECT * FROM vthedata;

RESULT:

CREATE FUNCTION
CREATE FUNCTION
                                      create_view_definition                                       
---------------------------------------------------------------------------------------------------
 CREATE VIEW vthedata AS ( SELECT a00600 AS "Total population", a00900 AS "Zipcode" FROM thedata )
(1 row)

 execute_view_definition 
-------------------------
                       0
(1 row)

 Total population | Zipcode 
------------------+---------
 key1             | data1
 key2             | data2
(2 rows)

Please note this is only an example. If it were for real, I would at least put the generated views into a separate schema, to avoid name collisions and pollution of the original schema.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM