обойти вложенный запрос

admGT

Новичок
обойти вложенный запрос

Имеется 4 таблицы: CREATE TABLE `locations` (
`locId` int(11) NOT NULL AUTO_INCREMENT,
`locName` text NOT NULL,
PRIMARY KEY (`locId`)
) ENGINE=MyISAM;

CREATE TABLE `objects` (
`objectId` int(11) NOT NULL AUTO_INCREMENT,
`objectName` text,
`locId` tinyint(4) NOT NULL,
PRIMARY KEY (`objectId`)
) ENGINE=MyISAM ;

CREATE TABLE `orders` (
`setId` int(11) NOT NULL,
`objectId` int(11) NOT NULL,
PRIMARY KEY (`setId`)
) ENGINE=InnoDB;

CREATE TABLE `sets` (
`setId` int(11) NOT NULL AUTO_INCREMENT,
`termDate` datetime NOT NULL,
PRIMARY KEY (`setId`)
) ENGINE=InnoDB;

В реале таблицы конечно имеют больше полей, но для упрощения задачи они опущены.
Задача: Имеется таблица locations, допустим, содержащая города (id, название), objects - филиалы (id,название,id города), заказы sets, содержащая id заказа и дату заказа, orders - соединительная таблица (id заказа, id филиала)
Необходимо выбрать количество заказов по каждому из филиалов за сегодня. Если заказов сегодня нет, необходимо написать 0 )

Пишем запрос: SELECT COUNT(`sets`.`setId`) AS `cntDay`,`locations`.`locName`,`objects`.`objectName` FROM `sets` STRAIGHT JOIN `orders` ON `sets`.`setId`=`orders`.`setId` JOIN `objects` ON `objects`. `objectId`=`orders`.`objectId` JOIN `locations` ON `locations`.`locId`=`objects`.`locId` WHERE `sets`.`termDate`>CURDATE() GROUP BY `objects`.`objectId`

При этом запросе, если за сегодня заказов нет, то и locName и objectName отображаться не будут. Как можно побороть? Первая мысль была использовать вложенный селект, в который поместить count(`setId`). Даже если количество заказов за сегодня равно нулю, название филиала будет выведено. Но отказался от такого решения в связи с жуткими тормозами.
 

akd

dive now, work later
Команда форума
почитать про EXPLAIN, LEFT JOIN, индексы и хорошо подумать нужен ли в действительности STRAIGHT
 

admGT

Новичок
EXPLAIN в данном случае к чему? я тестировал им - все корректно. LEFT JOIN тоже никак не отразится на результате. Можете потестировать) Все запросы приведены. И дописать LEFT переставив таблицы местами тоже нетрудоемко.
 

iceman

говнокодер
SELECT t.objectId, COUNT(t.setId) FROM orders as t
WHERE <условие_по_дате>
GROUP BY t.objectId

вроде бы так...

и зачем таблица orders? 1 заказ может быть у 2-х филиалов?
 

prolis

Новичок
Автор оригинала: admGT
Можете потестировать)
Т.е. ты нам предлагаешь такую вот задачку, что бы доказать нам самим что это действительно сложно?
Тебе уже главное ответили в первом ответе.
 

admGT

Новичок
Автор оригинала: iceman
SELECT t.objectId, COUNT(t.setId) FROM orders as t
WHERE <условие_по_дате>
GROUP BY t.objectId

вроде бы так...

и зачем таблица orders? 1 заказ может быть у 2-х филиалов?
Здесь приведена часть структуры базы и таблицы усечены по полям только для решения данной задачи. Можно ее выбросить для упрощения решения здесь. В боевой системе я перепишу как нужно, если появится идея.

Ваше решение не подходит.

-~{}~ 02.07.10 11:00:

Автор оригинала: prolis
Т.е. ты нам предлагаешь такую вот задачку, что бы доказать нам самим что это действительно сложно?
Тебе уже главное ответили в первом ответе.
Я конкретно Вам ничего не предлагаю. Я ищу решение. Возможно кто-то с этим сталкивался.
 

iceman

говнокодер
этот запрос должен вывести кол-во заказов по каждому филиалу, этот запрос можно использовать в под запросе, чтобы решить твою другую задачу..

ВЫВОДИТЬ ПОЛЯ КОТОРЫЕ НЕ УКАЗАНЫ В УСЛОВИЕ ГРУППИРОВКИ НЕЛЬЗЯ, даже если БД позволяет это, нормальная БД ругается на это...
 

akd

dive now, work later
Команда форума
Автор оригинала: admGT
Я конкретно Вам ничего не предлагаю. Я ищу решение. Возможно кто-то с этим сталкивался.
удачи :)
пс. когда надоест искать, сходи в мануал и все-таки почитай что-нибудь.
 

admGT

