2015-12-20 90 views
1

我有Postgres的一个表:访问Postgres的字段指定字段的名称作为文本字符串

create table fubar (
name1 text, 
name2 text, ..., 
key integer); 

我想写从FUBAR给出的列名返回的域值的功能:

function getFubarValues(col_name text, key integer) returns text ... 

getFubarValues返回由key标识的行中指定列的值。似乎这应该很容易。

我不知所措。有人可以帮忙吗?谢谢。

+0

“*从FUBAR给出的列名*返回字段值” - 为什么你就不能写'选择fubar'栏吗?你在这里试图解决的**真正**问题是什么? –

回答

0

克林的回答是一个很好的(即安全的)方法的问题时提出的,但它可以简化为:

PostgreSQL的->运算符允许表达式。例如:

CREATE TABLE test (
    id SERIAL, 
    js JSON NOT NULL, 
    k TEXT NOT NULL 
); 
INSERT INTO test (js,k) VALUES ('{"abc":"def","ghi":"jkl"}','abc'); 
SELECT js->k AS value FROM test; 

主要生产

value 
------- 
"def" 

因此,我们可以结合起来,与row_to_json

CREATE TABLE test (
    id SERIAL, 
    a TEXT, 
    b TEXT, 
    k TEXT NOT NULL 
); 
INSERT INTO test (a,b,k) VALUES 
    ('foo','bar','a'), 
    ('zip','zag','b'); 
SELECT row_to_json(test)->k AS value FROM test; 

产地:

value 
------- 
"foo" 
"zag" 

在这里,我正从关键桌子我自己,但当然你可以从任何来源/表达。这只是一个价值。另请注意,返回的结果是JSON值类型(它不知道它是文本,数字还是布尔值)。如果你希望它是文本,只投它:(row_to_json(test)->k)::TEXT


现在,这个问题本身就是回答,这里就是为什么你不应该这样做,你应该做的,而不是!

永远不要相信任何数据。即使它已经存在于你的数据库中,你也不应该相信它。我在这里发布的方法对SQL注入攻击是安全的,但是攻击者仍然可以将k设置为'id',并看到一个不打算让他们看到的列。

一个更好的方法是用这种类型的查询来构造数据。 Postgres对此有一些很好的数据类型; HSTORE和JSON/JSONB。将你的动态列合并到一个列中(我建议HSTORE的简单性和通用性更强)。

这有几个优点:您的模式定义明确,如果添加更多动态列,则不需要更改,您不需要执行昂贵的重新铸造(即row_to_json),并且您可以利用列上的索引(感谢PostgreSQL的功能索引)。

等同于我上面写的是代码:

CREATE EXTENSION HSTORE; -- necessary if you're not already using HSTORE 
CREATE TABLE test (
    id SERIAL, 
    cols HSTORE NOT NULL, 
    k TEXT NOT NULL 
); 
INSERT INTO test (cols,k) VALUES 
    ('a=>"foo",b=>"bar"','a'), 
    ('a=>"zip",b=>"zag"','b'); 
SELECT cols->k AS value FROM test; 

或者,你的价值观的自动转义插入时,你可以使用一个:

INSERT INTO test (cols,k) VALUES 
    (hstore('a', 'foo') || hstore('b', 'bar'), 'a'), 
    (hstore(ARRAY['a','b'], ARRAY['zip','zag']), 'b'); 

http://www.postgresql.org/docs/9.1/static/hstore.html更多细节。

0

您可以使用动态SQL选择由名称的列:

create or replace function get_fubar_values (col_name text, row_key integer) 
returns setof text language plpgsql as $$begin 
    return query execute 'select ' || quote_ident(col_name) || 
     ' from fubar where key = $1' using row_key; 
end$$; 
+0

这可能比窑的回答快,但OP应该注意的是,他们必须要小心,列名是使用此方法(空格,引号或其他特殊字符会打破之前的安全,如果COL_NAME输入不能被信任 - 即它来自用户或数据库本身,这似乎可能在这个问题的上下文中 - 这是SQL注入风险) – Dave

相关问题