Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Web программирование > SQL, базы данных
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 04.06.2010, 13:28   #1
slips
Форумчанин
 
Аватар для slips
 
Регистрация: 28.10.2008
Сообщений: 350
По умолчанию SQL запрос в MYSQL для интервала дат

Добрый день вторые сутки мучаюсь составить следующий запрос.
Есть таблица следующего вида :
cId cDate cIdTovat
1 2010-01-01 1
1 2010-01-02 1
1 2010-01-03 2
1 2010-01-04 1
1 2010-01-05 2

Где cDate - это дата на которую будет выставлен товар, cIdTovar - соответственно id- товара

Нужно получить результат следующего вида для товара 1:
2010-01-01 по 2010-01-02, 2010-01-04
Подскажите как это можно сделать, очень нужно.
slips вне форума Ответить с цитированием
Старый 04.06.2010, 13:53   #2
Serge_Bliznykov
Старожил
 
Регистрация: 09.01.2008
Сообщений: 26,229
По умолчанию

ничего не утверждаю, но попробуйте такой запрос:
Код:
select min(cDate) as TovarBegin, max(cDate) as TovarEnd,
  cIdTovar from ВашаТаблица
group by cIdTovar

МОЖЕТЕ НЕ ПРОБОВАТЬ!
я проглядел, что Вам даты нужны без пропусков собирать в диапазоны,
а даты с пропусками писать через запятую...
Я такое только через ХП (или код на клиенте) умею делать..
а в SQL — мне такое сделать слабо...
Serge_Bliznykov вне форума Ответить с цитированием
Старый 04.06.2010, 14:31   #3
slips
Форумчанин
 
Аватар для slips
 
Регистрация: 28.10.2008
Сообщений: 350
По умолчанию

Я полностью согласен с вами Сергей , что на чистом SQL - запросе не сделать. А как ХП делать в MYSQL понятия не имею.
slips вне форума Ответить с цитированием
Старый 04.06.2010, 20:12   #4
slips
Форумчанин
 
Аватар для slips
 
Регистрация: 28.10.2008
Сообщений: 350
По умолчанию

А если таблица будет исключительно содержать вот такие последовательности ?
cId cDate cIdTovat
1 2010-01-01 1
2 2010-01-02 1
3 2010-01-04 1
4 2010-01-05 1
slips вне форума Ответить с цитированием
Старый 05.06.2010, 06:45   #5
Serge_Bliznykov
Старожил
 
Регистрация: 09.01.2008
Сообщений: 26,229
По умолчанию

Цитата:
А если таблица будет исключительно содержать вот такие последовательности ?
это абсолютно непринципиально!
в любом случае при решении нужно сортировать (или даже отбирать) по товарам, а внутри сортировать по датам...

Цитата:
А как ХП делать в MYSQL понятия не имею.
к сожалению, я тоже...
но, судя по всему, это возможно...
вот, посмотрите через поиск на Гугле - результаты поиска

а Вы клиентскую часть на чём пишете? Может на клиенте подобное решение написать?
Serge_Bliznykov вне форума Ответить с цитированием
Старый 05.06.2010, 15:46   #6
slips
Форумчанин
 
Аватар для slips
 
Регистрация: 28.10.2008
Сообщений: 350
По умолчанию

Цитата:
Сообщение от Serge_Bliznykov Посмотреть сообщение
это абсолютно непринципиально!
а Вы клиентскую часть на чём пишете? Может на клиенте подобное решение написать?
Да стандрат серверную- PHP, клиент JS (были мысли написать на JS какую то функцию, ну что то меня отталкивает)
slips вне форума Ответить с цитированием
Старый 05.06.2010, 19:16   #7
slips
Форумчанин
 
Аватар для slips
 
Регистрация: 28.10.2008
Сообщений: 350
По умолчанию Решение было найдено, возникает проблема с переустановкой ключа

