在 PostgreSQL 中选择具有特定列名的列
Posted
技术标签:
【中文标题】在 PostgreSQL 中选择具有特定列名的列【英文标题】:Select columns with particular column names in PostgreSQL 【发布时间】:2013-03-25 21:18:00 【问题描述】:我想编写一个简单的查询来选择 PostgreSQL 中的多个列。但是,我不断收到错误 - 我尝试了一些选项,但它们对我不起作用。目前我收到以下错误:
org.postgresql.util.PSQLException:错误:语法错误在或附近 “列”
要获取具有值的列,我尝试以下操作:
select * from weather_data where column like '%2010%'
有什么想法吗?
【问题讨论】:
您是要返回其中包含 2010 的列,还是要返回特定列包含值 2010 的行?您不能选择这样的列列表(好吧,也许使用动态 sql 可以)... 你有一个名为 column 的列吗? 好吧,我正在尝试返回列名称中包含 2010 的列。例如,有名称的列:m01y2010 - 所以我想要那个,以及:m02y2010 ... 等等 - 以及存储在它们列中的值。所以没有办法选择名称中包含 2010 的列列表!? 动态 SQL 可能是您唯一的选择。 使用这样的列名,您的数据模型可能很差。我听说过《为凡人设计数据库》这本书的好消息。 【参考方案1】:column
是 reserved word。除非双引号,否则不能将其用作标识符。喜欢:"column"
。
但这并不意味着你应该这样做。只是不要使用保留字作为标识符。永远。
到...
选择名称中包含 2010 的列列表:
..您可以使用此功能从系统目录表pg_attribute
动态构建SQL命令:
CREATE OR REPLACE FUNCTION f_build_select(_tbl regclass, _pattern text)
RETURNS text AS
$func$
SELECT format('SELECT %s FROM %s'
, string_agg(quote_ident(attname), ', ')
, $1)
FROM pg_attribute
WHERE attrelid = $1
AND attname LIKE ('%' || $2 || '%')
AND NOT attisdropped -- no dropped (dead) columns
AND attnum > 0; -- no system columns
$func$ LANGUAGE sql;
呼叫:
SELECT f_build_select('weather_data', '2010');
返回类似:
SELECT foo2010, bar2010_id, FROM weather_data;
在我们实际构建查询之前,您无法使其完全动态化,因为返回类型是未知。
【讨论】:
Em,我实际上没有 - 我只是试图搜索以 2010 作为其名称一部分的列名,而不是名为 column 的列,其中 2010 作为值之一的一部分...... 谢谢!使用了您的解决方案! 如何执行这个函数返回的select
语句?
@ian-campbell:运行它就像运行函数调用一样。您可以使用动态 SQL(随机示例:***.com/a/8449341/939860)或使用 psql 中的\gexec
(例如 ***.com/a/18389184/939860)自动执行此操作。【参考方案2】:
这将为您提供特定表中的列列表(如果需要,您可以选择添加架构):
SELECT column_name
FROM information_schema.columns
WHERE table_name = 'yourtable'
and column_name like '%2010%'
SQL Fiddle Demo
然后您可以使用该查询创建动态 sql 语句来返回结果。
【讨论】:
【参考方案3】:尝试使用这样的动态结构通常表明您应该使用适合动态访问的数据格式,例如 hstore
、json
、xml
等。
您可以通过在应用程序中动态创建 SQL 来获取动态列列表。您可以查询INFORMATION_SCHEMA
以获取有关表列的信息并构建查询。
可以在 PL/PgSQL 中执行此操作并使用 EXECUTE
运行生成的查询,但您会发现使用结果 RECORD
有点困难,因为您必须获取和解码复合元组,您可以' t 将结果集展开为普通的列列表。观察:
craig=> CREATE OR REPLACE FUNCTION retrecset() returns setof record as $$
values (1,2,3,4), (10,11,12,13);
$$ language sql;
craig=> select retrecset();
retrecset
---------------
(1,2,3,4)
(10,11,12,13)
(2 rows)
craig=> select * from retrecset();
ERROR: a column definition list is required for functions returning "record"
craig=> select (r).* FROM (select retrecset()) AS x(r);
ERROR: record type has not been registered
您所能做的就是获取原始记录并在客户端中对其进行解码。您无法从 SQL 中对其进行索引,也无法将其转换为其他任何内容,等等。大多数客户端 API 不提供解析匿名记录的文本表示的工具,因此您可能必须自己编写。
所以:您可以在不知道结果类型的情况下从 PL/PgSQL 返回动态记录,这并不是特别有用,而且在客户端处理起来很痛苦。您真的只想首先使用客户端生成查询。
【讨论】:
“有些困难”是指“几乎不可能”,因为返回类型未知。您需要提供列定义列表,但如果您知道列定义列表,则不需要动态查询。第 22 条。 @ErwinBrandstetter 如果您对结果集中未展开的匿名记录感到满意,您可以调用返回record
或 setof record
的函数而不使用列定义列表。查看更新的答案。【参考方案4】:
您不能像这样搜索所有列。你必须指定一个特定的列。
例如,
select * from weather_data where weather_date like '%2010%'
如果是日期,最好指定日期范围:
select * from weather_data where weather_date between '2010-01-01' and '2010-12-31'
【讨论】:
【参考方案5】:找到这个here:
SELECT 'SELECT ' || array_to_string(ARRAY(SELECT 'o' || '.' || c.column_name
FROM information_schema.columns As c
WHERE table_name = 'officepark'
AND c.column_name NOT IN('officeparkid', 'contractor')
), ',') || ' FROM officepark As o' As sqlstmt
结果是您只需要进一步执行的 SQL SELECT 查询。 它符合我的需要,因为我将结果 在 shell 中像这样传递:
psql -U myUser -d myDB -t -c "SELECT...As sqlstm" | psql -U myUser -d myDB
这会返回格式化的输出,但它只能在 shell 中工作。 希望有一天这对某人有所帮助。
【讨论】:
以上是关于在 PostgreSQL 中选择具有特定列名的列的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Oracle Sql Developer 中选择特定的列标题