Новичок
Автор оригинала: iceman
ВЫВОДИТЬ ПОЛЯ КОТРЫЕ НЕ УКАЗАНЫ В УСЛОВИЕ ГРУППИРОВКИ НЕЛЬЗЯ, даже если БД позволяет это, нормальная БД ругается на это...
Можно в выбираемые поля добавить поле, по которому группировка происходит. Не суть. В итоге проблему это не решает.
 

iceman

говнокодер
ты спорить сюда пришел?

> Можно в выбираемые поля добавить поле, по которому группировка происходит...

я это и говорю,

в твоем запросе GROUP BY `objects`.`objectId`

а ты пытаешся вывести `locations`.`locName`,`objects`.`objectName`

этого делать нельзя, я не знаю почему МуСкул на это не ругается, но сам подумай как он выведит поле, если произошла групировка, по какому критерию?


> При этом запросе, если за сегодня заказов нет

COUNT = 0?
 

admGT

Новичок
Автор оригинала: akd
удачи :)
пс. когда надоест искать, сходи в мануал и все-таки почитай что-нибудь.
Спасибо за пожелание! Мануал читан и запросов с LEFT JOIN писано немало. Если я переставлю таблицы местами и начну склеивать с location,objects,orders,sets тормоза будут тоже достаточно серьезные, поскольку sets достаточно объемная таблица и ее я предпочел поставить на первое место в склейке.
 

akd

dive now, work later
Команда форума
/me сел поудобнее и достал попкорн :)
 

admGT

Новичок
Автор оригинала: iceman
ты спорить сюда пришел?

> Можно в выбираемые поля добавить поле, по которому группировка происходит...

я это и говорю,

в твоем запросе GROUP BY `objects`.`objectId`

а ты пытаешся вывести `locations`.`locName`,`objects`.`objectName`

этого делать нельзя, я не знаю почему МуСкул на это не ругается, но сам подумай как он выведит поле, если произошла групировка, по какому критерию?
Специально для Вас: SELECT COUNT(`sets`.`setId`) AS `cntDay`,`locations`.`locName`,`objects`.`objectName`,`objects`.`objectId` FROM `sets` STRAIGHT JOIN `orders` ON `sets`.`setId`=`orders`.`setId` JOIN `objects` ON `objects`. `objectId`=`orders`.`objectId` JOIN `locations` ON `locations`.`locId`=`objects`.`locId` WHERE `sets`.`termDate`>CURDATE() GROUP BY `objects`.`objectId`

проблему это не решает.
 

prolis

Новичок
"Широко известна шутка о потерянных часах, которые "надо искать под фонарем, потому что там светло". Искать там, где светло, - вполне естественное устремление каждого субъекта, в том числе и ученого-исследователя."
 

iceman

говнокодер
PHP:
select z.objectName, y.cnt from objects z
inner join (
  SELECT t.objectId, COUNT(t.setId) cnt FROM orders t
  inner join sets x on x.setId = t.setId
  WHERE x.termDate > CURDATE()
  GROUP BY t.objectId
) y on y.objectId = z.objectId
 

admGT

Новичок
Автор оригинала: prolis
"Широко известна шутка о потерянных часах, которые "надо искать под фонарем, потому что там светло". Искать там, где светло, - вполне естественное устремление каждого субъекта, в том числе и ученого-исследователя."
Бывает, думаешь над задачей и замыливаешься. Именно для этого я пришел на форум, а не потому что масса свободного времени. Максимально описал задачу, чтобы избежать обвинений в том, что прошу за меня что то решить. курить мануал - не ответ на вопрос. Мануал курен. Я пришел сюда за советом, а не для того, чтобы кто-то самоутверждался за мой счет.

-~{}~ 02.07.10 11:25:

iceman именно вложенных запросов и хочется избежать
 

admGT

Новичок
akd SELECT COUNT(`sets`.`setId`) AS `cntDay`,`locations`.`locName`,`objects`.`objectName`,`objects`.`objectId` FROM `locations` LEFT JOIN `objects` ON `locations`.`locId`=`objects`.`locId` LEFT JOIN `orders` ON `objects`. `objectId`=`orders`.`projectId` LEFT JOIN `sets` ON `sets`.`setId`=`orders`.`setId` WHERE `sets`.`termDate`>CURDATE() GROUP BY `objects`.`objectId`

так же ничего не отдает при отсутствии заказов.
 

akd

dive now, work later
Команда форума
admGT, это означает что уже настало время, когда надо начать читать как дебажить SQL :)
 

prolis

Новичок
что вернёт?
[sql]
select o.id, sts.termDate, count(distinct ord.objectid) from objects obj
left join orders ord on (obj.id=ord.objectid)
left join sets sts on (ord.setid=sts.setid)
group by o.id, sts.termDate
[/sql]
 
Сверху