しばらく庭に行っていなかったので、あっという間に2017年も3月になってしまいましたが、最近は忙しくてブログも書けず(実は怠け者です)、そんな感じです。恥ずかしい。昨日、退勤前に技術担当の上司が突然テーブル構造を変更したいと言い、あるテーブルのフィールド値を別のテーブルの特定のフィールドにコピーできるかどうか尋ねてきました。ほんの一口ですが、実際にはテーブル間の値のコピーでした。ということで、昨夜残業してBaiduを少し検索してローカルで試してみたので、備忘録としてこのSQL文を書き留めておきます。
1、背景と要件
2 つのテーブル a_user と b_user の構造は次のとおりです:
a_user
+--------+-------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +--------+-------------+------+-----+---------+----------------+ | id_a | int(11) | NO | PRI | NULL | auto_increment| | a_name| varchar(45)| YES | | NULL | | +--------+-------------+------+-----+---------+----------------+
b_user
+--------+-------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +--------+-------------+------+-----+---------+----------------+ | id_b | int(11) | NO | PRI | NULL |auto_increment| | a_id | int(11) | NO | MUL | NULL | | | b_name| varchar(45)| YES | | NULL | | +--------+-------------+------+-----+---------+----------------+
2 つのテーブル間の関係: テーブル b_user の a_id 外部キーテーブル a_user の主キー id_a を参照します。
レコードは次のとおりです:
a_user
+------+--------+ | id_a | a_name | +------+--------+ | 1 | | | 2 | | | 3 | | | 4 | | +------+--------+
b_user
+------+------+--------+ | id_b | a_id | b_name | +------+------+--------+ | 1 | 1 | 张三 | | 2 | 2 | 李四 | | 3 | 2 | 李四 | | 4 | 3 | 王五 | | 5 | 3 | 王五 | | 6 | 3 | 王五 | | 7 | 4 | 赵六 | | 8 | 4 | 赵六 | +------+------+--------+
要件: b_user テーブルの b_name フィールドの値を a_user テーブルの a_name にコピーします。
2、Baidu で発生した問題を解決してください
Baidu、この SQL ステートメントがより信頼できることがわかりました:
update a_user set a_name = (select b_name from b_user where id_a = a_id);
このステートメントは、おそらくテーブル a_user フィールドの a_name の更新を参照しています。テーブル b_user の b_name フィールドの値が値のソースとして使用されますが、上記のステートメントが直接実行されると、mysql は次のようにエラーを報告します:
ERROR 1242 (21000): Subquery returns more than 1 row
これは、update ステートメントが期待していることを意味します。データソースの行数は a_user テーブルと同じになります。 4 の行数は同じですが、上記のサブクエリの結果は...、待て、上記のサブクエリは実行できますか?もちろん違います。実際、上記のサブクエリは
select b_name from b_user left join a_user on a_id = id_a;
と同等ですが、返される結果は 8 行であり、テーブル a_user の行数とは異なります。
(1) データソースから重複行を削除します
次に、最初にこの問題を解決し、重複レコードを削除します: select distinct a_id, b_name from b_user left jo でa_user on a_id = id_a; 返される結果は次のとおりです。
+------+--------+ | a_id | b_name | +------+--------+ | 1 | 张三 | | 2 | 李四 | | 3 | 王五 | | 4 | 赵六 | +------+--------+
次のステートメントを実行すると、エラーが報告されます。では、上記の結果が b_name のみを含む列になったらどうなるでしょうか?
これは簡単に解決できます。サブクエリを再度ネストするだけです。もう一度 update ステートメントを試してみます
1 update a_user set a_name = (select distinct a_id, b_name from b_user left join a_user on a_id = id_a);
2 ERROR 1241 (21000): Operand should contain 1 column(s)
奇妙なことに、上記のサブクエリ
select
b_name
(
select
) は、サブクエリの結果が上記で報告された更新された行の数と一致していないことがわかります。 unique
a_id, b_namefrom
b_user
join
on a_id = id_a) t; 結果は次のようになります: select b_name from (select distinct a_id, b_name from b_user left join a_user on a_id = id_a) t;
重複行は削除されていませんか? (3) サブクエリのネストと SQL ステートメントの実行シーケンス 上記の問題を分析してください: ここで、外側の select ステートメントは、クエリするためのデータ ソースとして内側の select ステートメントを使用します。そして、外側の選択は個別に実行すると期待される結果を返すことができるのに、更新の実行時に次のように表示されるのはなぜですか: ERROR 1242 (21000): Subquery
more than
1row ?
以下は私の推測です: update ステートメントは行ごとに実行されるため、最初のレコードが更新されると、update は select サブクエリから最初のレコードに対応するデータを取得することを期待します。つまり、update です。 a_user set a_name = value source where id_a = a_id; 次に、修飾するために where ステートメントを追加する必要があります: 1 update a_user set a_name = (select b_name from (select distinct a_id, b_name from b_user left join a_user on a_id = id_a) t);
2 ERROR 1242 (21000): Subquery returns more than 1 row
これで、結果は次のようになります:
+--------+ | b_name | +--------+ | 张三 | | 李四 | | 王五 | | 赵六 | +--------+
3、結果を書きましょう
まずここに、最後の文は
update a_user set a_name = (select b_name from (select distinct a_id, b_name from b_user left join a_user on a_id = id_a) t where t.a_id = id_a);
正直に言うと、まだ不安です。これには、SQL のネストされたクエリ、SQL ステートメントの実行シーケンス、更新ステートメントの実行プロセス、およびその他の SQL の知識が含まれます。つまり、私は Baidu と自分の間違いに頼って SQL を作成しましたが、ローカルでテストしただけで、テストしませんでした。実稼働環境で使用する場合、この SQL の実行効率についてはわかりません。最初に記録を作成し、後で検討します。データベースを専門とする学生の方からアドバイスをいただければ幸いです。
上記は、SQL ステートメント内のテーブル間でフィールド値をコピーする際に発生するいくつかの問題です。これは、mysql の内容に基づいています。その他の関連コンテンツについては、PHP 中国語 Web サイト (www.php.cn) に注目してください。