Warning: Cannot use a scalar value as an array in /home/admin/public_html/forum/include/fm.class.php on line 757

Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/include/fm.class.php on line 770

Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/topic.php on line 737
Форумы портала PHP.SU :: Запрос с LEFT JOIN. Нужна помощь.

 PHP.SU

Программирование на PHP, MySQL и другие веб-технологии
PHP.SU Портал     На главную страницу форума Главная     Помощь Помощь     Поиск Поиск     Поиск Яндекс Поиск Яндекс     Вакансии  Пользователи Пользователи


 Страниц (2): [1] 2 »   

> Описание: Запрос с LEFT JOIN. Нужна помощь.
Uchkuma
Отправлено: 11 Августа, 2010 - 16:51:12
Post Id



Участник


Покинул форум
Сообщений всего: 1539
Дата рег-ции: Март 2010  
Откуда: Киров


Помог: 6 раз(а)




Нужна ваша помощь, ребят!
Собственная cms. Записи выводятся из БД, данные собираются из 3-х таблиц.
1. table - основные данные записи
2. table_lng - локализации (тексты на разных языках)
3. table_tpl - шаблоны. тут лежат шаблоны с различными именами, а также шаблон с именем "default".
Каждой записи из table соответствует какой-либо шаблон в table_tpl.
Помощь нужна именно в присоединении шаблонов.
Есть следующий запрос (лишние поля опущены):
PHP:
скопировать код в буфер обмена
  1. $sql = 'SELECT
  2. lng.content, tpl.name, item.template
  3. FROM
  4. table AS item
  5. LEFT JOIN
  6. table_lng AS lng
  7. ON item.id=lng.id AND lng.lang="'.$lang.'"
  8. LEFT JOIN
  9. table_tpl AS tpl
  10. ON tpl.name=item.template
  11. WHERE item.id='.$id;
В нем делается выборка данных с присоединением шаблона из table_tpl AS tpl, где tpl.name=item.template. Все отлично работает, если item.template имеет значение, присутствующее в table_tpl.
Но мне необходимо сделать, чтобы если в table_tpl отсутствует шаблон item.template, то присоединялся бы шаблон с именем "default".

Как выкрутиться?
 
 Top
DeepVarvar Супермодератор
Отправлено: 11 Августа, 2010 - 17:03:51
Post Id



Активный участник


Покинул форум
Сообщений всего: 10377
Дата рег-ции: Дек. 2008  
Откуда: Альфа Центавра


Помог: 353 раз(а)




Хм... Попробую предположить (я так не особо ещев БД):
Тут вижу 2 варианта:
Или делать еще запросы - но это плохо,
или пробуй определив все для двух первых UNION для третьего...
Больше мыслей нет... )
 
 Top
Champion Супермодератор
Отправлено: 11 Августа, 2010 - 18:22:52
Post Id



Активный участник


Покинул форум
Сообщений всего: 4350
Дата рег-ции: Авг. 2008  
Откуда: Москва


Помог: 57 раз(а)




Не совсем понял вопрос, но надо в эту сторону копнуть:
LEFT JOIN
table_tpl AS tpl
ON coalesce(tpl.name, 'default') =item.template
или
LEFT JOIN
table_tpl AS tpl
ON tpl.name =item.template or (tpl.name is null and item.template = 'default')
Не понял, где именно когда должен быть default.

Второе будет производительнее, если есть индекс по tpl.name.
 
 Top
DeepVarvar Супермодератор
Отправлено: 11 Августа, 2010 - 18:36:45
Post Id



Активный участник


Покинул форум
Сообщений всего: 10377
Дата рег-ции: Дек. 2008  
Откуда: Альфа Центавра


Помог: 353 раз(а)




Champion а если можно вот об этом для тупых (для мене) поподробнее???
 
 Top
Champion Супермодератор
Отправлено: 11 Августа, 2010 - 18:42:31
Post Id



Активный участник


Покинул форум
Сообщений всего: 4350
Дата рег-ции: Авг. 2008  
Откуда: Москва


Помог: 57 раз(а)




Ну я так понял, что соединение должно быть таким: если соответствие из другой таблицы есть, то всё как обычно. А если нет, то должна быть не строка с null-ми, а строка для 'default'. Вот отсюда такое правило соединения придумалось.
Если нужно описание функции coalsesce - она выдает самое левое не null значение в скобках.
 
 Top
DeepVarvar Супермодератор
Отправлено: 11 Августа, 2010 - 18:57:54
Post Id



