[ Поиск ] - [ Пользователи ] - [ Календарь ]
Полная Версия: Выборка из разных таблиц по условию
Quieteroks
Здравствуйте.

Подскажите, как лучше реализовать выборку различных данных из разных таблиц с условием в поле начальной таблицы?

Пример

1. Основная таблица:
id, type, with, operation

2. Таблица пользователей
id, name

3. Таблица с админами
id, status, name

В результате нужно получить имя Пользователя или Админа в зависимости от того, какой type стоит в основной таблице. Это нужно для подстановки в операцию этого самого имени.

На сколько я понял, что if нельзя использовать в инструкции from...
Компоновать запрос в php не выход, ибо из основной таблицы получается порядка 25 строк за раз. Вариантов много, вплоть до трех отдельных запросов на все три таблицы а после собирать их в php.

Какой вариант посоветуете Вы?
andrey888
На вскидку ..
Сделай два разных VIEW (для юзеров и админов) .. собери эти Вьюхи Джоином из твоих трех таблиц ..
а в коде будешь обращаться к той таблице - (читать Вьюхе) к которой нужно..
-------
Раз уж ты решил разделить таблицами Юзеров и Админов.. А вообще можешь еще по архитектуре БД поразмыслить чтоб проблем потом не возникало с выборкой..
Как пример на одном из относительно известных Лайт Движков для форума залазил в БД и там права распределяются из одной и той же таблицы .. (то бишь Админы те же Юзеры просто с другими правами, что на мой взгляд логичнее будет выглядеть ... )

_____________
Прогноз на следующие 5 лет : Россия, Китай - две величайшие державы.
США в Ж*пе. Справедливость восторжествует. )
sergeiss
Quieteroks, чуть подробнее, плз... Что за условие в поле начальной таблицы? Мне кажется, что можно сделать всё одним запросом. Но пока маловато данных, чтобы сделать вывод.

И еще вопрос - а насколько важно делать таблицы 2 и 3? Почему эти данные у тебя находятся не в одной таблице? Вроде бы логичнее так было smile.gif И выбирать проще будет.

_____________
* Хэлп по PHP
* Описалово по JavaScript
* Хэлп и СУБД для PostgreSQL

* Обучаю PHP, JS, вёрстке. Интерактивно и качественно. За разумные деньги.

* "накапливаю умение телепатии" (С) и "гуглю за ваш счет" (С)

user posted image
Quieteroks
sergeiss
Я же пример привел, а не реальную ситуацию.
Периодически имеются разные сущности в таблицах. Объединить их никак. Особенно когда расширяется уже созданная система новой сущностью. К примеру как тут описано: были только пользователи с распределением своих доступов, а теперь нужны еще и отдельно админы, у которых нет 75% информации, что есть в пользователях, но есть что то дополнительное...

andrey888
А чем мне тут разные вьюхи помогут? В одной выписке могут быть разные данные, а не в разных выписках свои данные. Это бы гораздо упростило ситуацию, но нет.

Попробую чутка еще подробнее.

Основная таблица собирательная, в примере это история чего-то (изменений Аккаунта допустим). Их может внести Пользователь, а может Админ (да, желательно их в одну таблицу, но вот ситуация, когда в разных они и менять уже нельзя). Для РоотАдмина допустим имеется доступ к списку изменений, кто и что вносил в Аккаунт.

И вот мы собираем этот список:
1. Правку внес Админ в поле Фамилия
2. Правку внес Пользователь в поле Адрес
...
25. Правку внес Пользователь в поле Телефон

Таблицы три, ссылка на id одна. Имеется ключ показатель type на то, кто вносил правку.
Завтра появится еще таблица, в которой будет какой нить тип данных, не относящийся к реальным пользователям, например крон скрипт (вообще надумано, но возможно)...

И вот нужно сделать соответствующую выборку и подставить в выписку кто сделал изменение...

Можно отдельно все выбирать, а можно одним запросом, но в from нельзя использовать условия вообще. Делать выборку из всех таблиц одновременно объединяя все по полю id, а после выбирать и подставлять нужное поле uname, aname в самом php, но вдруг никто не трогал выписку, кроме самого Пользователя, а ворошить придется все таблицы.

