用SQL中的主键克隆一行?

时间:2010-01-04 22:20:17

标签: c# sql-server postgresql ansi-sql

我试图使一些跨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作为我的客户。

3 个答案:

答案 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功能

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更改为您的主要/唯一字段名称。