테이블의 모든 행을 어떻게 반복 할 수 있습니까? (MySQL)


88

테이블 A가 있고 하나의 기본 키 ID가 있습니다.

이제 A의 모든 행을 살펴 보겠습니다.

'A의 각 레코드마다'와 같은 것을 찾았지만 이것은 MySQL에서 수행하는 방식이 아닌 것 같습니다.

필드를 가져 와서 변환하고 다른 테이블에 삽입 한 다음 행의 일부 필드를 업데이트하려는 각 행에 대한 것입니다. 선택 부분과 삽입을 하나의 문에 넣을 수 있지만 거기에 업데이트를 얻는 방법도 모르겠습니다. 그래서 반복하고 싶습니다. 그리고 연습을 위해 MySQL 이외의 다른 것을 사용하고 싶지 않습니다.

편집하다

예를 들어 감사하겠습니다.

그리고 절차에 넣을 필요가없는 솔루션.

편집 2

이 시나리오를 생각해보십시오.

각각 필드 ID 및 VAL이있는 테이블 A 및 B.

이제 이것은 내가 원하는 일에 대한 의사 코드입니다.

for(each row in A as rowA)
{
  insert into B(ID, VAL) values(rowA[ID], rowA[VAL]);
}

기본적으로 루프를 사용하여 A의 내용을 B로 복사합니다.

(이것은 단순한 예제 일뿐입니다. 물론 루프를 사용하지 않을 것입니다.)}


안녕하세요 Rafeel은 다음과 같은 오류를 제공합니다. My SQL> for (wp_mobiune_ecommune_user의 각 행을 x로) {insert into wp_mobiune_ecommune_user (gender_new) values ​​(x [gender])}; RROR 1064 (42000) : SQL 구문에 오류가 있습니다. MySQL 서버 버전에 해당하는 설명서에서 'for (wp_mobiune_ecommune_user의 각 행을 x로) {insert into wp_mobiune_ecommune'at line 1
dinesh kandpal

답변:


134

루프의 제안은 프로 시저 유형 솔루션에 대한 요청을 의미하기 때문에. 여기 내 꺼야.

테이블에서 가져온 단일 레코드에 대해 작동하는 쿼리는 다음과 같이 테이블의 각 행을 통해 실행되도록 프로 시저로 래핑 될 수 있습니다.

DROP PROCEDURE IF EXISTS ROWPERROW;
DELIMITER ;;

다음은 귀하의 예에 따른 절차입니다 (명확성을 위해 table_A 및 table_B 사용)

CREATE PROCEDURE ROWPERROW()
BEGIN
DECLARE n INT DEFAULT 0;
DECLARE i INT DEFAULT 0;
SELECT COUNT(*) FROM table_A INTO n;
SET i=0;
WHILE i<n DO 
  INSERT INTO table_B(ID, VAL) SELECT (ID, VAL) FROM table_A LIMIT i,1;
  SET i = i + 1;
END WHILE;
End;
;;

그런 다음 구분 기호를 재설정하는 것을 잊지 마십시오

DELIMITER ;

그리고 새로운 절차를 실행하십시오.

CALL ROWPERROW();

예제 요청에서 단순히 복사 한 "INSERT INTO"줄에서 원하는대로 할 수 있습니다.

여기에 사용 된 "INSERT INTO"행은 질문의 행을 미러링합니다. 이 답변에 대한 설명에 따라 쿼리가 실행중인 SQL 버전에 대해 구문 상 올바른지 확인해야합니다.

ID 필드가 증가하고 1에서 시작하는 간단한 경우 예제의 행은 다음과 같을 수 있습니다.

INSERT INTO table_B(ID, VAL) VALUES(ID, VAL) FROM table_A WHERE ID=i;

"SELECT COUNT"줄을

SET n=10;

table_A의 처음 10 개 레코드에서만 쿼리를 테스트 할 수 있습니다.

마지막 한가지. 이 프로세스는 또한 여러 테이블에 걸쳐 중첩하기가 매우 쉽고 부모 테이블의 각 행에서 새 테이블에 다른 수의 레코드를 동적으로 삽입하는 프로세스를 하나의 테이블에서 수행 할 수있는 유일한 방법이었습니다.

더 빨리 실행해야하는 경우에는 기반으로 설정하도록하십시오. 그렇지 않으면 괜찮습니다. 위의 내용을 커서 형태로 다시 작성할 수도 있지만 성능이 향상되지 않을 수 있습니다. 예 :

DROP PROCEDURE IF EXISTS cursor_ROWPERROW;
DELIMITER ;;

CREATE PROCEDURE cursor_ROWPERROW()
BEGIN
  DECLARE cursor_ID INT;
  DECLARE cursor_VAL VARCHAR;
  DECLARE done INT DEFAULT FALSE;
  DECLARE cursor_i CURSOR FOR SELECT ID,VAL FROM table_A;
  DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
  OPEN cursor_i;
  read_loop: LOOP
    FETCH cursor_i INTO cursor_ID, cursor_VAL;
    IF done THEN
      LEAVE read_loop;
    END IF;
    INSERT INTO table_B(ID, VAL) VALUES(cursor_ID, cursor_VAL);
  END LOOP;
  CLOSE cursor_i;
