5

以下で説明するテーブルの組み合わせの問題を解決するには、SQL コードが必要です。

テーブルの古いデータ: テーブルの古い

    name     version    status    lastupdate      ID
    A        0.1        on        6/8/2010        1
    B        0.1        on        6/8/2010        2
    C        0.1        on        6/8/2010        3
    D        0.1        on        6/8/2010        4
    E        0.1        on        6/8/2010        5
    F        0.1        on        6/8/2010        6
    G        0.1        on        6/8/2010        7

テーブルの新しいデータ: テーブルの新しい

    name     version    status    lastupdate     ID         
    A        0.1        on        6/18/2010                
                                                           #B entry deleted
    C        0.3        on        6/18/2010                #version_updated
    C1       0.1        on        6/18/2010                #new_added
    D        0.1        on        6/18/2010                
    E        0.1        off       6/18/2010                #status_updated
    F        0.1        on        6/18/2010                
    G        0.1        on        6/18/2010                
    H        0.1        on        6/18/2010                #new_added
    H1       0.1        on        6/18/2010                #new_added

新しいデータと古い日付の違い:

B エントリが削除されました

C エントリ バージョンが更新されました

Eエントリー状況を更新しました

C1/H/H1 エントリー 新規追加

私が望むのは、後でデータがどのように変更されても、ID - 名前のマッピング関係を常に古いデータ テーブルに保持することです。別名、名前には常に一意の ID 番号がバインドされています。

エントリが更新された場合はデータを更新し、エントリが新しく追加された場合はテーブルに挿入し、新しく割り当てられた一意の ID を与えます。エントリが削除された場合は、エントリを削除し、後でその ID を再利用しないでください。

ただし、単純な select または update ステートメントでしか SQL を使用できないため、そのようなコードを記述するのは難しすぎる可能性があります。専門知識のある人が方向性を示してくれることを願っています。SQL バリアントの違いに関する詳細は必要ありません。サンプルで十分です。

前もって感謝します!

Rg

KC

======== ここに私の草稿SQLをリストしましたが、それが機能するかどうかはわかりません.専門知識のある誰かがコメントしてください.

1. ストアの更新用に古いテーブルを tmp として複製する

select * from old としてテーブル tmp を作成

2.古いテーブルと新しいテーブルで「名前」が同じであるtmpに更新します

update tmp where name in (新しいものから名前を選択)

3.異なる「名前」(古いものと新しいもの)をtmpに挿入し、新しいIDを割り当てます

insert into tmp (name version status lastupdate ID) set idvar = max(select max(id) from tmp) + 1 select * from (select new.name new.version new.status new.lastupdate new.ID from old, new where old.name <> new.name)

4. 削除されたエントリを tmp テーブルから削除します (B など)。

tmp から削除 (??? を選択)

4

7 に答える 7

1

使用している DBMS について言及したことはありませんが、SQL Server を使用している場合、本当に優れているのは SQLMERGEステートメントです。参照: http://www.mssqltips.com/tip.asp?tip=1704

MERGE ステートメントは基本的に、すべて同じステートメント内の個別の挿入、更新、および削除ステートメントとして機能します。「ソース」レコード セットと「ターゲット」テーブル、および 2 つの間の結合を指定します。次に、2 つのデータ間のレコードが一致する場合または一致しない場合に発生するデータ変更のタイプを指定します。MERGE は、特にデータ ウェアハウス テーブルをロードする場合に非常に便利です。データ ウェアハウス テーブルは非常に大きくなる可能性があり、行が存在する場合と存在しない場合に特定のアクションを実行する必要があります。

例:

