mysql 기반 sql 문에서 테이블 간 필드 값을 복사할 때 발생하는 몇 가지 문제

黄舟
풀어 주다: 2017-03-06 11:51:16
원래의
1186명이 탐색했습니다.

오랜만에 정원에 가보게 되었어요. 눈 깜짝할 새에 벌써 2017년 3월이 다가왔네요. 너무 부끄러워요. 어제 퇴근 전 기술사장이 갑자기 테이블 구조를 바꾸고 싶다고 말하며 한 테이블의 필드 값을 다른 테이블의 특정 필드에 복사할 수 있는지 물어봤습니다. 한 입이지만 실제로는 테이블 간 필드였습니다. 그래서 어젯밤에 야근을 하고 잠시 바이두를 검색한 뒤 로컬에서 테스트를 해보니 실제로 알아낸 내용이 있으니 참고삼아 이 SQL문을 적어보겠습니다.

1. 배경 및 요구 사항

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    |                      |
+--------+-------------+------+-----+---------+----------------+
로그인 후 복사

두 테이블 간의 관계: 테이블 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
로그인 후 복사


는 업데이트 문이 예상하는 데이터 소스 행의 수를 의미합니다. a_user 테이블과 동일해야 합니다. 행 수는 4인데 위 서브 쿼리의 결과는... 잠깐, 위 서브 쿼리가 실행될 수 있나요? 물론 그렇지 않습니다. 실제로 위 하위 쿼리는


select b_name from b_user left join a_user on a_id = id_a;
로그인 후 복사


와 동일합니다. 그러나 반환되는 결과는 8행입니다. a_user 테이블의 행 수가 다릅니다.

(1) 데이터 소스에서 중복 행 제거

그런 다음 이 문제를 먼저 해결하고 중복 레코드를 제거합니다. select 고유한 a_id, b_name from b_user left join a_user on a_id = id_a; 반환되는 결과는 다음과 같습니다.

+------+--------+
| a_id | b_name |
+------+--------+
|    1 | 张三   |
|    2 | 李四   |
|    3 | 王五   |
|    4 | 赵六   |
+------+--------+
로그인 후 복사

결과는 2개 열입니다. 다음 문을 실행하면 오류가 보고됩니다.


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)
로그인 후 복사


그럼 위 결과를 b_name만 포함하는 열로 변경하려면 어떻게 해야 할까요?

(2) Unique를 사용하여 a_id로 중복 행을 제거한 후 추가 a_id 열이 있습니다.

이 문제는 중첩으로 쉽게 해결할 수 있습니다. 하위 쿼리 한 번만 클릭하세요.


select b_name from (select distinct a_id, b_name from b_user left join a_user on a_id = id_a) t;
로그인 후 복사


좋아, 업데이트 문을 다시 시도해 보세요.


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
로그인 후 복사


위에서 서브쿼리 결과와 업데이트된 행 개수가 일치하지 않는 문제가 보고된 것을 볼 수 있는데, 위 서브쿼리 select b_name from (select distinct a_id, b_name from b_user left join a_user on a_id = id_a) t; 결과는

+--------+
| b_name |
+--------+
| 张三   |
| 李四   |
| 王五   |
| 赵六   |
+--------+
로그인 후 복사

중복 행이 제거되지 않았나요?

(3) 하위 쿼리 중첩 및 sql 문 실행 순서

위 문제를 분석합니다. 이제 select에 하위 쿼리가 두 개 있습니다. 문에서 외부 선택은 내부 선택을 쿼리할 데이터 소스로 사용합니다. 내부 선택과 외부 선택은 모두 별도로 실행될 때 예상된 결과를 반환할 수 있습니다. 그렇다면 업데이트를 실행할 때 왜 다음 오류가 발생합니까? >1242 (21000): 하위 쿼리 반환 1개 행 ?

다음은 내 추측입니다. 업데이트 문은 한 줄씩 실행되므로 첫 번째 레코드가 업데이트되면 업데이트는 선택 항목에서 첫 번째 레코드에 해당하는 레코드를 얻을 것으로 예상합니다. 기록된 데이터, 즉 update a_user set a_name = value source where id_a = a_id; 그러면 자격을 부여하기 위해 where 문을 추가해야 합니다:

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);
로그인 후 복사


그렇습니다.

+------+--------+
| id_a | a_name |
+------+--------+
|    1     | 张三   |
|    2     | 李四   |
|    3     | 王五   |
|    4     | 赵六   |
+------+--------+
로그인 후 복사

3. 먼저 여기에 결과를 써보겠습니다.

솔직히 아직은 불안해요. 여기에는 SQL 중첩 쿼리, SQL 문 실행 순서, 업데이트 문 실행 프로세스 및 기타 SQL 지식이 포함됩니다. 간단히 말해서 Baidu와 내 실수에 의존하여 SQL을 생각해 냈지만 로컬에서만 테스트하지 않았습니다. 프로덕션 환경에서 사용하기 위해 이 SQL의 실행 효율성에 대해서는 먼저 기록하고 나중에 연구하겠습니다. 데이터베이스를 전공하는 학생들이 조언을 해주셨으면 좋겠습니다.

위 내용은 mysql 내용을 기반으로 SQL 문에서 테이블 간의 필드 값을 복사할 때 발생하는 몇 가지 문제입니다. 더 많은 관련 내용은 PHP 중국어 홈페이지(www.php.cn)를 참고해주세요!


관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