使用SQL别名查询或将列名称连接到行值?

时间:2012-09-04 18:03:34

标签: sql postgresql dynamic-sql

我正在使用PostgreSQL中的数据,该数据使用数据字典表来提供数据集中其他表的列(变量)名称的描述。例如:

表1:

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

数据字典(Key)列:

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

出于报告目的,如何编写SQL以动态执行以下操作(不指定每个列名称)?

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

我意识到可能有更好的方法来解析这个问题/问题,并对我需要完成的任何想法持开放态度。

2 个答案:

答案 0 :(得分:2)

您需要使用动态SQL 和过程语言功能。通常 plpgsql 并使用EXECUTE

棘手的部分是在创建时定义返回类型

我在this related answer编译了许多解决方案 关于SO已经有很多相关的答案了。搜索[plpgsql] EXECUTE RETURN QUERY [dynamic-sql] quote_ident等字词组合。


您的方法通常在数据库设计者中不受欢迎 我的个人意见:我不会那样做。我总是使用基本的描述性名称。如果需要,您可以随时在应用程序中添加更多装饰。

答案 1 :(得分:0)

获取描述而不是实际列名的另一种方法是创建视图(每个表一个)。这可以通过自动生成视图来自动完成。这看起来相当笨拙,但它具有巨大的优势,对于“复杂*查询,生成的查询计划将与原始列名称完全相同。”加入复杂查询的函数将表现不佳:优化器不能将它们分开,因此产生的行为将等同于“一次排” 例如:

-- 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;

结果:

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)

请注意,这只是一个例子。如果它是真实的,我将至少将生成的视图放入一个单独的模式中,以避免名称冲突和原始模式的污染。