私は単純な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
を実行している場合、内部クエリでそのテーブルを参照することはできません(youcanしかし、その外側のテーブルのフィールドを参照しています...)
この問題を解決するには、サブクエリのmyTable
のインスタンスを(SELECT * FROM myTable)
に置き換えます。
UPDATE myTable
SET myTable.A =
(
SELECT B
FROM (SELECT * FROM myTable) AS something
INNER JOIN ...
)
これにより、必要なフィールドが一時テーブルに暗黙的にコピーされるように見えるため、許可されています。
私はこの解決策 をここで見つけました 。その記事からのメモ:
実生活では、副照会の中に
SELECT * FROM table
だけを入れたくはありません。例を単純にしておきたかっただけです。実際には、その最も内側のクエリに必要な列を選択し、結果を制限するために適切なWHERE
句を追加するだけで済みます。
これは3つのステップで行うことができます。
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では、同じテーブルをサブクエリにして1つのテーブルを更新することはできません。
あなたは2つの部分にクエリを分けることができます
UPDATE TABLE_A AS A 内部結合TABLE_A AS B ON 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によって投稿されたアプローチは遅く、私はテーブルから重複を削除するために使っていたのでそれを修正しました。それが大きなテーブルを持っている人をだれでも助ける場合オリジナルクエリ
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;
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));
上記のコードは、condition-fieldが条件に一致したときに、fieldAからfieldBに値をコピーします。これはADOでも動作します(例:アクセス)
ソース:自分で試した
MariaDBはこれを10.3.xから引き上げました(DELETE
とUPDATE
の両方)。
UPDATE - 同じソースとターゲットを持つステートメント
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);
その他の回避策には、サブクエリでのSELECT DISTINCTまたはLIMITの使用が含まれますが、これらは具体化への影響がそれほど明確ではありません。これは私のために働いた