7

これの目的は、既存の行を上書きせずに、ある環境から別の環境にいくつかの行をコピーすることです。

サンプルDB:

INSERT INTO `school` (school_id,name) VALUES (15,'Middle');
INSERT INTO `class` (class_id,school_id,name) VALUES (12,15,'Sample');

アイデアは自動インクリメントでschool_idあり、に戻る外部キーリンクがあります。しかし、これらの行だけをダンプして、すでに15のある別のデータベースに挿入したいと思います。class_idclassschoolschool_id

次のようになります。

INSERT INTO `school` (name) VALUES ('Middle');
INSERT INTO `class` (school_id,name) VALUES (LAST_INSERT_ID(),'Sample');

しかし、それはこの単純な例の場合にすぎません。50のクラスがあり、それぞれに25人の生徒がいて、生徒とクラスの組み合わせごとに数百の成績があると想像してみてください。LAST_INSERT_ID()一連の変数に格納しないと、がどのように機能しないかを確認できます。

この種の操作を行うための適切なツールは何でしょうか?mysqldumpこれほど賢いことは何でもできますか?

4

7 に答える 7

4

あなたはこれを行うことができます:

  • school_idターゲットschoolテーブルでMAXを検索します-

    SELECT MAX(school_id) INTO @max_school_id FROM school;

  • school_idソーステーブルのすべての値を変更します( school、 )-前のポイントからclassMAXを追加します-school_id

    UPDATE school SET school_id = school_id + @max_school_id + 1;

外部キーにアクションを追加すると非常に便利な場合があります。子テーブルを自動的にON UPDATE CASCADE変更するのに役立ちます。例:-school_id

ALTER TABLE class
  DROP FOREIGN KEY FK_name;
ALTER TABLE class
  ADD CONSTRAINT FK_name FOREIGN KEY (school_id)
    REFERENCES school(school_id) ON UPDATE CASCADE;
  • ダンプを作成してインポートします。

説明と例:

ソーステーブルを作成します。

CREATE TABLE school(
  school_id INT PRIMARY KEY AUTO_INCREMENT,
  name VARCHAR(20)
);

INSERT INTO school (school_id, name) VALUES
  (1, 'Middle1'),
  (2, 'Middle2'),
  (3, 'Middle3'),
  (15, 'Middle');

CREATE TABLE class(
  class_id INT(11) NOT NULL,
  school_id INT(11) DEFAULT NULL,
  name VARCHAR(20) DEFAULT NULL,
  PRIMARY KEY (class_id),
  CONSTRAINT FK_class_school_school_id FOREIGN KEY (school_id)
  REFERENCES school (school_id) ON DELETE RESTRICT ON UPDATE CASCADE
)
ENGINE = INNODB;

INSERT INTO class (class_id, school_id, name) VALUES (11, 1, 'Sample1');
INSERT INTO class (class_id, school_id, name) VALUES (12, 15, 'Sample');

ターゲットテーブルを作成します。

CREATE TABLE school(
  school_id INT PRIMARY KEY AUTO_INCREMENT,
  name VARCHAR(20)
);

INSERT INTO school (school_id, name) VALUES
  (1, 'Top'),
  (2, 'Middle'),
  (3, 'Bottom'),
  (15, 'Top');

CREATE TABLE class(
  class_id INT(11) NOT NULL,
  school_id INT(11) DEFAULT NULL,
  name VARCHAR(20) DEFAULT NULL,
  PRIMARY KEY (class_id),
  CONSTRAINT FK_class_school_school_id FOREIGN KEY (school_id)
  REFERENCES school (school_id) ON DELETE RESTRICT ON UPDATE CASCADE
)
ENGINE = INNODB;

INSERT INTO class (class_id, school_id, name) VALUES (10, 2, 'Sample2');
INSERT INTO class (class_id, school_id, name) VALUES (12, 15, 'Sample');

ソーステーブルの更新、ID値の増分: すべての一意の値を更新する必要があります。この場合class_idclassテーブルとテーブルを更新する必要school_idがありschoolます。

class_idTARGETclassテーブルの最大値を見つける

SELECT MAX(class_id) + 1000 FROM class; -- This will return => 1012

すべてのSOURCEclass_id値をインクリメントしますclass_id + 1012

UPDATE class SET class_id = class_id + 1012;

school_idTARGETschoolテーブルの最大値を見つける

SELECT max(school_id) + 1000 FROM school; -- This will return =>1015

すべてのSOURCEschool_id値をインクリメントしますschool_id + 1015

UPDATE school SET school_id = school_id + 1015;

以上です。ソーステーブルをダンプできます。

INSERT INTO school VALUES
  (1016, 'Middle1'),
  (1017, 'Middle2'),
  (1018, 'Middle3'),
  (1030, 'Middle');

INSERT INTO class VALUES
  (1023, 1016, 'Sample1'),
  (1024, 1030, 'Sample');

これで、ターゲットデータベースに対してこのスクリプトを簡単に実行できます。

于 2012-04-20T07:53:05.483 に答える
2

SQLでこれを行う必要がありますか?最も基本的なETLツールでさえも適しています。代わりにpentahoまたはtalendを試してください。

于 2012-04-22T16:09:18.733 に答える
0

純粋なSQLソリューションが必要ない場合は、古いデータベースから読み取り、新しいデータベースに書き込むスクリプトを非常に簡単に作成できます。PHP、Python、Ruby、Perl、...を考えています。