Активный участник


Покинул форум
Сообщений всего: 10377
Дата рег-ции: Дек. 2008  
Откуда: Альфа Центавра


Помог: 353 раз(а)




Во!!!!! Сенкс )
 
 Top
Uchkuma
Отправлено: 11 Августа, 2010 - 20:43:00
Post Id



Участник


Покинул форум
Сообщений всего: 1539
Дата рег-ции: Март 2010  
Откуда: Киров


Помог: 6 раз(а)




Champion, ну во-первых не
Цитата:
LEFT JOIN
table_tpl AS tpl
ON coalesce(tpl.name, 'default')=item.template
, а
Цитата:
LEFT JOIN
table_tpl AS tpl
ON tpl.name=coalesce(item.template, 'default')
, т.к мы присоединяем данные из таблицы "tpl" по полю "name", которое равняется либо "item.template", либо "default", если не нашли совпадения с "item.template". Но такой запрос не сработает, т.к. "item.template" никогда не будет NULL, а всегда будет иметь значение.

Пока что я выкрутился из ситуации вложенным запросом:
Цитата:
$sql = 'SELECT
lng.content, tpl.name, item.template
FROM
table AS item
LEFT JOIN
table_lng AS lng
ON item.id=lng.id AND lng.lang="'.$lang.'"
LEFT JOIN
table_tpl AS tpl

вместо: ON tpl.name=item.template

написал: ON tpl.name=IF((SELECT name FROM table_tpl WHERE name=item.template) IS NULL, "default", item.template)

WHERE item.id='.$id;

Т.е. если в таблице "table_tpl" не будет найдено имя равное item.template, то произойдет присоединение по tpl.name='default', иначе по tpl.name=item.template.

Возможно, это не очень кошерно, поэтому я жду еще советов.
 
 Top
alexspb
Отправлено: 11 Августа, 2010 - 22:38:13
Post Id


Посетитель


Покинул форум
Сообщений всего: 260
Дата рег-ции: Май 2010  


Помог: 0 раз(а)




проблема в or - может бытьобе строки
решение в лоб - дефолтный шаблон должен иметь id = 1 (в своей таблице)
тогда вместо
ON tpl.name=item.template
CODE (SQL):
скопировать код в буфер обмена
  1. ON (tpl.name=item.template OR tpl.name='default')


и добавить
CODE (SQL):
скопировать код в буфер обмена
  1. ORDER BY `tpl`.`id`
  2. LIMIT 1;


(и вообще, не стоит забывать про LIMIT 1 - если вам по логике нужна 1 строка)

+ (точнее -)
tpl.name - лишнее похоже в выборке

(Отредактировано автором: 11 Августа, 2010 - 22:40:46)



-----
Хостинг - неограниченно доменов на одну папку
Ajax - отличное введение
 
 Top
JustUserR
Отправлено: 12 Августа, 2010 - 02:08:00
Post Id



Активный участник


Покинул форум
Сообщений всего: 8715
Дата рег-ции: Июнь 2009  


Помог: 17 раз(а)




Uchkuma пишет:
Пока что я выкрутился из ситуации вложенным запросом:
Во многих случаях функциональность достигаемая с помощью вложенных запросов и с помощью табличных соединения является практически идентичной - причем использование вложенных запросов является более эффективным - и оптимизатор SQL перед его выполнением может проводить предвартельное конвертирование табличных соединенний в набор соответсвующих вложенных запросов Более поднобную информацию о такой оптимизации можно посмотреть здесь http://articles[dot]org[dot]ru/cn/showde[dot][dot][dot]ail.php?cid=7205
Причина такой ситуации достаточно ясна - ведь SQL-интерпретатор в конечном итоге выполняет некоторых алгоритм для последовательной выборки данных - а вложенные запросы более явно указывают каким именно образом это необходимо сделать При этом конечно SQL-интерпретатор используется и дополнительные оптимизации связанные с реальным доступом к сохраненным данным - а также использованию ключей и индексов при совершении выборки


-----
Сделать можно все что угодно - нужно только старание, терпение и хороший поисковик Улыбка
Безлимитный web-хостинг от 15 рублей за 40 МБ дискового пространства - http://ihost[dot]oks71[dot]ru/
 
 Top
Uchkuma
Отправлено: 12 Августа, 2010 - 07:16:29
Post Id



Участник


Покинул форум
Сообщений всего: 1539
Дата рег-ции: Март 2010  
Откуда: Киров


