2

我正在尝试制作一些跨数据库(SQL Server 和 PostgreSQL)兼容的 SQL。我需要做的是克隆一行。最好在 SQL 服务器上本地执行此操作,而不必将整行下拉到我们的客户端并重新插入。此外,我们宁愿不必从头开始创建新的 SQL 查询,动态输入列名,但我想这是一个选项。

例如:我们有一个地址表,它是这样的表: address_rid: integer, primary key, auto-incrementing, not null address1: varchar(100) address2: varchar(100)

好吧,我们的目标是能够克隆这些行之一,以便 address1 和 address2 相同,但 address_rid 将像往常一样设置为下一个值。

你会怎么做呢?

另外,我已经看到了在 SQL 中克隆行的最快方法

其中有


INSERT INTO PrimKeys 
SELECT 'PrimKey2' AS PrimKey,* 
  FROM PrimKeys 
 WHERE PrimKey='PrimKey1'

我无法让这样的东西在 postgres 上工作,也无法default在插入的主键上使用类似的东西。

编辑:另外,我也希望在 SQL Server 和 Postgres 上执行 2 个单独的查询,尽管我更愿意只维护 1 个查询。

我使用 C# ado.net 作为我的客户端。

4

3 回答 3

3

我不确定 PostgreSQL,但如果它像大多数系统一样支持自动增量,那么只需将主键字段留空。但是,这确实意味着您需要指定列名。

此外,当您说克隆时,听起来您想要复制记录,但在您的描述中,地址 1 和地址 2 列位于同一行数据上。

如果要将 address1 复制到 address2 列,可以使用简单的更新语句。

如果您尝试克隆整行以拥有两条完全相同的记录,那么您可以使用类似的东西,它应该适用于两种环境。

INSERT INTO Addresses
( address1, address2 )
SELECT address1, address2
  FROM Addresses
 WHERE addressId = ID

现在下一个问题是,您是否正在从一种数据库类型克隆到另一种数据库类型?如果是这样,那么无论如何您都需要将其拉入您的应用程序。如果你是那你为什么不使用像 nHibernate 这样的东西来抽象你的 db 层。

如果目标只是制作一个副本,那么您可以使用上面的 sql 在数据库中直接进行。

虽然这个 sql 可能是最简单的(如果需要,您可以使用系统/主表从数据库中反映它)您仍然需要指定列名。主要原因是,只要您添加 * 通配符,它​​仍然会尝试将您的原始主键列包含在选择列表中,然后您拥有的内容将增加 1 列。

在插入语句中使用通配符时要注意的另一个问题是您的列顺序必须匹配,否则您将得到非常意外的结果。

于 2010-01-04T22:36:16.760 回答
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作为主键列的占位符,并为您提供值。这是你得到的最接近的。

参考:

于 2010-01-04T22:46:09.367 回答
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。例如

select  duplicate('_schema','test_tbl',500001);

您需要将字段名称 id 更改为您的主要/唯一字段名称。

于 2012-05-25T02:34:43.390 回答