2014-09-12 1 views
0

Позвольте мне объяснить мою цель сначала, у меня есть приложение для бронирования автомобилей, где посетитель добавит дату начала и дату окончания своего путешествия, в базе данных есть список драйверов с наличием (available_from_date и available_to_date), который является длительностью, в течение которой они работают, есть поле для исключений_данных для некоторых конкретных дат, когда они не работают. Приложение должно найти список транспортных средств, которые доступны в течение дат поездки, введенных пользователем. например, пользователь вводит, что он хочет перейти от места A до B в течение 13-го перерыва, с 2014 года по 17 сентября 2014 года , тогда база данных должна вернуть список такси, которые доступны в течение этого периода, и не должны иметь никакой даты исключения в течение этого периода ,с использованием mysql хранимой функции с выбранным запросом

Теперь я сохранил exclude_dates в формате, разделенном запятыми, в таблице (я мог бы создать отдельную таблицу, но тогда для выполнения запроса потребуется намного больше времени) Я пытался создать функцию mysql, которая была бы вызванный внутри фактического поискового запроса и вернет true, если есть какая-то некоторая исключенная дата, присутствующая в течение продолжительности, и false, если нет.

эти запросы, которые я написал

SELECT id, exclude_dates 
FROM `taxi_route` 
WHERE status = 1 
    AND `to_city` = 'Surat' 
    AND `from_city` = 'Ahmedabad' 
    AND `trip_type` = 2 
    AND `available_from_date` <= '2014-09-13' 
    AND available_to_date >= '2014-09-17' 
    AND STR_TO_DATE((SELECT `split`(exclude_dates, ',', 1)),'%d-%m-%Y') 
     NOT BETWEEN STR_TO_DATE('13-09-2014','%d-%m-%Y') 
       AND STR_TO_DATE('17-09-2014','%d-%m-%Y') 

Split является функцией я создал в MySQL, чтобы отделить даты, присутствующие в формате разделителями

DELIMITER $$ 

CREATE FUNCTION split(str VARCHAR(500), delchar VARCHAR(2), x INT) 
RETURNS VARCHAR(500) 
BEGIN 
RETURN SUBSTR(SUBSTRING_INDEX(str, delchar, x), 
LENGTH(SUBSTRING_INDEX(str, delchar, x-1))+IF(x > 1, 2, 1)); 
END$$ 

DELIMITER ; 

это работает отлично, насколько я передать 1 в split (exclude_dates, ',', 1), но если у exclude_dates больше одной даты, тогда это не сработает может кто-то может предложить или указать, как это можно сделать. моментальный снимок базы данных находится здесь http://i.imgur.com/JaI8MSx.png

+0

Остановить это -> 'STR _TO_DATE() ' – Kermit

+0

hi @Kermit, спасибо за комментирование, но нам не нужно преобразовывать строку, заданную пользователем, в допустимый формат даты, и exclude_dates является varchar, и когда мы извлекаем дату из нее, это будет строка, которая снова необходимо преобразовать в формат даты? –

+0

Вы не должны хранить дату в виде строки. – Kermit

ответ

0

Ваш запрос, скорее всего, займет больше времени, чем определение отдельной таблицы для exclusion dates. Это не является хорошей практикой, используя список разделенных запятыми внутри столбца для поиска, это противоречит правилам нормализации.

Вы должны определить свои таблицы отдельно (например, такси, такси_route, taxi_route_exclusion, route_exclusion), а затем добавить необходимые индексы, чтобы сделать ваши поиски более эффективными.

Пример:

 
taxi 
--------- 
id 
country 
*** 
*** 
*** 
 
taxi_route 
------------------- 
id 
taxi_id 
available_from_date 
available_to_date 
from_city 
to_city 
 
route_exclusion 
--------------- 
id 
taxi_id 
exclusion_date 

А также добавить таблицу соотношение между taxi_route и route_exclusion таблиц для представления многие-ко-многим. Позже определите внешние ключи по таблице taxi_route_route_exclusion в таблице taxi_route и route_exclusion таблиц.

 
taxi_route_route_exclusion 
-------------------------- 
taxi_route_id 
route_eclusion_id 

Определить внешние ключи, как:

  • taxi_route.taxi_id -> taxi.id
  • taxi_route_route_exclusion.taxi_route_id -> taxi_route.id
  • taxi_route_route_exclusion.route_exclusion_id -> route_exclusion.ID

Определение индексов, как:

  • такси: IX1 (статус, trip_type)
  • taxi_route: IX1 (to_city, from_city, available_from_date, available_to_date)

Ваш последний запрос должен выглядят так:

SELECT tr.id, re.exclusion_date 
FROM `taxi_route` tr JOIN `taxi_route_route_exclusion` trre 
    ON tr.id = trre.taxi_route_id 
JOIN `route_exclusion` re 
    ON re.id = trre.route_exclusion_id 
JOIN `taxi` t 
    ON t.id = tr.id 
WHERE 
    t.status = 1 
    AND t.trip_type = 2 
    AND tr.to_city = 'Surat' 
    AND tr.from_city = 'Ahmedabad' 
    AND tr.available_from_date <= '2014-09-13' 
    AND tr.available_to_date >= '2014-09-17' 
+0

привет, советник, спасибо за объяснение, но я думаю, что хранимая процедура или функция выполнялись бы намного быстрее, чем соединялись бы на mysql, у нас могли бы быть тысячи таких записей, а затем многие исключающие_даты в каждом из них с использованием объединения будут потреблять много времени и память, а хранимая процедура просто вернет результат в форме да или нет, используя который мы можем иметь обычный запрос выбора, который проверяет только, есть ли какая-то исключенная дата между поездкой или нет. [пожалуйста, поправьте меня, если я ошибаюсь] –

+0

Использование функций приведет к их вызову для каждой возвращенной записи. В зависимости от вашего запроса он может возвращать результаты гораздо медленнее, чем sql-соединения, что, по-видимому, не является хорошим подходом в вашем случае. Кроме того, соединения намного яснее функций; если вы можете написать свой запрос в одном заявлении, а не использовать функции, ваш запрос будет более читабельным. Использование хранимых процедур - это нечто иное. Вы можете определить свою хранимую процедуру и записать указанный выше запрос в определение. Для повышения производительности рассмотрите использование индексов. – oardic

+0

Здравствуйте, @oardic, я попытался реализовать ваше предложение, добавив новую таблицу транзакций taxi_route_excluded_dates, у нас не может быть другой таблицы route_exclusion, так как исключенные даты добавляются в отношении самого маршрута. например, для примера водитель D работает от места A до места B с 1-го числа каждого месяца до 10, затем он работает от места B до C от 11 до 20, затем от X до Y от 21 до 30, НО он не работает на 5-м, 15-й и 25-й даты месяца, и, следовательно, система не должна показывать свое такси, если кто-то планирует совершить поездку на или в течение этих исключенных дат/с. –