MySQL. WHERE MATCH () AGAINST ( IN BOOLEAN MODE) и LEFT JOIN в одном запросе

120tonn
9 years old
0

Доброго времени суток!
Имеются две таблицы:
1)mailing (письма):

|id|time|num_comms(кол-во комментов)|cor(автор письма)|resp(получатели, может быть несколько, через запятую)|text|send|

Запрос:

$user_mail_all=mysql_query("SELECT * FROM `mailing` WHERE MATCH (resp) AGAINST ('$user_resp' IN BOOLEAN MODE) OR `cor`='$username' ORDER BY `id` DESC LIMIT ".$start.",".$per_page )

работает замечательно. (Здесь $user_resp=str_replace("-","tyre",$username) то есть убиреам возможное тире в имени пользователя для корректной работы поиска MATCH (resp) AGAINST(...), resp, разумеется, fooltext).

2)mail_views (запись количества комментариев к СВОИМ письмам, прочитанных юзером):

|id|uid(ай-ди юзера)|lid(ай-ди письма)|time|number(количество комментов к этому письму на момент открытия его юзером)|

Эта таблица нужна для вывода количества ответов на каждое письмо, оставленное после закрытия его адресатом или автором. Для показа новых ответов.

И вот, такой запрос:

$user_mail_all=mysql_query("SELECT * FROM `mailing` WHERE MATCH (resp) AGAINST ('$user_resp' IN BOOLEAN MODE) OR `cor`='$username' LEFT JOIN `mail_views` ON mailing.id=mail_views.lid AND mail_views.uid=".$_SESSION['uid']." ORDER BY `id` DESC LIMIT ".$start.",".$per_page)

выдает такую ошибку:

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'LEFT JOIN `mail_views` ON mailing.id=mail_views.lid AND mail_views.uid=12 ORDER ' at line 1

(Здесь 12 - это id пользователя, переданный в $_SESSION['uid'])
Если убрать из запроса "MATCH (resp) AGAINST ('$user_resp' IN BOOLEAN MODE) OR ", оставив

$user_mail_all=mysql_query("SELECT * FROM `mailing` WHERE `cor`='$username' LEFT JOIN `mail_views` ON mailing.id=mail_views.lid AND mail_views.uid=".$_SESSION['uid']." ORDER BY `id` DESC LIMIT ".$start.",".$per_page)

ошибка сохраняется.

Подскажите, пожалуйста, в чем дело?
Спасибо.

rudenko
9 years old
0

LEFT JOIN должен идти до условия WHERE:
SELECT *
FROM `mailing`
LEFT JOIN `mail_views` ON mailing.id=mail_views.lid AND mail_views.uid=".$_SESSION['uid']."
WHERE MATCH (resp) AGAINST ('$user_resp' IN BOOLEAN MODE) OR `cor`='$username'
ORDER BY `id` DESC
LIMIT ".$start.",".$per_page

120tonn
9 years old
0

Спасибо, Илья!
Мне уже разжевали проблему: stackoverflow.com/questions/14296021/left-join-not-works-after-match-against-in-boolean-mode
Для тех, кто столкнется с чем-то подобным, хочу напомнить, что в случае с сортировкой (ORDER BY `id` DESC) первичные ключи обеих таблиц не должны называться одинаково.

rudenko
9 years old
0

> первичные ключи обеих таблиц не должны называться одинаково
Это плохой совет Вам дали. Нужно просто алиасы в запросах использовать или полное название таблицы писать.
Например так: ORDER BY mailing.id DESC

120tonn
9 years old
0

Спасибо, Илья! И все-таки проблема...
Вот такая вот получилась конструкция:


$user_mail_all=mysql_query("SELECT *
FROM `mailing`
LEFT JOIN `mail_views`
ON mailing.id=mail_views.lid
WHERE MATCH (resp)
AGAINST ('$user_resp' IN BOOLEAN MODE)
OR `cor`='$username'
AND mail_views.uid=".$_SESSION['uid']."
ORDER BY `id`DESC LIMIT ".$start.",".$per_page) or die(mysql_error());


В таблице `mailing` находятся письма, и пользователь может быть либо с столбце `cor` (если он - отправитель), либо в столбце `resp` (получатель, их может быть несколько, через запятую, где '$user_resp' - это наш '$username' с экранированным тире(если оно есть в имени пользователя)).
В таблице `mail_views` хранятся записи о количестве ответов на письма, для того, чтобы подсвечивать новые.
Суть проблемы.
В этой редакции запроса, в которой идет поиск сначала получателей в столбце `resp`, письма получателям видны, они выводятся. Но отправитель (столбец `cor`) их не видит.

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

WHERE MATCH (resp)
AGAINST ('$user_resp' IN BOOLEAN MODE)
OR `cor`='$username'


написать:

WHERE `cor`='$username'
OR MATCH (resp)
AGAINST ('$user_resp' IN BOOLEAN MODE)


выводятся только письма у отправителя, а уже получатели ничего на странице не видят.
Почему??

rudenko
9 years old
0

Если это скрипт, который вы разрабатываете сами, то необходимо изменить структуру хранения данных - убрать хранение получателей через запятую. Сделайте для них отдельную таблицу. Это решит проблемы с выборками и уберет MATCH ... AGAINST, так как это используется только для полнотекстового поиска с релевантностью (это как с танка по воробьям стрелять), а вам нужна простая выборка where a='b' или where a in ('a', 'b'....). Если в условии есть OR и используется более 3-х сравнений, то нужны скобки, так как не понятно к чему OR относится. Например: a=1 or b=2 and c=3 варианты со скобками: (a=1 or b=2) and c=3 или a=1 or (b=2 and c=3) что даст разные результаты.

120tonn
9 years old
0

Ага, спасибо! Завтра привезут книгу по mysql - засяду за учебник. И мне нужно время, чтобы "увидеть" предлагаемую вами структуру базы, иначе я не могу.
Но проблема, кажись, решена:

<?php
$user_mail_all=mysql_query("SELECT *
FROM `mailing`
LEFT JOIN `mail_views`
ON mailing.id=mail_views.vid
WHERE MATCH (resp)
AGAINST ('$user_resp' IN BOOLEAN MODE)
OR `cor`='$username'
ORDER BY `mailing`.`time` DESC LIMIT ".$start.",".$per_page)

?>


Сделано почти наугад заменой
ON mailing.id=mail_views.lid

(где `mail_views`.`lid` - это ай-ди номер прочтенного текущим пользователем письма в таблице `mailing`, записанный в табл. `mail_views`)

на:
ON mailing.id=mail_views.vid

(здесь `mail_views`.`vid` - это PRIMARY KEY табл. `mail_views`)

Наугад, потому, что я плохо представляю себе, что такое и что делает оператор ON в LEFT JOIN. Поэтому не уверен в работоспособности этого фрагмента кода...

The topic is closed.