Код:
SET @id0 := 0;
SET @id1 := 0;
select  B.row_number, A.cdate as StartDate, B.cdate as EndDate FROM (
SELECT @id0 := @id0 + 1 AS row_number,T.*
FROM (
  SELECT O.cdate,O.cparentUsl FROM `sUslugaDateTovar` O
  WHERE O.cparentUsl =1  AND EXISTS(SELECT `cdate` 
  FROM `sUslugaDateTovar` K  WHERE ((to_days( O.cdate ) +1) = to_days(K.cdate) OR (to_days( O.cdate ) -1) = to_days(K.cdate )) AND O.cparentUsl =1)
ORDER BY O.cdate
)  T 
WHERE NOT DATE_ADD(T.cdate, INTERVAL -1 DAY) IN (SELECT cdate 
FROM (
  SELECT O.cdate,O.cparentUsl FROM `sUslugaDateTovar` O
  WHERE O.cparentUsl =1  AND EXISTS(SELECT `cdate` 
  FROM `sUslugaDateTovar` K  WHERE ((to_days( O.cdate ) +1) = to_days(K.cdate) OR (to_days( O.cdate ) -1) = to_days(K.cdate )) AND O.cparentUsl =1)
ORDER BY O.cdate
)  L 
)
   ) A
 INNER JOIN (
SELECT @id1 := @id1 + 1 AS row_number,T.*
FROM (
  SELECT O.cdate,O.cparentUsl FROM `sUslugaDateTovar` O
  WHERE O.cparentUsl =1  AND EXISTS(SELECT `cdate` 
  FROM `sUslugaDateTovar` K  WHERE ((to_days( O.cdate ) +1) = to_days(K.cdate) OR (to_days( O.cdate ) -1) = to_days(K.cdate )) AND O.cparentUsl =1)
ORDER BY O.cdate
)  T 
WHERE NOT DATE_ADD(T.cdate, INTERVAL +1 DAY) IN (SELECT cdate 
FROM (
  SELECT O.cdate,O.cparentUsl FROM `sUslugaDateTovar` O
  WHERE O.cparentUsl =1  AND EXISTS(SELECT `cdate` 
  FROM `sUslugaDateTovar` K  WHERE ((to_days( O.cdate ) +1) = to_days(K.cdate) OR (to_days( O.cdate ) -1) = to_days(K.cdate )) AND O.cparentUsl =1)
ORDER BY O.cdate
)  L 
)
  ) B ON (A.row_number=B.row_number)

Собственно код разбивается на две части 1 часть(находим границы максимума)
Код:
 SELECT *
FROM (
  SELECT O.cdate,O.cparentUsl FROM `sUslugaDateTovar` O
  WHERE O.cparentUsl =1  AND EXISTS(SELECT `cdate` 
  FROM `sUslugaDateTovar` K  WHERE ((to_days( O.cdate ) +1) = to_days(K.cdate) OR (to_days( O.cdate ) -1) = to_days(K.cdate )) AND O.cparentUsl =1)
ORDER BY O.cdate
)  T 
WHERE NOT DATE_ADD(T.cdate, INTERVAL +1 DAY) IN (SELECT cdate 
FROM (
  SELECT O.cdate,O.cparentUsl FROM `sUslugaDateTovar` O
  WHERE O.cparentUsl =1  AND EXISTS(SELECT `cdate` 
  FROM `sUslugaDateTovar` K  WHERE ((to_days( O.cdate ) +1) = to_days(K.cdate) OR (to_days( O.cdate ) -1) = to_days(K.cdate )) AND O.cparentUsl =1)
ORDER BY O.cdate
)  L 
)
Часть №2 (находим границы минимума)
Код:
SELECT *
FROM (
  SELECT O.cdate,O.cparentUsl FROM `sUslugaDateTovar` O
  WHERE O.cparentUsl =1  AND EXISTS(SELECT `cdate` 
  FROM `sUslugaDateTovar` K  WHERE ((to_days( O.cdate ) +1) = to_days(K.cdate) OR (to_days( O.cdate ) -1) = to_days(K.cdate )) AND O.cparentUsl =1)
ORDER BY O.cdate
)  T 
WHERE NOT DATE_ADD(T.cdate, INTERVAL -1 DAY) IN (SELECT cdate 
FROM (
  SELECT O.cdate,O.cparentUsl FROM `sUslugaDateTovar` O
  WHERE O.cparentUsl =1  AND EXISTS(SELECT `cdate` 
  FROM `sUslugaDateTovar` K  WHERE ((to_days( O.cdate ) +1) = to_days(K.cdate) OR (to_days( O.cdate ) -1) = to_days(K.cdate )) AND O.cparentUsl =1)
ORDER BY O.cdate
)  L 
)
Далее обьединяем их, проблема собствено в чём что для каждой таблицы приходиться делать своё уникальное поле(что существенно влияет на скорость выполнения скрипта) чтобы потом можно было обьединить.