MERGE Products AS TARGET
USING UpdatedProducts AS SOURCE 
ON (TARGET.ProductID = SOURCE.ProductID) 
--When records are matched, update 
--the records if there is any change
WHEN MATCHED AND TARGET.ProductName <> SOURCE.ProductName 
OR TARGET.Rate <> SOURCE.Rate THEN 
UPDATE SET TARGET.ProductName = SOURCE.ProductName, 
TARGET.Rate = SOURCE.Rate 
--When no records are matched, insert
--the incoming records from source
--table to target table
WHEN NOT MATCHED BY TARGET THEN 
INSERT (ProductID, ProductName, Rate) 
VALUES (SOURCE.ProductID, SOURCE.ProductName, SOURCE.Rate)
--When there is a row that exists in target table and
--same record does not exist in source table
--then delete this record from target table
WHEN NOT MATCHED BY SOURCE THEN 
DELETE
--$action specifies a column of type nvarchar(10) 
--in the OUTPUT clause that returns one of three 
--values for each row: 'INSERT', 'UPDATE', or 'DELETE', 
--according to the action that was performed on that row
OUTPUT $action, 
DELETED.ProductID AS TargetProductID, 
DELETED.ProductName AS TargetProductName, 
DELETED.Rate AS TargetRate, 
INSERTED.ProductID AS SourceProductID, 
INSERTED.ProductName AS SourceProductName, 
INSERTED.Rate AS SourceRate; 
SELECT @@ROWCOUNT;
GO
于 2010-06-08T20:28:19.707 に答える
1

注-パフォーマンスが心配な場合は、この回答全体をスキップできます:-)

再設計できる場合は、2 つのテーブルを用意します。1 つはデータ、もう 1 つは名前 - ID リンケージです。何かのようなもの

table_original

name     version    status    lastupdate
A        0.1        on        6/8/2010
B        0.1        on        6/8/2010
C        0.1        on        6/8/2010
D        0.1        on        6/8/2010
E        0.1        on        6/8/2010
F        0.1        on        6/8/2010
G        0.1        on        6/8/2010

およびname_id

name     ID 
A        1 
B        2 
C        3 
D        4 
E        5 
F        6 
G        7

新しいデータセットで table_new を取得すると

  1. TRUNCATE table_original
  2. INSERT INTO name_id (name_id にない table_new からの名前)
  3. table_new を table_original にコピー

注 : ここでの削除については、少しあいまいな点があると思います

エントリが削除された場合は、エントリを削除し、後でその ID を再利用しないでください。

名前 A が削除され、その後の一連の更新で再び表示された場合、あなたは a. A にタグ付けされた元の ID を再利用するか、または b. 新しい ID を生成しますか?

Bなら。列を削除する必要がありますか? name_id と最後のステップで

4 . セット 削除されましたか? = Y where name not in table_original

2. Deleted を除外しますか? = Y レコード。

table_old から必要なものは名前と ID のリンクのみであるというロジックに基づいて、name_id テーブルを使用せずに同じことを行うこともできます。他に必要なものはすべて table_new にあります。

于 2010-06-16T05:27:07.397 に答える
1

これは Informix で機能し、必要な表示を正確に提供します。同じまたは類似のものがMySQLでも機能するはずです。ここでの秘訣は、すべての名前の結合を一時テーブルに取得し、その上で結合を残して、他の 2 つの値を比較できるようにすることです。

古いものから DISTINCT 名を選択
連合
SELECT DISTINCT name FROM new
INTO TEMP _tmp;

選択する
  CASE WHEN b.name IS NULL THEN ''
       ELSE aa.name
       END AS名、
  CASE WHEN b.version IS NULL THEN ''
       WHEN a.version = b.version THEN a.version
       ELSE b.バージョン
       END AS バージョン、
  CASE WHEN a.status = b.status THEN a.status
       WHEN b.status IS NULL THEN ''
       ELSE b.ステータス
       END AS ステータス、
  CASE WHEN a.lastupdate = b.lastupdate THEN a.lastupdate
       b.lastupdate IS NULL THEN null の場合
       ELSE b.lastupdate
       END AS 最終更新、
  CASE WHEN A.name IS NULL THEN '#new_added'
       b.name が NULL の場合、'#' || aa.name || 「エントリが削除されました」
       WHEN a.version b.version THEN '#version_updated'
       WHEN a.status b.status THEN '#status_updated'
       そうしないと ''
  END AS 変更
  FROM _tmp aa
  LEFT JOIN 古い a
         ON a.name = aa.name
  LEFT JOIN 新しい b
         ON b.name = aa.name;
