SQLinfo.ru - Все о MySQL

Форум пользователей MySQL

Задавайте вопросы, мы ответим

Вы не зашли.

#1 30.08.2010 23:37:09

GrandAgr
Участник
Зарегистрирован: 30.08.2010
Сообщений: 2

Нужна помощь с запросом выборки

Имеется несколько таблиц (несущественные поля не показываю)

Таблица 1 (договора):


CREATE TABLE `db_agreement` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `fio_agreementer` varchar(40) DEFAULT NULL,
  PRIMARY KEY (`id`)
 ) ENGINE=MyISAM DEFAULT CHARSET=cp1251


Таблица 2 (услуги):

CREATE TABLE `db_service` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `use_begin` date NOT NULL DEFAULT '0000-00-00',
  `use_end` date NOT NULL DEFAULT '0000-00-00',
  `id_service_name` int(11) unsigned DEFAULT NULL,
  `id_agreement` int(11) unsigned NOT NULL DEFAULT '0',
  `id_service_prev` int(10) unsigned DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `id_agreement` (`id_agreement`),
  KEY `use_end` (`use_end`),
  KEY `use_begin` (`use_begin`),
  KEY `id_service_prev` (`id_service_prev`),
  KEY `combo` (`id_agreement`,`use_begin`,`use_end`),
  KEY `combo2` (`use_begin`,`use_end`),
  KEY `combo3` (`use_begin`,`use_end`,`id_service_name`)
) ENGINE=MyISAM DEFAULT CHARSET=cp1251


Таблица 3 (наименование услуг):

CREATE TABLE `db_service_name` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `ID` (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=cp1251



Связи между таблицами и полями следующие:

db_service.id_agreement   --->   db_agreement.id
db_service.id_service_name  --->  db_service_name.id
db_service.id_service_prev   ---> db_service.id   (ID предыдущей услуги)



Требуется помощь в составлении выборки, причем по каждому договору необходимо выбрать ТОЛЬКО последнюю услугу (с максимальным db_service.id, причем дата окончания db_service.use_end должна быть или '0000-00-00' или разница между NOW() и db_service.use_end не более 90 дней). Выборку к тому же необходимо производить по условию db_service_name.id = определенное значение (будет задаваться скриптом на PHP)....
Одновременно на договоре может быть активной только 1 услуга.. Если производится смена услуги, то предыдущей услуге ставится дата закрытия и новой услуге устанавливается значение поля db_service.id_service_prev, равное db_service.id предыдущей услуги. "Подводные камни" - на договоре могут быть одинаковые услуги в разное время.. но активная - только одна.

Выбирать необходимо след. поля:

db_agreement.id
db_service.id
db_service.use_begin
db_service.use_end
db_service_name.name

Надеюсь, что сформулировал не очень сумбурно. Заранее благодарю за готовый запрос или указание куда "копать"

Неактивен

 

#2 31.08.2010 00:00:13

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6757

Re: Нужна помощь с запросом выборки

Честно говоря, не вижу, почему это нельзя написать «в лоб»:
SELECT MAX(id) AS id
FROM db_service
WHERE id_service_name = $id AND (use_end = '0000-00-00' OR use_end >= NOW() - INTERVAL 90 DAY)
GROUP BY id_agreement

Ну и
SELECT нужные поля
FROM список таблиц
WHERE условия связи AND db_service.id IN (подзапрос выше)

Неактивен

 

#3 31.08.2010 02:13:33

GrandAgr
Участник
Зарегистрирован: 30.08.2010
Сообщений: 2

Re: Нужна помощь с запросом выборки


SELECT
  service.id,
  service.fio_agreementer,
  service.use_begin,
  service.use_end,
  srvn.name
FROM db_service service
  INNER JOIN db_agreement agr
    ON agr.id = service.id_agreement
  INNER JOIN db_service_name srvn
    ON service.id_service_name = srvn.id
WHERE service.id IN(SELECT
                  MAX(id)
                FROM db_service
                WHERE id_service_name = $id
                    AND (use_end = '0000-00-00'
                          OR use_end >= (NOW() - INTERVAL 90 DAY))
                GROUP BY id_agreement)
ORDER BY agr.id DESC


Возможна ли модернизация данного запроса в плане ускорения работы выборки?

Неактивен

 

#4 31.08.2010 12:56:51

Lem0nti
Гуру
Откуда: Северная Пальмира
Зарегистрирован: 08.11.2007
Сообщений: 98

Re: Нужна помощь с запросом выборки

Можно избавиться от внутреннего селекта

SELECT
  max(service.id),
  service.fio_agreementer,
  service.use_begin,
  service.use_end,
  srvn.name
FROM db_service service
  INNER JOIN db_agreement agr
    ON agr.id = service.id_agreement
  INNER JOIN db_service_name srvn
    ON service.id_service_name = srvn.id
  WHERE service.id_service_name = $id
  AND (service.use_end = '0000-00-00' OR service.use_end >= (NOW() - INTERVAL 90 DAY))
  GROUP BY service.fio_agreementer,service.use_begin,service.use_end,srvn.name
  ORDER BY agr.id DESC

Неактивен

 

Board footer

Работает на PunBB
© Copyright 2002–2008 Rickard Andersson