在Postgres 8.4或更高版本中,使用默认值填充一行数据的最有效方法是什么,而不实际创建行。例如,作为交易(伪代码):
create table "mytable"
(
id serial PRIMARY KEY NOT NULL,
parent_id integer NOT NULL DEFAULT 1,
random_id integer NOT NULL DEFAULT random(),
)
begin transaction
fake_row = insert into mytable (id) values (0) returning *;
delete from mytable where id=0;
return fake_row;
end transaction
基本上我希望查询单行,其中parent_id为1,random_id是随机数(或其他函数返回值),但我不希望此记录在表中持久存在或影响主键序列serial_id_seq。
我的选项似乎是使用上面的事务或创建视图,这些视图是添加了假行的表的副本,但我不知道每个的优缺点或是否存在更好的方法。
我正在寻找一个答案,假设没有事先了解除id
之外的任何列的数据类型或默认值或列的数量或顺序。只知道表名,并且表中不应存在id为0的记录。
过去我创建假记录0作为永久记录,但我开始认为这种记录是一种污染(因为我通常不得不在未来的查询中过滤掉它)。
答案 0 :(得分:4)
您可以使用以下命令将表定义和默认值复制到临时表:
CREATE TEMP TABLE table_name_rt (LIKE table_name INCLUDING DEFAULTS);
使用此临时表生成虚拟行。这样的表将在会话(或事务)结束时删除,并且只对当前会话可见。
答案 1 :(得分:2)
我只想选择假值作为文字:
select 1 id, 1 parent_id, 1 user_id
返回的行(实际上)与实际行无法区分。
从目录中获取值:
select
0 as id, -- special case for serial type, just return 0
(select column_default::int -- Cast to int, because we know the column is int
from INFORMATION_SCHEMA.COLUMNS
where table_name = 'mytable'
and column_name = 'parent_id') as parent_id,
(select column_default::int -- Cast to int, because we know the column is int
from INFORMATION_SCHEMA.COLUMNS
where table_name = 'mytable'
and column_name = 'user_id') as user_id;
请注意,您必须知道列是什么以及它们的类型,但这是合理的。如果更改表模式(默认值除外),则需要调整查询。
请参阅上文SQLFiddle。
答案 2 :(得分:2)
您可以查询目录并构建动态查询
假设我们有这张表:
create table test10(
id serial primary key,
first_name varchar( 100 ),
last_name varchar( 100 ) default 'Tom',
age int not null default 38,
salary float default 100.22
);
运行以下查询时:
SELECT string_agg( txt, ' ' order by id )
FROM (
select 1 id, 'SELECT ' txt
union all
select 2, -9999 || ' as id '
union all
select 3, ', '
|| coalesce( column_default, 'null'||'::'||c.data_type )
|| ' as ' || c.column_name
from information_schema.columns c
where table_schema = 'public'
and table_name = 'test10'
and ordinal_position > 1
) xx
;
结果你会得到这种刺痛:
"SELECT -9999 as id , null::character varying as first_name ,
'Tom'::character varying as last_name , 38 as age , 100.22 as salary"
然后执行此查询,您将获得“幻影行”。
我们可以构建一个函数来构建和处理查询并返回我们的行:
CREATE OR REPLACE FUNCTION get_phantom_rec (p_i test10.id%type )
returns test10 as $$
DECLARE
v_sql text;
myrow test10%rowtype;
begin
SELECT string_agg( txt, ' ' order by id )
INTO v_sql
FROM (
select 1 id, 'SELECT ' txt
union all
select 2, p_i || ' as id '
union all
select 3, ', '
|| coalesce( column_default, 'null'||'::'||c.data_type )
|| ' as ' || c.column_name
from information_schema.columns c
where table_schema = 'public'
and table_name = 'test10'
and ordinal_position > 1
) xx
;
EXECUTE v_sql INTO myrow;
RETURN myrow;
END$$ LANGUAGE plpgsql ;
然后这个简单的查询为您提供了所需内容:
select * from get_phantom_rec ( -9999 );
id | first_name | last_name | age | salary
-------+------------+-----------+-----+--------
-9999 | | Tom | 38 | 100.22