mysqlを使用していて、データベース間でデータを移動していると仮定した場合のPHPの簡単なソリューションは次のとおりです(テストされていない、エラーが含まれている可能性があります)。

$dbh1 = new PDO("mysql:host=db1.host;dbname=db1", "user1", "pass1");
$dbh2 = new PDO("mysql:host=db2.host;dbname=db2", "user2", "pass2");

$sth1 = $dbh1->query("
    SELECT
        school.school_id as school_id,
        school.name as school_name, 
        class.name as class_name
    FROM school
    JOIN class ON (school.school_id = class.school_id)
");

$sth3 = $dbh2->prepare("INSERT INTO school (name) VALUES (:name)");
$sth4 = $dbh2->prepare("INSERT INTO class (school_id, name) VALUES (:school_id, :name)");

$schools = array();

// get schools and classes
while ($school = $sth1->fetch(PDO::FETCH_ASSOC)) {
    $school_id = $school['school_id'];
    $school_name = $school['school_name'];

    $schools[$school_id]['school_name'] = $school_name;

    $schools[$school_id]['classes'][] = array(
        'class_name' => $school['class_name']
    );
}

// insert schools and classes
foreach ($schools as $school_id => $school) {
    // insert school
    $sth3->bindParam(':name', $school['school_name'], PDO::PARAM_INT);
    $sth3->execute();

    $new_school_id = $dbh2->lastInsertId();

    // a loop for classes
    foreach ($school['classes'] as $class) {
        // insert class
        $sth4->bindParam(':school_id', $new_school_id, PDO::PARAM_INT);
        $sth4->bindParam(':name', $class['class_name'], PDO::PARAM_STR);

        $sth4->execute();
    }

    // a loop for another joined table
    /*
    foreach ($school['joined'] as $join) {
        // insert join
        $sth4->bindParam(':school_id', $new_school_id, PDO::PARAM_INT);
        $sth4->bindParam(':name', $join['join_name'], PDO::PARAM_STR);

        $sth4->execute();
    }
    */
}
于 2012-04-22T17:12:08.687 に答える
0

一時的なテーブル権限がある場合は、次のことができます。

CREATE TEMPORARY TABLE tmp_school LIKE school;
LOAD DATA LOCAL INFILE 'school.dat' INTO TABLE tmp_school;
CREATE TEMPORARY TABLE tmp_class LIKE class;
LOAD DATA LOCAL INFILE 'class.dat' INTO TABLE tmp_class;
INSERT INTO school (name) SELECT name FROM tmp_school;
INSERT INTO class (school_id,name) 
  SELECT school.school_id, class.name FROM school school JOIN tmp_school new
USING(name) JOIN tmp_class class ON new.school_id = class.school_id

これは正しいと思いますが、少し確認する必要があります。

于 2012-04-28T14:41:46.013 に答える
0

本当に簡単なトリックの1つは、IDに-1を掛けるだけです。負のIDは他のIDと同じくらい優れており、auto_increment列はとにかく正の数で始まると思います。

1つの環境からのエクスポート:

select -1*school_id, name from school into outfile 'school.out';
select -1*class_id, -1*school_id, name from class into outfile 'class.out';

秒にインポート:

load data infile 'school.out' into table school;
load data infile 'class.out' into table class;

明らかに、これはあなたの問題に対する一般的な解決策ではありませんが、どれくらいの頻度でそれが必要ですか?:)

一般的な解決策は、他の人が述べているように、ETLツールで、またはスタンドアロンスクリプトとして、移行ロジックを自分で作成することです。そして、そのツール/スクリプトを作成して、INFORMATION_SCHEMA.TABLESとINFORMATION_SCHEMA.COLUMNSを使用して、調整が必要なテーブルと列を動的に見つけます。

于 2012-04-29T12:02:17.050 に答える
0

転送からIDを削除するのが最善の方法だと思います。学校名が一意であると仮定すると、これは逸脱者のスキーマで機能するように見えます。簡単にするために、同じサーバー上に2つのデータベースがあります。

IDを使用せず、名前だけを使用して、データを新しいデータベースのテーブルにコピーします。

CREATE TEMPORARY TABLE tmp AS SELECT s.name as school_name, c.name as class_name
FROM test.school s JOIN test.class c USING(school_id);

新しい学校を学校のテーブルに追加します。

INSERT INTO school (name) SELECT DISTINCT school_name FROM tmp
LEFT JOIN school ON school_name = name WHERE name IS NULL;

新しいクラス(既存の学校と新しい学校の両方)をクラステーブルに追加します。

INSERT INTO class (name, school_id) SELECT class_name, school_id
FROM tmp t JOIN school s ON s.name = t.school_name;

ソース内の学校のターゲットデータベースに、そのクラスを持たないクラスがある場合、どのようなセマンティクスが必要ですか?これはユニオンです。削除する場合は変更する必要があります。

于 2012-04-29T14:09:28.977 に答える
0

このコマンドをphpで使用している場合は、挿入クエリの最後のIDを提供する単純な関数があります。つまり、mysql_insert_id()です。

コードは次のようになります:

<?php
    $query = mysql_query("INSERT INTO `school` (school_id,name) VALUES (15,'Middle')");
    $last_id = mysql_insert_id();
    INSERT INTO `class` (class_id,school_id,name) VALUES ('$last_id','Sample');
?>

他の言語で使用している場合、何をしなければならないかわかりません。

于 2012-04-29T14:10:46.900 に答える