2015-04-16 1 views
2

У меня есть этот запрос, который будет работать отлично (я думаю) с более высокой версией MySQL, но, к сожалению, это не вариант.Изменение IN для входа в приложение UPDATE Подзапрос

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

Я хочу установить только winner = «Y» для максимального количества совпадений по электронной почте, так что у пользователя может быть только 1 «победитель» каждую неделю.

Я хочу обновить 1 строку для каждого письма, а не 1 строку во всей таблице.

Моя цель - выполнить все это в рамках одного запроса или, по крайней мере, уменьшить стресс на моем сервере в максимально возможной степени. У меня есть более 30 000 строк/билетов для обработки каждую неделю.

Я предполагаю, что лучше всего использовать JOIN вместо IN, но я не могу понять это.

UPDATE `tickets` 
SET `winner`='Y' 
WHERE `ticketid` IN 
    (SELECT `ticketid` 
    FROM `tickets` 
    WHERE `email` IN 
     (SELECT distinct(email) 
      FROM `tickets` 
      WHERE `date` BETWEEN '$weekstart' AND '$weekend' 
      AND `matches`>='3') 
    ORDER BY `matches` DESC LIMIT 1) 

Этот запрос дает мне ошибку: "# 1235 - Эта версия MySQL еще не поддерживает 'LIMIT & IN/ALL/ANY/SOME подзапрос'"

+1

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

+0

Обновление вопроса сейчас. – Arsis

+0

Все еще неясно, чего вы хотите достичь. Обновить 1 строку на электронную почту? Или всего одна строка за всю таблицу? –

ответ

0

Вы хотите обновить одну из строки в билетах, в которых письмо имеет максимальное количество совпадений - в соответствии с вашими условиями.

Я думаю, что это вопрос вы хотите:

UPDATE `tickets` t JOIN 
     (SELECT `email`, max(matches) as maxm 
     FROM tickets t 
     WHERE `date` BETWEEN '$weekstart' AND '$weekend' AND `matches` >= 3 
     GROUP BY email 
     ORDER BY maxm DESC 
     LIMIT 1 
     ) te 
     ON t.email = t3.email 
    SET t `winner` = 'Y' 
    LIMIT 1; 

Вы можете поставить какую-то рандомизации, используя этот order by:

order by maxm DESC, rand() 
+0

ДА! Это очень умно, я не думал о функции max(). Я буду работать с этим, но в настоящее время он дает «# 1064 - У вас есть ошибка в синтаксисе SQL, проверьте руководство, соответствующее версии вашего сервера MySQL, для правильного синтаксиса для использования рядом с' 'winner' = 'Y' LIMIT 1 «в строке 10» – Arsis

+0

Хммм, глядя на это дальше, я нахожу, что, возможно, я недостаточно хорошо объяснил ситуацию. Я хочу обновить одну из строк в билетах для EACH email, у которой максимальное количество совпадений для этого письма. Я обновил вопрос. – Arsis

0

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

UPDATE tickets 
INNER JOIN (
SELECT `ticketid` 
FROM `tickets` 
WHERE `date` BETWEEN '$weekstart' 
    AND '$weekend' AND `matches`>='3' 
ORDER BY `matches` DESC LIMIT 1) t 
ON tickets.ticketid = t.ticketid 
SET `winner`='Y' 
+0

Я думаю, что LIMIT 1 может быть в неправильной области. Я буду работать с этим, но в данный момент это влияет только на 1 строку за раз. edit: Это работало только 1 раз, чтобы обновить 1 строку, и теперь она влияет на 0 строк. – Arsis

+0

Так почему вы использовали это? :-) – Alex

1

Кроме LIMIT & IN/ALL/ANY/SOME subquery restri ction, само присоединение к таблице невозможно - без каких-либо трюков - в предложении WHERE оператора UPDATE, даже в последней версии MySQL.

Это, как правило, лучше переписать с помощью объединений - хотя далеко не тривиальна:

UPDATE 
    (SELECT DISTINCT email 
     FROM tickets 
    ) AS e 
    JOIN 
    tickets AS t 
     ON t.ticket_id = 
      (SELECT ti.ticket_id 
      FROM tickets AS ti 
      WHERE ti.email = e.email 
       AND ti.date BETWEEN '$weekstart' AND '$weekend' 
       AND ti.matches >= 3 
      ORDER BY ti.matches DESC 
      LIMIT 1 
     ) 
SET 
    t.winner = 'Y' ; 

Это находит только один ticket_id для каждого отдельного значения emails в таблице (и только если есть строка с дополнительными условиями , дата на желаемой неделе и 3 или более «совпадений»), а затем обновления.

Edit: Я был неправ, выше делает не работу, поднимает ошибку:

"#1093 - You can't specify target table 'e' for update in FROM clause"


Но это (даже более запутанным) делает работу:

UPDATE 
    tickets AS u 
    JOIN 
    (SELECT t.ticket_id 
     FROM 
      (SELECT DISTINCT email 
      FROM tickets 
     ) AS e 
     JOIN 
      tickets AS t 
      ON t.ticket_id = 
       (SELECT ti.ticket_id 
        FROM tickets AS ti 
        WHERE ti.email = e.email 
        AND ti.date BETWEEN '$weekstart' AND '$weekend' 
        AND ti.matches >= 3 
        ORDER BY ti.matches DESC 
        LIMIT 1 
       ) 
    ) AS x 
     ON x.ticket_id = u.ticket_id 
SET 
    u.winner = 'Y' ; 

Что касается эффективности, я думаю, что индекс на (email, date, matches, ticket_id) улучшит его.

Если процент строк в таблице matches >= 3 мал, альтернативный индекс будет на (email, matches, date, ticket_id).

+0

Да, спасибо Я думаю, что это то, что я ищу. Я получаю сообщение об ошибке. "# 1093 - Вы не можете указать целевую таблицу 'e' для обновления в разделе FROM" любые идеи? У меня нет опыта с JOINs. – Arsis

+0

Обновлен ответ. –

+0

Это работает, ypercube! Спасибо! Я очень ценю вашу помощь! Единственная проблема - это время, так как я запускаю его в базе данных с более чем 30000 строк за указанную неделю и более 200000 строк во всей таблице. Любые идеи о том, как ускорить его? Или я должен задать другой вопрос? – Arsis