于 2010-06-18T00:24:35.770 に答える
1

最後から始めましょう:

#4 では、tmp のすべての行を削除します。あなたの言いたいことはそこにありWHERE tmp.name NOT IN (SELECT name FROM new)ます; 同様に #3 は正しい構文ではありませんが、正しい構文である場合、すべての行を挿入しようとします。

#2に関しては、自動インクリメントを使用しないのはなぜIDですか?

#1に関しては、tmpテーブルが新しいものと同じ場合new、何らかの方法でテーブルを変更(更新、挿入、削除)しない限り、クエリ#2〜#4は意味がありません。

ただし(!)、テーブルnewを更新し、自動インクリメント フィールドがオンになっていて、アプリケーションからID( を使用して) テーブルを適切に更新している場合、ID手順全体は不要です (!)。

したがって、重要なことは、上記のように動作するようにシステムを設計しないことです。

アプリケーション側からデータベース内のデータを更新する概​​念を理解するには、こちら(php/mysql) の例を参照してください。

また、クエリで正しい構文を取得するには、基本バージョンの SET、INSERT、DELETE、および SELECT コマンドを使用します (これを回避する方法はありません)。

于 2010-06-08T07:51:13.273 に答える
0

2つのテーブルのコメントに基づいて必要なものをよく理解していれば、古いテーブルをマージまたは更新しない場合、必要なのはテーブルの新しいテーブルと古いテーブルのIDであるため、問題を大幅に簡略化できると思います。それらは存在し、存在しない場合は新しいIDですよね?

新しいレコード:テーブルnewにはすでに新しいレコードがあります-OK(ただし新しいIDが必要です)削除されたレコード:テーブルnewにはありません-OK更新されたレコード:テーブルnewですでに更新されています-OK(テーブルoldからIDをコピーする必要があります)変更されていないレコード:すでにテーブルにあります新しい-OK(古いテーブルからIDをコピーする必要があります)

したがって、実行する必要があるのは、(a)IDが存在する場合は古いテーブルから新しいテーブルにコピーする(b)古いテーブルに存在しない場合は新しいテーブルに新しいIDを作成する(c)新しいテーブルをコピーする古いテーブル。

(a)UPDATE new SET ID = IFNULL((SELECT ID FROM old WHERE new.name = old.name)、0);

(b)UPDATE new SET ID = FUNCTION_TO GENERATE_ID(new.name)WHERE ID = 0;

(c)古いテーブルを削除します。CREATE TABLE old(select * from new);

使用しているSQLデータベースがわからないので、(b)では、SQL関数を使用してデータベースに応じて一意のIDを生成できます。SQL Serverの場合、newid()、postgresqlの場合(古すぎないバージョン)、now()は精度が十分に見えるため、適切な選択のようです(ただし、MySQLなどの他のデータベースでは、精度が秒に制限されていると思います)。

編集:申し訳ありませんが、sqliteとpythonを使用しているのを見たことがありません。この場合、Pythonでstr(uuid.uuid4())関数(uuidモジュール)を使用してuuidを生成し、手順(b)でID=0の新しいテーブルにIDを入力できます。このようにして、IDで競合することなく、必要に応じて2つの独立したデータベースに参加できます。

于 2010-06-23T02:01:53.307 に答える
0

起草されたアプローチ、それがうまくいくかどうかはわかりません......

CREATE TRIGGER auto_next_id AFTER INSERT ON table FOR EACH ROW BEGIN UPDATE table SET uid = max(uid) + 1 ; 終わり;

于 2010-06-17T07:00:01.510 に答える
0

これにUUIDを使用しないのはなぜですか? プラグイン用に一度生成し、DB ではなくプラグインに組み込み/保持します。Pythonについて言及したので、それを生成する方法は次のとおりです。

import uuid
UID = str(uuid.uuid4()) # this will yield new UUID string

確かに、グローバルな一意性は保証されませんが、プロジェクトで同じ文字列を取得する可能性は非常に低くなります。

于 2010-06-25T19:54:57.980 に答える