我试图使一些跨DB(SQL Server和PostgreSQL)兼容的SQL。我需要做的是克隆一行。最好在SQL服务器上本地执行它,而不必将整行拖到我们的客户端并重新插入它。此外,我们更喜欢不必从头开始创建一个新的SQL查询动态放入列名,但我想这是一个选项。
例如: 我们有一个地址表就是这样一个表: address_rid:整数,主键,自动递增,非空 address1:varchar(100) address2:varchar(100)
好吧,我们的目标是能够克隆其中一行,以便address1和address2相同,但address_rid将照常设置为下一个值。
你会怎么做呢?
另外,我看过Quickest way to clone row in SQL
有
INSERT INTO PrimKeys
SELECT 'PrimKey2' AS PrimKey,*
FROM PrimKeys
WHERE PrimKey='PrimKey1'
我无法在postgres上使用这样的内容,并且在插入的主键上使用类似default
的内容。
编辑: 此外,我还要采取2个单独的查询,这些查询将在SQL Server和Postgres上执行此操作,但我更愿意只需维护1个查询。
我正在使用C#ado.net作为我的客户。
答案 0 :(得分:3)
我不确定PostgreSQL,但如果它像大多数系统那样支持自动增量,那么只需将主键字段留空即可。但是,这确实意味着您需要指定列名称。
另外,当你说克隆时,听起来你想要复制你的记录,但在你的描述中,address1和address2列在同一行数据上。
如果要将address1复制到address2列,可以使用简单的更新语句。
如果您尝试克隆整个行以使两个记录完全相同,那么您可以使用类似的东西,它应该适用于两种环境。
INSERT INTO Addresses
( address1, address2 )
SELECT address1, address2
FROM Addresses
WHERE addressId = ID
现在接下来的问题是,您是从一种数据库类型克隆到另一种数据库类型吗?如果是这样,那么无论如何你都需要把它拉进你的应用程序。如果你是那么为什么不使用像nHibernate这样的东西来抽象你的数据库层。
如果目标是制作副本,那么你可以使用上面的sql直接在db中完成。
虽然这个sql可能是最简单的(如果需要使用系统/主表,你可以从数据库中反映它),你仍然需要指定列名。主要原因是,只要添加*通配符,它仍然会尝试在选择列表中包含原始主键列,然后将有1个额外列到您拥有的列。
在插入语句中使用通配符时需要注意的另一个问题是,您的列命令 HAVE TO MATCH ,否则您将获得非常意外的结果。
答案 1 :(得分:2)
Postgres与Oracle一样,使用序列为人工/代理键生成顺序数值。要获得下一个值,您需要使用:
NEXTVAL(your_sequence_name)
...在INSERT语句中,以设置主键的值。您将无法从INSERT语句中省略它,除非由于某些奇怪的原因,该列可以为空。所以在Postgres你需要使用:
INSERT INTO PrimKeys
SELECT NEXTVAL(your_sequence_name),
[rest of columns, because you can't include the pk col/value]
FROM PrimKeys
WHERE PrimKey='PrimKey1'
SQL Server(和MySQL)允许您不指定列,或者提供NULL
作为主键列的占位符,并为您提供值。那就像你得到的那样近。
参考:
答案 2 :(得分:0)
派对有点晚了,但这个功能可以帮助别人。
创建聚合函数来分隔结果中的文本值,逗号分隔符将用于获取列列表。
CREATE OR REPLACE FUNCTION concat_delimited( TEXT, TEXT, TEXT ) RETURNS TEXT AS $$
SELECT $1 || (CASE WHEN $1 = '' THEN '' ELSE $3 END) || $2;
$$
LANGUAGE SQL STRICT IMMUTABLE;
CREATE AGGREGATE delimited_list_of ( TEXT, TEXT ) (
SFUNC = concat_delimited,
STYPE = TEXT,
INITCOND = ''
);
创建复制记录的功能
CREATE OR REPLACE FUNCTION duplicate(_schema text,_tbl text, _id integer)
RETURNS integer AS
$BODY$
DECLARE cols text;
sql text;
result integer;
BEGIN
SELECT into cols delimited_list_of(column_name, ',')
FROM information_schema.columns
WHERE table_schema = _schema AND table_name = _tbl AND column_name != 'id';
raise notice 'Cols: %', cols;
sql := 'insert into ' || quote_ident(_schema) || '.' || quote_ident(_tbl) || '('
|| cols || ') SELECT ' || cols || ' FROM ' || quote_ident(_schema) || '.'
|| quote_ident(_tbl) || ' WHERE id = ' || _id || ' RETURNING id' ;
raise notice 'Query: %', sql;
EXECUTE sql into result;
RETURN result;
END;
$BODY$
LANGUAGE plpgsql VOLATILE COST 100;
从那里只传递要克隆的记录的模式名称,表名和id,它将返回创建记录的id。 E.g
select duplicate('_schema','test_tbl',500001);
您需要将字段名称ID更改为您的主要/唯一字段名称。