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. Нужна помощь.
Покинул форум
Сообщений всего: 1539
Дата рег-ции: Март 2010 Откуда: Киров
Помог: 6 раз(а)
Нужна ваша помощь, ребят!
Собственная cms. Записи выводятся из БД, данные собираются из 3-х таблиц.
1. table - основные данные записи
2. table_lng - локализации (тексты на разных языках)
3. table_tpl - шаблоны. тут лежат шаблоны с различными именами, а также шаблон с именем "default".
Каждой записи из table соответствует какой-либо шаблон в table_tpl.
Помощь нужна именно в присоединении шаблонов.
Есть следующий запрос (лишние поля опущены):
В нем делается выборка данных с присоединением шаблона из table_tpl AS tpl, где tpl.name=item.template. Все отлично работает, если item.template имеет значение, присутствующее в table_tpl.
Но мне необходимо сделать, чтобы если в table_tpl отсутствует шаблон item.template, то присоединялся бы шаблон с именем "default".
Как выкрутиться?
DeepVarvar
Отправлено: 11 Августа, 2010 - 17:03:51
Активный участник
Покинул форум
Сообщений всего: 10377
Дата рег-ции: Дек. 2008 Откуда: Альфа Центавра
Помог: 353 раз(а)
Хм... Попробую предположить (я так не особо ещев БД):
Тут вижу 2 варианта:
Или делать еще запросы - но это плохо,
или пробуй определив все для двух первых UNION для третьего...
Больше мыслей нет... )
Покинул форум
Сообщений всего: 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.
DeepVarvar
Отправлено: 11 Августа, 2010 - 18:36:45
Активный участник
Покинул форум
Сообщений всего: 10377
Дата рег-ции: Дек. 2008 Откуда: Альфа Центавра
Помог: 353 раз(а)
Champion а если можно вот об этом для тупых (для мене) поподробнее???
Покинул форум
Сообщений всего: 4350
Дата рег-ции: Авг. 2008 Откуда: Москва
Помог: 57 раз(а)
Ну я так понял, что соединение должно быть таким: если соответствие из другой таблицы есть, то всё как обычно. А если нет, то должна быть не строка с null-ми, а строка для 'default'. Вот отсюда такое правило соединения придумалось.
Если нужно описание функции coalsesce - она выдает самое левое не null значение в скобках.
DeepVarvar
Отправлено: 11 Августа, 2010 - 18:57:54
Активный участник
Покинул форум
Сообщений всего: 10377
Дата рег-ции: Дек. 2008 Откуда: Альфа Центавра
Покинул форум
Сообщений всего: 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.
Возможно, это не очень кошерно, поэтому я жду еще советов.
alexspb
Отправлено: 11 Августа, 2010 - 22:38:13
Посетитель
Покинул форум
Сообщений всего: 260
Дата рег-ции: Май 2010
Помог: 0 раз(а)
проблема в or - может бытьобе строки
решение в лоб - дефолтный шаблон должен иметь id = 1 (в своей таблице)
тогда вместо
ON tpl.name=item.template
----- Хостинг - неограниченно доменов на одну папку Ajax - отличное введение
JustUserR
Отправлено: 12 Августа, 2010 - 02:08:00
Активный участник
Покинул форум
Сообщений всего: 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/
Uchkuma
Отправлено: 12 Августа, 2010 - 07:16:29
Участник
Покинул форум
Сообщений всего: 1539
Дата рег-ции: Март 2010 Откуда: Киров
Помог: 6 раз(а)
alexspb пишет:
проблема в or - может бытьобе строки
решение в лоб - дефолтный шаблон должен иметь id = 1 (в своей таблице)
тогда вместо...
Да, это была моя первая идея как решить эту задачу. Но дело в том, что в таблице tpl нету поля id и не хотелось бы его вводить чисто для этой цели. Поле name в таблице является уникальным и по нему идет индекс и выборка.
alexspb
Отправлено: 12 Августа, 2010 - 09:41:46
Посетитель
Покинул форум
Сообщений всего: 260
Дата рег-ции: Май 2010
Помог: 0 раз(а)
Uchkuma пишет:
Но дело в том, что...
Вы думаете, что упрощаете себе жизнь тем, что отказываетесь от индексного числового поля
между тем выборки по нему а) как правило быстрее б) позволяет его использовать как внешний ключ (опять же в числовом формате) в) в ряде случаев это важно для возможности менять значение, оставляя целостным ключ (не нарушать связи) и для нормализации таблиц
Просто поверьте, что ключи придуманы не зря.
PS к слову. выше в сортировке забыл указать порядок
чтобы сперва искался нужный шаблон и лишь затем - дефолтный
----- Хостинг - неограниченно доменов на одну папку Ajax - отличное введение
Uchkuma
Отправлено: 12 Августа, 2010 - 09:55:03
Участник
Покинул форум
Сообщений всего: 1539
Дата рег-ции: Март 2010 Откуда: Киров
Помог: 6 раз(а)
alexspb, спасибо. Возможно так и сделаю.
Champion
Отправлено: 12 Августа, 2010 - 19:02:01
Активный участник
Покинул форум
Сообщений всего: 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') то такой проблемы не будет
alexspb
Отправлено: 12 Августа, 2010 - 19:23:12
Посетитель
Покинул форум
Сообщений всего: 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 - отличное введение
Champion
Отправлено: 12 Августа, 2010 - 19:35:28
Активный участник
Покинул форум
Сообщений всего: 4350
Дата рег-ции: Авг. 2008 Откуда: Москва
Помог: 57 раз(а)
alexspb пишет:
если в table поле template содержит ссылку на несуществующий шаблон
То в таблице, которая прижойнится к ней справа будет null. И мы на место этой строки подтянем 'default' из этой же таблицы... Ща подумаю внимательно. Структуру таблиц бы с комментарием и пример как должно быть вместо чего (Добавление)
Перечитал вопрос. По-моему, я прав
Все гости форума могут просматривать этот раздел. Только зарегистрированные пользователи могут создавать новые темы в этом разделе. Только зарегистрированные пользователи могут отвечать на сообщения в этом разделе.