END;
;;

쿼리 된 테이블의 것과 동일한 유형으로 사용할 변수를 선언해야합니다.

내 조언은 가능하면 setbased 쿼리를 사용하고 필요한 경우 간단한 루프 또는 커서 만 사용하는 것입니다.


2
INSERT INTO table_B (ID, VAL) VALUES (ID, VAL) FROM table_A LIMIT i, 1; 구문 오류를 제공합니다.
Jonathan

1
'DECLARE done INT DEFAULT FALSE;'가 누락 된 것 같습니다. cursor_i 선언 후
ErikL 2014 년

1
done 속성이 true로 설정된 곳은 어디에 배치해야합니까? 아니면 mysql 커서가 자동으로 사용하는 예약어입니까?
IgniteCoders 2015-10-29

1
INSERT INTO 호출은 SQL 5.5부터 구문 오류를 발생시킵니다. 올바른 호출은 INSERT INTO table_B (ID, VAL) SELECT (ID, VAL) FROM table_A WHERE ID = i입니다.
Ambar

이것은 평생 걸릴 수 있으므로 제한 및 증가를 변경하여 1000 일괄 처리 크기를 증가하려고합니다 : LIMIT i,1000;set i = i + 1000;
Alan Deep

16

두 개의 쿼리 (기본 삽입)를 포함하는 집합 기반 솔루션을 실제로 사용해야합니다.

INSERT INTO TableB (Id2Column, Column33, Column44)
SELECT id, column1, column2 FROM TableA

UPDATE TableA SET column1 = column2 * column3

그리고 변형을 위해 :

INSERT INTO TableB (Id2Column, Column33, Column44)
SELECT 
    id, 
    column1 * column4 * 100, 
    (column2 / column12) 
FROM TableA

UPDATE TableA SET column1 = column2 * column3

이제 변환이 그보다 복잡하고 여러 테이블이 포함 된 경우 세부 정보와 함께 다른 질문을 게시하십시오.


예를 들어 +1. 이것이 내 현장에서 적용 가능한지 의심 스럽지만 나중에 업데이트는 삽입과 관련이 있으며 특히 선택한 행이 특정 삽입을 유발합니다. 이것이 내가 루프를 제안한 이유이므로 각 행에 대해 개별적으로 선택 / 삽입 / 업데이트를 수행 할 수 있습니다.
Raffael 2011-04-28

2
@ Raffael1984 : "특정 삽입을 유발하는 특정 행"에 대한 조건을 추가하도록 질문을 편집하면 도움을 드릴 수 있습니다. 커서 / 루프 경로로 가고 싶지는 않습니다. 매우 비효율적입니다.
Raj More

오 글쎄요 ... 당신은 내가 세트 기반 쿼리 방식으로 가면 더 좋을 것임을 알고 있습니다! 그러나 내 질문이 학문적 관심에 더 가깝기 때문에 효율성은 여기에서 동기가 아닙니다. 테이블은 내가 손으로 할 수있을 정도로 작습니다. 루프 버전을 정말 감사하겠습니다. 누군가가 세트 기반 스타일로 나를 도울 수 있도록 더 자세한 정보를 제공하는 문제를 다시 게시 할 수 있습니다.
Raffael 2011-04-28

@RajMore에 동의하고, 커서 / 루프는 비효율적입니다. 아래는 참조 용 커서 성능에 대한 2 개의 링크입니다. 1. rpbouman.blogspot.tw/2006/09/refactoring-mysql-cursors.html 2. stackoverflow.com/questions/11549567/ …
Browny Lin

@RajMore 내 질문에
Nurav

4

CURSORS는 여기에서 옵션이지만 쿼리 엔진을 가장 잘 사용하지 않는 경우가 많기 때문에 일반적으로 눈살을 찌푸립니다. CURSOR를 사용하지 않고 원하는 작업을 수행 할 수 있는지 확인하려면 'SET 기반 쿼리'를 조사해보십시오.


집합 기반 쿼리에 대한 정보를 많이 찾을 수 없습니다. 그러나 나는 당신이 일종의 진술에 대한 선택을 의미한다고 생각합니다. 문제는 업데이트를 실행해야한다는 것입니다.
Raffael 2011-04-28

0

MySQL 트리거에서 사용한 Mr Purple의 예는

begin
DECLARE n INT DEFAULT 0;
DECLARE i INT DEFAULT 0;
Select COUNT(*) from user where deleted_at is null INTO n;
SET i=0;
WHILE i<n DO 
  INSERT INTO user_notification(notification_id,status,userId)values(new.notification_id,1,(Select userId FROM user LIMIT i,1)) ;
  SET i = i + 1;
END WHILE;
end

2
솔루션 작동 방식에 대한 정보를 추가해 주시겠습니까?
TheTanic

-24
    Use this:

    $stmt = $user->runQuery("SELECT * FROM tbl WHERE ID=:id");
    $stmt->bindparam(":id",$id);
    $stmt->execute();

        $stmt->bindColumn("a_b",$xx);
        $stmt->bindColumn("c_d",$yy);


    while($rows = $stmt->fetch(PDO::FETCH_BOUND))
    {
        //---insert into new tble
    }   
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.