2016-04-08 6 views
0

У меня есть две таблицы:MySql - Multitable - И это неправильный выбор, но что это такое?

mytable1

UserId (int) (primary_key) 
Save (blob) 

mytable2

UserId (int) (primary_key) 
Save (blob) 

Я делаю следующее MySQL команды:

UPDATE mytable1 tb1, mytable2 tb2 SET tb1.Save='', tb2 .Save='' WHERE tb1.UserId=25 AND dbSv1.UserId=25 

Когда обе таблицы имеют пользователю UserId = 25, то это работает, а «Сохранить» - «». Однако, если одна таблица не имеет пользователя с UserId = 25, но другая делает, тогда Save не установлен в '' в том, что делает. Это не то поведение, которое я хочу.

ИЛИ не используется, поскольку другие Saves будут установлены в '', которые не имеют UserId из 25. Так что мне нужно?

+1

Поместить 2 оператора в транзакцию – Mihai

+0

Как вы это делаете с помощью одного оператора mysql? (Я знаю, как это сделать с множественным вызовом mysql в php, но предпочел бы избежать этого и сделать один вызов mysql.) – Rewind

+0

Вы не можете сделать это в одном заявлении sql. Но большинство расширений mysql поддерживают выделение нескольких операторов sql в одном вызове. Но если вы используете транзакции, на самом деле не имеет значения, сколько звонков вы совершаете. – Shadow

ответ

2