Помог: 6 раз(а)




alexspb пишет:
проблема в or - может бытьобе строки
решение в лоб - дефолтный шаблон должен иметь id = 1 (в своей таблице)
тогда вместо...

Да, это была моя первая идея как решить эту задачу. Но дело в том, что в таблице tpl нету поля id и не хотелось бы его вводить чисто для этой цели. Поле name в таблице является уникальным и по нему идет индекс и выборка.
 
 Top
alexspb
Отправлено: 12 Августа, 2010 - 09:41:46
Post Id


Посетитель


Покинул форум
Сообщений всего: 260
Дата рег-ции: Май 2010  


Помог: 0 раз(а)




Uchkuma пишет:
Но дело в том, что...

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

PS к слову. выше в сортировке забыл указать порядок
CODE (SQL):
скопировать код в буфер обмена
  1. ORDER BY `tpl`.`id` DESC
  2. LIMIT 1;

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


-----
Хостинг - неограниченно доменов на одну папку
Ajax - отличное введение
 
 Top
Uchkuma
Отправлено: 12 Августа, 2010 - 09:55:03
Post Id



Участник


Покинул форум
Сообщений всего: 1539
Дата рег-ции: Март 2010  
Откуда: Киров


Помог: 6 раз(а)




alexspb, спасибо. Возможно так и сделаю.
 
 Top
Champion Супермодератор
Отправлено: 12 Августа, 2010 - 19:02:01
Post Id



Активный участник


Покинул форум
Сообщений всего: 4350
Дата рег-ции: Авг. 2008  
Откуда: Москва


Помог: 57 раз(а)




Uchkuma пишет:
во-первых не
...
, а
...
, т.к мы присоединяем данные из таблицы "tpl" по полю "name"
Я приблизительно написал, потому что криво понял, что в итоге должно получиться. Правильно, что вдумался.
Uchkuma пишет:
Но такой запрос не сработает, т.к. "item.template" никогда не будет NULL, а всегда будет иметь значение.
Тогда самой первой в LEFT JOIN просто не должна быть эта таблица.
Uchkuma пишет:
Пока что я выкрутился из ситуации вложенным запросом:
Это тот же coalesce по сути
alexspb пишет:
проблема в or
Проблема в or будет, если написать
alexspb пишет:
(tpl.name=item.template OR tpl.name='default')
А если написать
(tpl.name=item.template OR (tpl.name='default' AND item.template is null)) или
(tpl.name=coalesce(item.template, 'default') то такой проблемы не будет
 
 Top
alexspb
Отправлено: 12 Августа, 2010 - 19:23:12
Post Id


Посетитель


Покинул форум
Сообщений всего: 260
Дата рег-ции: Май 2010  


Помог: 0 раз(а)




Champion пишет:
(tpl.name=item.template OR (tpl.name='default' AND item.template is null))

насколько я понял связи таблиц (table и table_tpl) такой запрос некорректен
item.template - выполняет роль внешнего ключа (но тоекстовой)
tpl.name - именно там хранятся имена шаблонов (и связь по item.template)

т.е. задача - если в table поле template содержит ссылку на несуществующий шаблон в table_tpl, то вытащить дефолтный...


-----
Хостинг - неограниченно доменов на одну папку
Ajax - отличное введение
 
 Top
Champion Супермодератор
Отправлено: 12 Августа, 2010 - 19:35:28
Post Id



Активный участник


Покинул форум
Сообщений всего: 4350
Дата рег-ции: Авг. 2008  
Откуда: Москва


Помог: 57 раз(а)




alexspb пишет:
если в table поле template содержит ссылку на несуществующий шаблон
То в таблице, которая прижойнится к ней справа будет null. И мы на место этой строки подтянем 'default' из этой же таблицы... Ща подумаю внимательно. Структуру таблиц бы с комментарием и пример как должно быть вместо чего
(Добавление)
Перечитал вопрос. По-моему, я прав
 
 Top
Страниц (2): [1] 2 »
Сейчас эту тему просматривают: 0 (гостей: 0, зарегистрированных: 0)
« SQL и Архитектура БД »


Все гости форума могут просматривать этот раздел.
Только зарегистрированные пользователи могут создавать новые темы в этом разделе.
Только зарегистрированные пользователи могут отвечать на сообщения в этом разделе.
 



Powered by PHP  Powered By MySQL  Powered by Nginx  Valid CSS  RSS

 
Powered by ExBB FM 1.0 RC1. InvisionExBB