Пример данных в основной таблице (не расценивайте пример, как реальный момент системы):
id, type, with, operation
1, 0, 22, 'Правку внес [name] в поле Фамилия'
2, 1, 76, 'Правку внес [name] в поле Адрес'
...
25, 1, 76, 'Правку внес [name] в поле Телефон'

В итоге если type = 0, то это админ, если 1, то пользователь.
sergeiss
Говоря про возможность выборки одним запросом, я имел ввиду UNION. Поясни насчет айди: это число, которое уникально для каждого юзера, вне зависимости от таблиц 2,3,...? И в таблице 1 есть все айди, которые имеются в других таблицах?

Если да, то тогда такой запрос собери:
1. Джойнь таблицы 1 и 3 по айди с фильтром по нужному айди
2. Джойнь таблицы 1 и 2 по айди с фильтром по нужному айди, а также добавь пустое поле вместо отсутствующего status.
3. Полученные части имеют одинаковую структуру - объедини их через юнион, в рамках одного запроса.

В результате реальная выборка будет происходить либо в первом, либо во втором джойне. Но на выходе ты всегда будешь иметь результат.
Можно это сделать в виде вьюшки. Тогда если появятся таблицы 4, 5, 6,..., то ты сможешь их добавить в эту вьюшку.

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

_____________
* Хэлп по PHP
* Описалово по JavaScript
* Хэлп и СУБД для PostgreSQL

* Обучаю PHP, JS, вёрстке. Интерактивно и качественно. За разумные деньги.

* "накапливаю умение телепатии" (С) и "гуглю за ваш счет" (С)

user posted image
Quieteroks
sergeiss
Нет, id могут пересекаться. Разные таблицы могут иметь id 1,2,3...25, но в той же таблице пользователей их много, а админов пара человек допустим.

Что будут вьюхи делать? Извлекать дополнительную информацию?
Тогда опять таки возвращаемся к моему вопросу, каждую таблицу отдельно ворошить или одним запросов получить?

PS. Для данного примера, да, структура не верна и стоит их объединить, я это понимаю.
Но возникает ситуация, когда таблицы невозможно объединить.

Во, давайте пример с выпиской в интернет магазине (с личным счетом, куда можно положить средства для оплаты или каким то способ их заработать на сайте):
1. Пользователь может пополнить свой счет
2. Может на чем то заработать
3. Может перечислить кому либо средства
4. Можно купить товар

В итоге нужно писать выписку с названиями:
1. Пополнил счет (не идет пересечения с другими товарами)
2. Заработал по акции (тоже не пересекается, если не ведем названия акций)
3. Перечислил средства Пользователю (тот самый name в строке)
4. Приобрел Кружку (второй name, но явно в одну таблицу не поместим все это?)

В реале, я не храню саму строку в базе, а только ссылку на языковой файл.
Таблица такая:
entry, user, operation, with, amount

В выборку нужно собрать и имена пользователей и имена товаров.

В данном примере же нет сомнений, что неправильная структура может быть и мы должны товары хранить в одной таблице с пользователями? Или две выписки создавать? А как их потом объединять?

В принципе union наверно можно использовать:
В каждый из запросов просто внедряем where type = 0, во вторую where type = 1 с разным join. Структура ответа общая, тогда они же вполне верно объединяться?
Только как тогда будет выглядеть order by и limit?

Пошел читать справку по union.

UPD:
Да, union вполне справился с данной задачей...
Главное не потерять строки из запроса в последствии. Один из запросов должен быть как минимум left join, например с type = 0, как общедоступный, а type = 1 только inner.

Сортировка и лимит как я понял применяется к результату запроса union.
Еще ни разу не использовал union smile.gif

UPD2:
Кстати наверное такой запрос будет весьма сложно обслуживать.
А добавление третьей таблицы просто уничтожает желание его дописывать каждый раз.

Какая альтернатива этому имеется?
Что переложить на вьюху?

1. Делать основной запрос с объединением с самой вероятной таблицей.
2. Все что не попало в общий запрос, запросить дополнительно и отдельно?
dr.nomore
Такие проблемы возникают когда аффторы экономят на отношениях. Например влом добавить поле timestamp во все таблицы и начинается мутотень с

Цитата
Основная таблица собирательная, в примере это история чего-то (изменений Аккаунта допустим).


