столбец обновления mysql со значением из select case [duplicate]

NullPointerException s - исключения, возникающие при попытке использовать ссылку, которая указывает на отсутствие местоположения в памяти (null), как если бы она ссылалась на объект. Вызов метода по нулевой ссылке или попытка получить доступ к полю нулевой ссылки вызовет функцию NullPointerException. Они наиболее распространены, но другие способы перечислены на странице NullPointerException javadoc.

Вероятно, самый быстрый пример кода, который я мог бы придумать для иллюстрации NullPointerException, be:

public class Example {

    public static void main(String[] args) {
        Object obj = null;
        obj.hashCode();
    }

}

В первой строке внутри main я явно устанавливаю ссылку Object obj равной null. Это означает, что у меня есть ссылка, но она не указывает на какой-либо объект. После этого я пытаюсь обработать ссылку так, как если бы она указывала на объект, вызывая метод на нем. Это приводит к NullPointerException, потому что нет кода для выполнения в местоположении, на которое указывает ссылка.

(Это техничность, но я думаю, что она упоминает: ссылка, которая указывает на null, равна 't то же, что и указатель C, указывающий на недопустимую ячейку памяти. Нулевой указатель буквально не указывает на в любом месте , который отличается от указаний на местоположение, которое оказывается недопустимым.)

468
задан shA.t 31 May 2015 в 09:35
поделиться

14 ответов

Обновление: этот ответ охватывает общую классификацию ошибок. Более подробный ответ о том, как лучше всего обрабатывать точный запрос OP, см. В других ответах на этот вопрос

. В MySQL вы не можете изменить ту же таблицу, которую используете в SELECT часть. Это поведение задокументировано по адресу: http://dev.mysql.com/doc/refman/5.6/en/update.html

Возможно, вы можете просто присоединиться к таблице самим себе

Если логика достаточно простая, чтобы переформатировать запрос, потеряйте подзапрос и присоединитесь к таблице, используя соответствующие критерии выбора. Это заставит MySQL видеть таблицу как две разные вещи, позволяя деструктивным изменениям идти вперед.

UPDATE tbl AS a
INNER JOIN tbl AS b ON ....
SET a.col = b.col

Альтернативно, попробуйте вложить подзапрос глубже в предложение from ...

Если вам абсолютно необходим подзапрос, есть обходной путь, но он уродлив по нескольким причинам, включая производительность:

UPDATE tbl SET col = (
  SELECT ... FROM (SELECT.... FROM) AS x);

Вложенный подзапрос в предложении FROM создает неявную временную таблицу , поэтому он не считается той же таблицей, которую вы обновляете.

... но следите за оптимизатором запросов

Однако будьте осторожны, что из MySQL 5.7.6 и далее оптимизатор может оптимизировать подзапрос , и все еще дают вам ошибку. К счастью, переменную optimizer_switch можно использовать для отключения этого поведения; хотя я не мог рекомендовать делать это как нечто большее, чем краткосрочное исправление, или для небольших одноразовых задач.

SET optimizer_switch = 'derived_merge=off';

Благодаря Peter V. Mørch для этого совета в комментариях.

Примерный метод был от барона Шварца, , первоначально опубликованного в Nabble , перефразированного и расширенного здесь.

599
ответ дан Community 19 August 2018 в 13:28
поделиться
  • 1
    Упрощенный этот ответ, потому что мне пришлось удалять элементы и не мог получить информацию из другой таблицы, приходилось подзапрос из той же таблицы. Так как это то, что всплывает наверху при поиске в Google для ошибки, я понял, что это лучший ответ для меня и многих людей, пытающихся обновить, в то время как subquerieing из той же таблицы. – HMR 12 December 2012 в 05:36
  • 2
  • 3
    Остерегайтесь, что из MySQL 5.7.6 на оптимизатор может оптимизировать суб-запрос и все равно дать вам ошибку, если вы не SET optimizer_switch = 'derived_merge=off'; :-( – Peter V. Mørch 6 November 2015 в 16:36
  • 4
    @ PeterV.Mørch После mysqlserverteam.com/derived-tables-in-mysql-5-7 , в случае выполнения определенных операций слияния не может произойти. Например. предоставить полученную фиктивную таблицу с помощью LIMIT (до минимального значения), и ошибка никогда не произойдет. Это довольно хаки, хотя и по-прежнему существует риск того, что будущие версии MySQL будут поддерживать слияние запросов с LIMIT в конце концов. – user2180613 18 August 2016 в 18:59
  • 5
    лол! большой маленький взлом! – Diego Aguado 6 January 2017 в 00:59

NexusRex предоставил очень хорошее решение для удаления с соединением из той же таблицы.

Если вы это сделаете:

DELETE FROM story_category
WHERE category_id NOT IN (
        SELECT DISTINCT category.id AS cid FROM category 
        INNER JOIN story_category ON category_id=category.id
)

вы получите ошибку.

Но если вы завернете условие в еще один select

DELETE FROM story_category
WHERE category_id NOT IN (
    SELECT cid FROM (
        SELECT DISTINCT category.id AS cid FROM category 
        INNER JOIN story_category ON category_id=category.id
    ) AS c
)

, он поступил бы правильно!

Объяснение: Оптимизатор запросов выполняет полученную оптимизацию слияния для первого запроса (что приводит к сбою с ошибкой), но второй запрос не подходит для оптимизация слияния , поэтому оптимизатор вынужден сначала выполнить подзапрос.

213
ответ дан ADTC 19 August 2018 в 13:28
поделиться
  • 1
    Может быть, это потому, что сегодня я на связи, но это был самый легкий ответ, даже если это, возможно, не «лучший». один. – Tyler V. 6 September 2014 в 00:13
  • 2
    Это отлично поработало, спасибо! Так в чем тут логика? Если он вложен еще на один уровень, он будет выполнен перед внешней частью? И если он не вложен, mySQL пытается запустить его после удаления блокировки на столе? – Flat Cat 14 December 2014 в 17:40
  • 3
    Эта ошибка и решение не имеют логического смысла ... но это работает. Иногда мне интересно, какие наркотики работают в MySQL dev ... – Cerin 16 December 2015 в 18:01
  • 4
    Согласитесь с @Cerin .. это совершенно абсурдно, но оно работает. – FastTrack 28 June 2017 в 15:44
  • 5
    @ekonoval Спасибо за решение, но это не делает для меня минимальным, похоже, что вы обманываете MySQL, и он принимает его, LOL – deFreitas 24 July 2017 в 16:59

Недавно мне пришлось обновлять записи в той же таблице, я сделал это, как показано ниже:

UPDATE skills AS s, (SELECT id  FROM skills WHERE type = 'Programming') AS p
SET s.type = 'Development' 
WHERE s.id = p.id;
82
ответ дан Andy 19 August 2018 в 13:28
поделиться
  • 1
    Разве это не может быть написано как UPDATE skills SET type='Development' WHERE type='Programming';? Это, похоже, не отвечает на исходный вопрос. – lilbyrdie 30 May 2014 в 16:23
  • 2
    Кажется, что излишний, @lilbyrdie правильный - это может быть только UPDATE skills SET type='Development' WHERE type='Programming';. Я не понимаю, почему так много людей не думают о том, что они делают ... – shadyyx 5 December 2014 в 11:00
  • 3
    это лучший ответ здесь, ИМХО. Синтаксис легко понять, вы можете повторно использовать свое предыдущее утверждение, и это не ограничивается некоторым конкретным случаем. – Steffen Winkler 7 September 2015 в 14:28
  • 4
    Временная таблица работала как прелесть для меня. Ницца. – Ligemer 18 July 2016 в 22:19
  • 5
    Даже если примерный случай сомнительный, принцип лучше всего понять и развернуть в реальных сценариях. Показанный запрос работает, потому что неявное объединение в списке таблиц создает временную таблицу для подзапроса, обеспечивая тем самым стабильные результаты и избегая столкновения между поиском и модификацией той же таблицы. – AnrDaemon 26 April 2017 в 13:11

В соответствии с синтаксисом Mysql UPDATE , связанным с @CheekySoft, он говорит прямо внизу.

В настоящее время вы не можете обновить таблицу и выбрать один и тот же table в подзапросе.

Я думаю, что вы удаляете из store_category, все еще выбирая из него в объединении.

3
ответ дан briankip 19 August 2018 в 13:28
поделиться

Попробуйте сохранить результат оператора Select в отдельной переменной, а затем используйте это для запроса на удаление.

1
ответ дан lipika chakraborty 19 August 2018 в 13:28
поделиться
0
ответ дан Melvin Angelo Jabonillo 19 August 2018 в 13:28
поделиться
DELETE FROM story_category
WHERE category_id NOT IN (
    SELECT cid FROM (
        SELECT DISTINCT category.id AS cid FROM category INNER JOIN story_category ON category_id=category.id
    ) AS c
)
29
ответ дан NexusRex 19 August 2018 в 13:28
поделиться
  • 1
    Можете ли вы объяснить, почему это работает, почему работает только одно гнездование? Этот вопрос был задан уже как комментарий к вопросу @ EkoNoval, но никто не ответил. Может быть, вы можете помочь. – Akshay Arora 27 January 2016 в 14:00
  • 2
    @AkshayArora, Пройдите часть под заголовком «Может быть, вы можете просто присоединиться к таблице к себе» в ответе @ Cheekysoft. Он сказал, что UPDATE tbl AS a INNER JOIN tbl AS b ON .... SET a.col = b.col - это будет работать как другой псевдоним для одной и той же таблицы. Аналогично в ответе @ NexusRex первый SELECT запрос действует как производная таблица, в которую story_category используется во второй раз. Таким образом, ошибка, упомянутая в OP, не должна происходить здесь, верно? – Istiaque Ahmed 9 November 2017 в 11:00

Самый простой способ сделать это - использовать псевдоним таблицы, когда вы ссылаетесь на родительскую таблицу запросов внутри подзапроса.

Пример:

insert into xxx_tab (trans_id) values ((select max(trans_id)+1 from xxx_tab));

Измените его на:

insert into xxx_tab (trans_id) values ((select max(P.trans_id)+1 from xxx_tab P));
0
ответ дан S.Roshanth 19 August 2018 в 13:28
поделиться

Это то, что я сделал для обновления значения столбца Priority на 1, если он = = 1 в таблице и в его предложении WHERE, используя подзапрос в той же таблице, чтобы удостовериться, что хотя бы одна строка содержит Priority = 1 (потому что это условие, которое нужно проверить при выполнении обновления):


UPDATE My_Table
SET Priority=Priority + 1
WHERE Priority >= 1
AND (SELECT TRUE FROM (SELECT * FROM My_Table WHERE Priority=1 LIMIT 1) as t);

Я знаю, что это немного уродливо, но все работает отлично.

11
ответ дан sactiw 19 August 2018 в 13:28
поделиться
  • 1
    @anonymous_reviewer: Если вы дадите [-1] или даже [+1] кому-то комментарий, пожалуйста, также укажите, почему вы его дали. Благодаря!!! – sactiw 20 December 2010 в 17:42
  • 2
    -1, потому что это неверно. Вы не можете изменить ту же таблицу, которую используете в инструкции SELECT. – Chris 27 January 2011 в 21:10
  • 3
    @Chris Я проверил его на MySQL, и он работает отлично для меня, поэтому я бы попросил вас, пожалуйста, проверить его на вашем конце, а затем утверждать, что он является правильным или неправильным. Благодаря!!! – sactiw 18 February 2011 в 16:03
  • 4
    В нижней части этой страницы говорится: «В настоящее время вы не можете обновить таблицу и выбрать из той же таблицы в подзапросе». - и я испытал это, чтобы быть правдой во многих случаях. dev.mysql.com/doc/refman/5.0/en/update.html – Chris 19 February 2011 в 01:08
  • 5
    @Chris Я знаю это, но для этого есть обходной путь, и именно это я пытался показать с помощью моего запроса «UPDATE» и считаю, что он работает нормально. Я не думаю, что вы действительно пытались проверить мой запрос вообще. – sactiw 21 February 2011 в 14:39

попробуйте это

DELETE FROM story_category 
WHERE category_id NOT IN (
SELECT DISTINCT category.id 
FROM (SELECT * FROM STORY_CATEGORY) sc;
0
ответ дан Sameer Khanal 19 August 2018 в 13:28
поделиться

Если вы не можете сделать

UPDATE table SET a=value WHERE x IN
    (SELECT x FROM table WHERE condition);

, потому что это та же таблица, вы можете обмануть и сделать:

UPDATE table SET a=value WHERE x IN
    (SELECT * FROM (SELECT x FROM table WHERE condition) as t)

[обновление или удаление или что-то еще]

17
ответ дан Sequoya 19 August 2018 в 13:28
поделиться

inner join в вашем суб-запросе не требуется. Похоже, вы хотите удалить записи в story_category, где category_id не находится в таблице category.

Сделайте это:

DELETE FROM story_category 
WHERE category_id NOT IN (
    SELECT DISTINCT category.id 
    FROM category);

Вместо этого :

DELETE FROM story_category 
WHERE category_id NOT IN (
    SELECT DISTINCT category.id 
    FROM category INNER JOIN
         story_category ON category_id=category.id);
99
ответ дан shA.t 19 August 2018 в 13:28
поделиться

Если что-то не срабатывает, когда выходите через входную дверь, тогда возьмите заднюю дверь:

drop table if exists apples;
create table if not exists apples(variety char(10) primary key, price int);

insert into apples values('fuji', 5), ('gala', 6);

drop table if exists apples_new;
create table if not exists apples_new like apples;
insert into apples_new select * from apples;

update apples_new
    set price = (select price from apples where variety = 'gala')
    where variety = 'fuji';
rename table apples to apples_orig;
rename table apples_new to apples;
drop table apples_orig;

Это быстро. Чем больше данных, тем лучше.

1
ответ дан Tom Schaefer 19 August 2018 в 13:28
поделиться
  • 1
    И вы просто потеряли все свои внешние ключи, и, возможно, у вас также есть каскадные удаления. – Walf 9 December 2014 в 07:48

Вы можете вставить идентификаторы нужных строк в временную таблицу, а затем удалить все строки, найденные в этой таблице.

, что может быть тем, что @Cheekysoft означало, делая это за два шага.

4
ответ дан YonahW 19 August 2018 в 13:28
поделиться
Другие вопросы по тегам:

Похожие вопросы: