Nie można określić tabeli docelowej dla aktualizacji w klauzuli FROM
Mam prostą tabelę 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);
Próbowałem uruchomić po aktualizacji, ale dostaję tylko błąd 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
))
Wyszukałem błąd i znalazłem z mysql po stronie http://dev.mysql.com/doc/refman/5.1/en/subquery-restrictions.html , ale to mi nie pomaga.
Co zrobić, aby poprawić zapytanie sql?
11 answers
Problem polega na tym, że MySQL, z jakiegokolwiek powodu, nie pozwala na pisanie zapytań takich jak:
UPDATE myTable
SET myTable.A =
(
SELECT B
FROM myTable
INNER JOIN ...
)
To znaczy, jeśli robisz UPDATE
/INSERT
/DELETE
w tabeli nie można odwoływać się do tej tabeli w zapytaniu wewnętrznym (można można jednak odwoływać się do pola z tej tabeli zewnętrznej...)
Rozwiązaniem jest zastąpienie instancji myTable
w zapytaniu podrzędnym przez (SELECT * FROM myTable)
, tak jak to
UPDATE myTable
SET myTable.A =
(
SELECT B
FROM (SELECT * FROM myTable) AS something
INNER JOIN ...
)
To najwyraźniej powoduje, że niezbędne pola są domyślnie skopiowane do tymczasowej tabeli, więc jest to dozwolone.
Znalazłem to rozwiązanie tutaj . Uwaga z tego artykułu:
Nie chcesz po prostu
SELECT * FROM table
w subquery w prawdziwym życiu; chciałem tylko, aby przykłady były proste. W rzeczywistości powinieneś wybrać tylko te kolumny, których potrzebujesz w tym najbardziej wewnętrznym zapytaniu, i dodać dobrą klauzulęWHERE
, aby ograniczyć wyniki.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-16 16:04:01
Możesz to zrobić w trzech krokach:
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;
Lub
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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-10 16:14:44
W Mysql, nie można zaktualizować jednej tabeli przez subquery tej samej tabeli.
Możesz rozdzielić zapytanie na dwie części, lub zrobić
UPDATE TABLE_A AS A INNER JOIN TABLE_A AS B ON A.field1 = B.field1 SET field2 = ?
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-31 02:42:20
Utwórz tymczasową tabelę (tempP) z zapytania podrzędnego
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
)
Wprowadziłem osobną nazwę (alias) i nadałem nową nazwę kolumnie 'persID' dla tymczasowej tabeli
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-09 20:42:56
To dość proste. Na przykład zamiast pisać:
INSERT INTO x (id, parent_id, code) VALUES (
NULL,
(SELECT id FROM x WHERE code='AAA'),
'BBB'
);
Powinieneś napisać
INSERT INTO x (id, parent_id, code)
VALUES (
NULL,
(SELECT t.id FROM (SELECT id, code FROM x) t WHERE t.code='AAA'),
'BBB'
);
Lub podobne.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-26 15:26:20
Podejście dodane przez BlueRaja jest powolne zmodyfikowałem je jako Używałem do usuwania duplikatów z tabeli. W przypadku, gdy pomoże to każdemu z dużymi stołami Oryginalne Zapytanie
delete from table where id not in (select min(id) from table group by field 2)
To zajmuje więcej czasu:
DELETE FROM table where ID NOT IN(
SELECT MIN(t.Id) from (select Id,field2 from table) AS t GROUP BY field2)
Faster Solution
DELETE FROM table where ID NOT IN(
SELECT x.Id from (SELECT MIN(Id) as Id from table GROUP BY field2) AS t)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-07 21:01:12
Jako odniesienie, Możesz również użyć zmiennych Mysql do zapisywania tymczasowych wyników, np.:
SET @v1 := (SELECT ... );
UPDATE ... SET ... WHERE x=@v1;
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-06 08:16:31
MariaDB podniósł to począwszy od 10.3.x (zarówno dla DELETE
jak i UPDATE
):
UPDATE - instrukcje z tym samym źródłem i celem
Od MariaDB 10.3.2, Instrukcje aktualizacji mogą mieć to samo źródło i cel.
Do MariaDB 10.3.1 następująca instrukcja aktualizacji nie będzie działać:
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
Od MariaDB 10.3.2 polecenie wykonuje się pomyślnie:
UPDATE t1 SET c1=c1+1 WHERE c2=(SELECT MAX(c2) FROM t1);
DELETE-to samo źródło i Tabela Docelowa
Do MariaDB 10.3.1 usunięcie z tabeli z tym samym źródłem i celem nie było możliwe. Od MariaDB 10.3.1 jest to teraz możliwe. Na przykład:
DELETE FROM t1 WHERE c1 IN (SELECT b.c1 FROM t1 b WHERE b.c2=0);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-23 17:40:22
Jeśli próbujesz odczytać fieldA z tableA i zapisać go na fieldB w tej samej tabeli, gdy fieldc = fieldd możesz chcieć to rozważyć.
UPDATE tableA,
tableA AS tableA_1
SET
tableA.fieldB= tableA_1.filedA
WHERE
(((tableA.conditionFild) = 'condition')
AND ((tableA.fieldc) = tableA_1.fieldd));
Powyższy kod kopiuje wartość z fieldA do fieldB, gdy warunek-pole spełnia Twój warunek. działa to również w ADO (np. access)
Źródło: wypróbowałem siebie
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-08 09:37:44
MySQL nie pozwala na wybór z tabeli i aktualizację w tej samej tabeli w tym samym czasie. Ale zawsze jest obejście:)
To nie działa.>>>>
UPDATE table1 SET col1 = (SELECT MAX(col1) from table1) WHERE col1 IS NULL;
Ale to działa >>>>
UPDATE table1 SET col1 = (SELECT MAX(col1) FROM (SELECT * FROM table1) AS table1_new) WHERE col1 IS NULL;
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-15 04:44:52
Inne obejścia obejmują użycie SELECT DISTINCT lub LIMIT w zapytaniu podrzędnym, chociaż nie są one tak wyraźne w ich wpływie na materializację. this worked for me
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-08-26 06:51:00