2

クロス DB (SQL Server と PostgreSQL) 互換の SQL を作成しようとしています。私がする必要があるのは、行を複製することです。行全体をクライアントにプルして再挿入することなく、SQL サーバーでローカルに実行することをお勧めします。また、列名を動的に入力する新しい SQL クエリを最初から作成する必要はありませんが、これはオプションだと思います。

例: アドレス テーブルがあります。次のようなテーブルです: address_rid: 整数、主キー、自動インクリメント、非 null address1: varchar(100) address2: varchar(100)

さて、私たちの目標は、address1 と address2 が同じになるようにこれらの行の 1 つを複製できるようにすることですが、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 についてはよくわかりませんが、ほとんどのシステムのように自動インクリメントがサポートされている場合は、主キー フィールドを空白のままにします。ただし、これは列名を指定する必要があることを意味します。

また、クローンと言うと、レコードの複製が必要なように聞こえますが、説明では、address1 列と address2 列はデータの同じ行にあります。

address1 を address2 列に複製する場合は、単純な update ステートメントを使用できます。

行全体を複製してまったく同じ 2 つのレコードを作成しようとしている場合は、このようなものを使用でき、両方の環境で機能するはずです。

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

次の質問は、ある DB タイプから別の DB タイプにクローンを作成していますか? その場合は、とにかくそれをアプリに取り込む必要があります。そうであれば、nHibernate のようなものを使用して、db レイヤーを抽象化してみてはいかがでしょうか。

目的が単にコピーを作成することである場合は、上記の SQL を使用してデータベースで直接行うことができます。

このSQLはおそらく最も簡単ですが(必要に応じてシステム/マスターテーブルを使用してデータベースから反映できます)、列名を指定する必要があります。主な理由は、 * ワイルドカードを追加するとすぐに、元の主キー列を選択リストに含めようとし、選択リストに 1 つの列が追加されることです。

挿入ステートメントでワイルドカードを使用する場合に注意すべきもう 1 つの問題は、列の順序が一致する必要があることです。そうしないと、非常に予期しない結果が得られます。

于 2010-01-04T22:36:16.760 に答える
2

Postgresは、Oracleと同様に、シーケンスを使用して、人工キー/代理キーのシーケンス数値を生成します。次の値を取得するには、次を使用する必要があります。

NEXTVAL(your_sequence_name) 

...主キーの値を設定するためにINSERTステートメントで。なんらかの奇妙な理由で列がNULL可能でない限り、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'

同等のSQLServer機能

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 に答える