Есть какие нибудь предложения по поводу ключей ?
И может у кого-то есть мысли по поводу оптимизации кода, самое существенное это как то минимизировать следующий код
Код:
SELECT O.cdate,O.cparentUsl FROM `sUslugaDateTovar` O
  WHERE O.cparentUsl =1  AND EXISTS(SELECT `cdate` 
  FROM `sUslugaDateTovar` K  WHERE ((to_days( O.cdate ) +1) = to_days(K.cdate) OR (to_days( O.cdate ) -1) = to_days(K.cdate )) AND O.cparentUsl =1)
ORDER BY O.cdate
Он по своей сути формирует последовательности вида:
1 2010-01-01 1
2 2010-01-02 1
3 2010-01-04 1
4 2010-01-05 1
ИЗ
1 2010-01-01 1
1 2010-01-02 1
1 2010-01-03 2
1 2010-01-04 1
1 2010-01-05 2
Видимо как всегда придётся додумывать всё самому, и делать из невозможного возможное ... эх.

Последний раз редактировалось slips; 05.06.2010 в 19:45. Причина: редактирование
slips вне форума Ответить с цитированием
Старый 05.06.2010, 21:41   #8
slips
Форумчанин
 
Аватар для slips
 
Регистрация: 28.10.2008
Сообщений: 350
По умолчанию

Немного упрощённый P.S я его сделаю гибким
Код:
SET @id0 := 0;
SET @id1 := 0;
select  B.row_number, A.cdate as StartDate, B.cdate as EndDate FROM (
SELECT @id0 := @id0 + 1 AS row_number,T.*
FROM (
  SELECT O.cdate,O.cparentUsl FROM `sUslugaDateTovar` O
  WHERE O.cparentUsl =1  AND EXISTS(SELECT `cdate` 
  FROM `sUslugaDateTovar` K  WHERE ((to_days( O.cdate ) +1) = to_days(K.cdate) OR (to_days( O.cdate ) -1) = to_days(K.cdate )) AND K.cparentUsl =1)
ORDER BY O.cdate
)  T 
WHERE  NOT DATE_ADD(T.cdate, INTERVAL -1 DAY) IN (SELECT O.cdate FROM `sUslugaDateTovar` O 
   WHERE  O.cparentUsl =1 ORDER BY O.cdate)  
) A
 INNER JOIN (
SELECT @id1 := @id1 + 1 AS row_number,T.*
FROM (
  SELECT O.cdate,O.cparentUsl FROM `sUslugaDateTovar` O
  WHERE O.cparentUsl =1  AND EXISTS(SELECT `cdate` 
  FROM `sUslugaDateTovar` K  WHERE ((to_days( O.cdate ) +1) = to_days(K.cdate) OR (to_days( O.cdate ) -1) = to_days(K.cdate )) AND K.cparentUsl =1)
ORDER BY O.cdate
)  T 
WHERE  NOT DATE_ADD(T.cdate, INTERVAL +1 DAY) IN (SELECT O.cdate FROM `sUslugaDateTovar` O 
     WHERE  O.cparentUsl =1 ORDER BY O.cdate)  
) B ON (A.row_number=B.row_number)
Результат отображается в следующем виде:
в таблице это в таком виде
cId cDate cIdTovat
1 2010-01-01 1
2 2010-01-02 1
3 2010-01-03 1
.
...
10 2010-01-07 1
11 2010-01-08 1

РЕЗУЛЬТАТ ВЫБОРКИ:
row_number StartDate EndDate
1 2010-01-01 2010-01-03
2 2010-01-07 2010-01-08

Последний раз редактировалось slips; 06.06.2010 в 01:30. Причина: редактирование
slips вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
SQL запрос для строк! Milishka БД в Delphi 8 21.04.2010 13:23
НАдо сделать запрос на SQL для MS Access! Artanis SQL, базы данных 9 05.11.2009 15:03
SQL запрос для поиска в связаных таблицах. Хитрец БД в Delphi 12 18.04.2009 14:46
Как организовать поиск интервала дат через SQL Selena Общие вопросы Delphi 1 14.03.2007 01:25
SOL-запрос интервала даты и времени в Delphi DENIS_ БД в Delphi 5 23.12.2006 12:55