Programing

FROM 절에서 업데이트 대상 테이블을 지정할 수 없습니다

lottogame 2020. 3. 2. 13:00
반응형

FROM 절에서 업데이트 대상 테이블을 지정할 수 없습니다


간단한 mysql 테이블이 있습니다.

CREATE TABLE IF NOT EXISTS `pers` (
  `persID` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(35) NOT NULL,
  `gehalt` int(11) NOT NULL,
  `chefID` int(11) DEFAULT NULL,
  PRIMARY KEY (`persID`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;

INSERT INTO `pers` (`persID`, `name`, `gehalt`, `chefID`) VALUES
(1, 'blb', 1000, 3),
(2, 'as', 1000, 3),
(3, 'chef', 1040, NULL);

다음 업데이트를 실행하려고했지만 오류 1093 만 발생합니다.

UPDATE pers P 
SET P.gehalt = P.gehalt * 1.05 
WHERE (P.chefID IS NOT NULL 
OR gehalt < 
(SELECT (
    SELECT MAX(gehalt * 1.05) 
    FROM pers MA 
    WHERE MA.chefID = MA.chefID) 
    AS _pers
))

오류를 검색하고 mysql 다음 페이지 http://dev.mysql.com/doc/refman/5.1/en/subquery-restrictions.html 에서 찾았 지만 도움이되지 않습니다.

SQL 쿼리를 수정하려면 어떻게해야합니까?


문제는 MySQL이 미친 이유가 무엇이든 다음과 같은 쿼리를 작성할 수 없다는 것입니다.

UPDATE myTable
SET myTable.A =
(
    SELECT B
    FROM myTable
    INNER JOIN ...
)

즉, 테이블에서 UPDATE/ INSERT/ DELETE수행하는 경우 내부 쿼리에서 해당 테이블을 참조 할 수 없습니다 ( 그러나 외부 테이블에서 필드를 참조 수는 있습니다 ...)


용액의 인스턴스를 대체하는 것이다 myTable와 서브 쿼리 (SELECT * FROM myTable)같이,

UPDATE myTable
SET myTable.A =
(
    SELECT B
    FROM (SELECT * FROM myTable) AS something
    INNER JOIN ...
)

이로 인해 필요한 필드가 임시 테이블에 내재적으로 복사되므로 허용됩니다.

이 솔루션을 여기 에서 찾았 습니다 . 그 기사의 메모 :

SELECT * FROM table실제 쿼리에서는 하위 쿼리 만 수행하고 싶지 않습니다 . 예제를 단순하게 유지하고 싶었습니다. 실제로 가장 안쪽 쿼리에 필요한 열만 선택 WHERE하고 결과를 제한 하는 좋은 절을 추가해야합니다 .


세 단계로이 작업을 수행 할 수 있습니다.

CREATE TABLE test2 AS
SELECT PersId 
FROM pers p
WHERE (
  chefID IS NOT NULL 
  OR gehalt < (
    SELECT MAX (
      gehalt * 1.05
    )
    FROM pers MA
    WHERE MA.chefID = p.chefID
  )
)

...

UPDATE pers P
SET P.gehalt = P.gehalt * 1.05
WHERE PersId
IN (
  SELECT PersId
  FROM test2
)
DROP TABLE test2;

또는

UPDATE Pers P, (
  SELECT PersId
  FROM pers p
  WHERE (
   chefID IS NOT NULL 
   OR gehalt < (
     SELECT MAX (
       gehalt * 1.05
     )
     FROM pers MA
     WHERE MA.chefID = p.chefID
   )
 )
) t
SET P.gehalt = P.gehalt * 1.05
WHERE p.PersId = t.PersId

MySQL에서는 동일한 테이블을 하위 쿼리하여 하나의 테이블을 업데이트 할 수 없습니다.

쿼리를 두 부분으로 분리하거나

 업데이트 TABLE_A AS A
 내부 조인 TABLE_A B에서 B로 A.field1 = B.field1
 SET field2 =? 

하위 쿼리에서 임시 테이블 (tempP) 만들기

UPDATE pers P 
SET P.gehalt = P.gehalt * 1.05 
WHERE P.persID IN (
    SELECT tempP.tempId
    FROM (
        SELECT persID as tempId
        FROM pers P
        WHERE
            P.chefID IS NOT NULL OR gehalt < 
                (SELECT (
                    SELECT MAX(gehalt * 1.05) 
                    FROM pers MA 
                    WHERE MA.chefID = MA.chefID) 
                    AS _pers
                )
    ) AS tempP
)

별도의 이름 (별칭)을 도입했으며 임시 테이블의 'persID'열에 새로운 이름을 지정했습니다.


아주 간단합니다. 예를 들어, 쓰는 대신 :

INSERT INTO x (id, parent_id, code) VALUES (
    NULL,
    (SELECT id FROM x WHERE code='AAA'),
    'BBB'
);

당신은 작성해야합니다

INSERT INTO x (id, parent_id, code)
VALUES (
    NULL,
    (SELECT t.id FROM (SELECT id, code FROM x) t WHERE t.code='AAA'),
    'BBB'
);

또는 유사합니다.


BlueRaja가 게시 한 접근법은 느리게 테이블에서 중복을 삭제하는 데 사용하면서 수정했습니다. 큰 테이블을 가진 사람에게 도움이되는 경우 Original Query

delete from table where id not in (select min(id) from table group by field 2)

시간이 더 걸립니다 :

DELETE FROM table where ID NOT IN(
  SELECT MIN(t.Id) from (select Id,field2 from table) AS t GROUP BY field2)

빠른 솔루션

DELETE FROM table where ID NOT IN(
   SELECT x.Id from (SELECT MIN(Id) as Id from table GROUP BY field2) AS t)

참고로 Mysql 변수를 사용하여 임시 결과를 저장할 수도 있습니다.

SET @v1 := (SELECT ... );
UPDATE ... SET ... WHERE x=@v1;

https://dev.mysql.com/doc/refman/5.7/en/user-variables.html


tableA에서 fieldA를 읽고 같은 테이블의 fieldB에 저장하려는 경우 fieldc = fieldd 일 때이를 고려할 수 있습니다.

UPDATE tableA,
    tableA AS tableA_1 
SET 
    tableA.fieldB= tableA_1.filedA
WHERE
    (((tableA.conditionFild) = 'condition')
        AND ((tableA.fieldc) = tableA_1.fieldd));

위의 코드는 조건 필드가 조건을 충족하면 필드 A에서 필드 B로 값을 복사합니다. 이것은 ADO에서도 작동합니다 (예 : 액세스)

출처 : 나 자신을 시도


MariaDB는 10.3.x ( DELETEUPDATE) 에서 이것을 시작했습니다 .

업데이트-소스 및 대상이 동일한 명령문

MariaDB 10.3.2부터 UPDATE 문은 동일한 소스 및 대상을 가질 수 있습니다.

MariaDB 10.3.1까지는 다음 UPDATE 문이 작동하지 않습니다.

UPDATE t1 SET c1=c1+1 WHERE c2=(SELECT MAX(c2) FROM t1);
  ERROR 1093 (HY000): Table 't1' is specified twice, 
  both as a target for 'UPDATE' and as a separate source for data

MariaDB 10.3.2부터 명령문이 성공적으로 실행됩니다.

UPDATE t1 SET c1=c1+1 WHERE c2=(SELECT MAX(c2) FROM t1);

삭제-동일한 소스 및 대상 테이블

MariaDB 10.3.1까지는 소스와 대상이 같은 테이블에서 삭제할 수 없었습니다. MariaDB 10.3.1부터는 이것이 가능합니다. 예를 들면 다음과 같습니다.

DELETE FROM t1 WHERE c1 IN (SELECT b.c1 FROM t1 b WHERE b.c2=0);

DBFiddle MariaDB 10.2-오류

DBFiddle MariaDB 10.3-성공


다른 해결 방법은 하위 쿼리에서 SELECT DISTINCT 또는 LIMIT를 사용하는 것을 포함하지만, 구체화에 미치는 영향은 명시 적이 지 않습니다. 이것은 나를 위해 일했다

MySql Doc에서 언급했듯이


x 업데이트 set available_material_id = id가없는 경우 null (add_info = 1 인 경우 x에서 id 선택);

-- use left join ----
update x left join
       x xx
       on x.id = xx.id and xx.additional_info = 1
    set available_material_id = null
    where xx.id is null;

참고 : https://stackoverflow.com/questions/4429319/you-cant-specify-target-table-for-update-in-from-clause



반응형