В вашем запросе используется синтаксис синтаксиса старой школы для операции соединения. (Есть некоторые проблемы в SQL ... dbSv1 используется как определитель, но он не отображается как псевдоним таблицы или таблицы. Предполагается, что это должно быть tb2.

Ваш запрос эквивалентно:

UPDATE mytable1 tb1 
    JOIN mytable2 tb2 
    SET tb1.save='' 
     , tb2.save='' 
    WHERE tb1.userid=25 
    AND tb2.userid=25 

Если соответствующая строка не найдена в любом tb1 или tb2, на операцию JOIN будет производить пустое множество Это ожидаемое поведение

Рассмотрим результирующий набор, возвращаемый из этого.. запрос:

SELECT tb1.userid 
     , tb2.userid 
    FROM mytable1 tb1 
    JOIN mytable2 tb2 
    WHERE tb1.userid=25 
    AND tb2.userid=25 

Если в tb2 нет строк, удовлетворяющих предикатам, запрос не будет возвращать никакие строки.

Вы можете использовать «внешнее» соединение, чтобы сделать возвращаемые строки из одной из таблиц необязательными. Например, чтобы обновить mytable1 даже если нет соответствующих строк не существует в mytable2 ...

UPDATE mytable1 tb1 
    LEFT 
    JOIN mytable2 tb2 
     ON tb2.userid=25 
    SET tb1.save='' 
     , tb2.save='' 
    WHERE tb1.userid=25 

Если нет строки в mytable1, которые имеют идентификатор пользователя = 25, то это не будет обновлять какие-либо строки.

MySQL не поддерживает FULL OUTER JOIN. Но вы пытаетесь что-то вроде этого, используя вложенное вернуть строку, а затем выполнять внешние соединения и к mytable1 и mytable2 ...

UPDATE (SELECT 25 + 0 AS userid) i 
    LEFT 
    JOIN mytable1 tb1 
     ON tb1.userid = i.userid 
    LEFT 
    JOIN mytable2 tb2 
     ON tb2.userid = i.userid 
    SET tb1.save = '' 
     , tb2.save = '' 

SQLFiddle демонстрация: http://sqlfiddle.com/#!9/6f8598/1


Followup

«Соединение» - это обычная операция SQL. Вам не должно быть никаких проблем с поиском информации о том, что это такое.

«+ 0» не является абсолютно необходимым. Это удобный сокращенный код в MySQL для CAST для численного.В качестве теста, посмотрим, что возвращает MySQL для этого:

SELECT '25' + 0 
    , '25xyz' + 0 
    , 'abc' + 0 

Целью зрения инлайн было возвращать одну строку. Мы могли бы написать запрос, чтобы жестко закодировать user_id два раза, и игнорировать то, что вернулись с точки зрения линии ....

SELECT t1.user_id AS t1_user_id 
     , t2.user_id AS t2_user_id 
    FROM (SELECT 'foo' AS dontcare) i 
    LEFT 
    JOIN mytable1 t1 
    ON t1.user_id = 25 
    LEFT 
    JOIN mytable t2 
    ON t2.user_id = 25 

Я предпочитаю, чтобы сделать его более ясным, что наша цель для обоих значений быть одинаковым. Мы могли бы указать, где один из них - 23, а другой - 27. Это синтаксически справедливо для этого. Когда мы превращаем это в подготовленное заявление с связываемых заполнителей ...

SELECT t1.user_id AS t1_user_id 
     , t2.user_id AS t2_user_id 
    FROM (SELECT 'foo' AS dontcare) i 
    LEFT 
    JOIN mytable1 t1 
    ON t1.user_id = ? 
    LEFT 
    JOIN mytable t2 
    ON t2.user_id = ? 

Мы вроде «потерять» идею, что эти два значения одинаковы. Чтобы получить это жестко заданное значение, указанное только один раз, у меня есть встроенный вид, возвращающий значение, которое мы хотим «сопоставить» в предложении ON внешних соединений.

SELECT t1.user_id AS t1_user_id 
     , t2.user_id AS t2_user_id 
    FROM (SELECT ? AS user_id) i 
    LEFT 
    JOIN mytable1 t1 
    ON t1.user_id = i.user_id 
    LEFT 
    JOIN mytable t2 
    ON t2.user_id = i.user_id 

Теперь мое намерение более ясное ... Я ищу «одно» значение user_id. Добавление «+ 0» означает, что любое значение передается (например, «25», «foo» или что-то еще), мой оператор будет интерпретировать это как числовое значение.

рядный вид

Я использовал термин "встроенный вид". Это просто запрос SELECT, используемый в контексте, где у нас обычно есть таблица.

например. если у меня есть таблица с именем mine, я могу написать запрос ...

SELECT m.id, m.name FROM mine m 

тест и посмотреть, что он возвращает строки, болтовня, болтовня.

Я также могу это сделать: обернуть этот запрос в круглые скобки и ссылаться на него вместо таблицы в другом заявлении, как это ...

SELECT t.* 
    FROM (SELECT m.id, m.name FROM mine m) t 

MySQL требует, чтобы мы присвоить псевдоним, который , как мы можем это сделать, если бы это была таблица. Мы называем это inline view, потому что он похож на шаблон, который мы используем для сохраненного вида. Давайте посмотрим на демонстрацию этого.

(Это просто демонстрация картины, есть несколько причин, мы не хотели бы, чтобы это сделать.)

CREATE VIEW myview 
    AS 
    SELECT m.id, m.name FROM mine m 
    ; 

Тогда мы можем сделать это:

SELECT t.* FROM myview t 

С inline view мы следуем одному и тому же шаблону, но мы обходим отдельный оператор create view. (Это заявление DDL, которое вызывает неявное коммитирование и создание объекта базы данных.) Обходя это, мы фактически создаем представление, которое существует только в контексте инструкции и делает это «inline» внутри оператора.

SELECT t.* FROM (SELECT m.id, m.name FROM mine m) t 

Документация MySQL относится к встроенному представлению как к «производной таблице».Если мы (случайно) забыли псевдоним, ошибка, которую мы вернем, говорит что-то вроде «каждая производная таблица должна иметь псевдоним». Более общий термин, используемый для баз данных, отличных от MySQL, - это «встроенный просмотр».

+0

Спасибо @ spencer7593, это отличный ответ. Я не уверен, что ПРИСОЕДИНЯЮТСЯ, но это прекрасный ответ, поскольку у него есть скрипка, чтобы показать, что он работает, поэтому я могу уйти и узнать, что все это значит, а затем вернуться и понять. Еще раз спасибо. Я программист по хобби, и это идеальный ответ для тех, кто хочет учиться. – Rewind

+0

После некоторого чтения я буквально все понимаю. Это всего лишь последний синий бит кода. Я не знаю, что такое встроенный просмотр и не может найти его в google. Это то, что вы делаете? Фраза после UPDATE - это таблица базы данных. Вы выбираете номер 25 и вызываете его userid. Затем вы переименовываете это в i. С LEFT JOINS вы получите все с номером 25 из двух объединений, потому что это то, что делает LEFT - это вещь слева (25), которая должна быть действительной. Я почти понимаю, вы можете объяснить первую строку, например, почему +0? – Rewind

+0

Добавлен ответ на вопрос, чтобы ответить на ваши комментарии. Надеюсь, это поможет объяснить, почему я сделал это так, как сделал это. – spencer7593