dr.nomore
Замечали что нельзя удалить запись в фейсбуках? Можно только скрыть ее, и то лишь заголовок в ленте. Потому что там не экономят на просранстве. Засирают его по любому поводу. Зато и таких вопросов как у ТС не возникает.

premature optimisation detected
Quieteroks
dr.nomore
Можно поинтересоваться? Вы второй пример (более удачный наверное) читали?
Скажите мне, как поле с временем поможет в данном вопросе (тоже пример не удачный...)?
Какое отношение и куда нудно добавить, что бы запрос получился корректным?

На каждый тип объединения (Товар, Пользователь...) добавлять по полю?
Вы про эти отношения?
mvg
Цитата (Quieteroks @ 21.11.2013 - 20:43)
Здравствуйте.

Подскажите, как лучше реализовать выборку различных данных из разных таблиц с условием в поле начальной таблицы?

Пример

1. Основная таблица:
id, type, with, operation

2. Таблица пользователей
id, name

3. Таблица с админами
id, status, name

В результате нужно получить имя Пользователя или Админа в зависимости от того, какой type стоит в основной таблице. Это нужно для подстановки в операцию этого самого имени.

На сколько я понял, что if нельзя использовать в инструкции from...
Компоновать запрос в php не выход, ибо из основной таблицы получается порядка 25 строк за раз. Вариантов много, вплоть до трех отдельных запросов на все три таблицы а после собирать их в php.

Какой вариант посоветуете Вы?

Сложно найти оптимальный вариант выборки, так как непонятны связи между таблицами (не видно reference).

Построив их, ответ скорее всего сам найдется.
sergeiss
Цитата (Quieteroks @ 22.11.2013 - 13:50)
Сортировка и лимит как я понял применяется к результату запроса union.

Всё это можно использовать и во внутренних запросах, составляющих ЮНИОН smile.gif Другое дело, что это не имеет никакого смысла.
Цитата (Quieteroks @ 22.11.2013 - 13:50)
Да, union вполне справился с данной задачей...

Покажи запрос. Оценим, посмотрим, что ты там сделал. Может быть, что-то полезное посоветуем.

_____________
* Хэлп по PHP
* Описалово по JavaScript
* Хэлп и СУБД для PostgreSQL

* Обучаю PHP, JS, вёрстке. Интерактивно и качественно. За разумные деньги.

* "накапливаю умение телепатии" (С) и "гуглю за ваш счет" (С)

user posted image
Quieteroks
Ну что то такое получилось:
SELECT	i.entry		AS id,
i.type AS type,
u.name AS name,
i.amount AS amount,
i.time AS time
FROM invoice AS i
INNER JOIN user AS u
ON i.with = u.id
WHERE i.type = 0

UNION

SELECT
i.entry AS id,
i.type AS type,
u.title AS name,
i.amount AS amount,
i.time AS time
FROM invoice AS i
LEFT JOIN item AS u
ON i.with = u.id
WHERE i.type = 1

ORDER BY id DESC
LIMIT
25


В любом случае весьма габаритно получается...
sergeiss
Цитата (Quieteroks @ 23.11.2013 - 19:18)
В любом случае весьма габаритно получается...

Ну а ты как хотел? Главное, чтобы быстро работал. То же, что "габаритно", это не критично smile.gif Ты хочешь узнать, что такое "габаритно", да? wink.gif Тогда зайди в эту http://phpforum.ru/index.php?showtopic=50424&hl= тему и посмотри (просмотри до конца всё). И ты поймешь, что у тебя очень даже скромный, компактный запрос smile.gif

Цитата (Quieteroks @ 22.11.2013 - 13:50)
Что будут вьюхи делать? Извлекать дополнительную информацию?

Вот этот запрос как раз во вьшку и можно положить.

_____________
* Хэлп по PHP
* Описалово по JavaScript
* Хэлп и СУБД для PostgreSQL

* Обучаю PHP, JS, вёрстке. Интерактивно и качественно. За разумные деньги.

* "накапливаю умение телепатии" (С) и "гуглю за ваш счет" (С)

user posted image
Быстрый ответ:

 Графические смайлики |  Показывать подпись
Здесь расположена полная версия этой страницы.
Invision Power Board © 2001-2024 Invision Power Services, Inc.