2015-12-09 5 views
0

Я знаю, что есть десятки вопросов «выберите первую строку», но у меня есть интересная ситуация, которую я не думаю, что могу исправить с помощью LIMIT.MySQL выбирает первую строку таблицы

Я пытаюсь показать свойства, доступные между датой начала и окончания, с доступными N днями. Я так близок.

Я собираюсь разбить этот запрос на части, потому что он большой.

Блокированные Даты (часть 1)

(SELECT c.id,c.property_id,c.start_date,c.end_date FROM property_calendar as c WHERE c.start_date <= '.$endQuote.' AND c.end_date >= '.$startQuote) 
UNION 
(SELECT l.id,l.property_id,l.start_date,l.end_date FROM lease as l WHERE l.start_date <= '.$endQuote.' AND l.end_date >= '.$startQuote.' AND l.status < 6) 
ORDER BY start_date ASC 

Этот союз разбивает наши два календаря вместе для удобства сравнения. Каждая запись имеет start_date и end_date. Даты, которые попадают между (включая начало и конец), считаются недоступными.

Калькулятора (часть 2)

SELECT IFNULL(DATEDIFF(IFNULL(ct2.start_date, '2015-12-09'), ct1.end_date) - 1, 0) as open_days, 
(DATEDIFF(ct1.start_date, '2015-12-01') - 1) as first_open, 
IFNULL(DATEDIFF(LEAST(ct1.end_date, '2015-12-09'), GREATEST(ct1.start_date, '2015-12-01')) + 1, 0) as blocked_days, 
ct1.property_id as property_id 
FROM ({blocked dates}) as ct1 
LEFT JOIN ({blocked dates}) as ct2 ON ct2.property_id = ct1.property_id AND ct2.start_date > ct1.end_date 
GROUP BY ct1.property_id,ct1.start_date 

Это занимает таблицу в части 1, и соединяет его к себе позволяет нам сравнивать предыдущую заблокированную дату со следующим. open_days - это отрицательное пространство между каждой заблокированной датой. blocked_days - это сколько дней заблокировано в ct1. Часть, вызывающая проблемы, - first_open.

Этот запрос работает, если только первая заблокированная дата не была выполнена после даты начала, которую дал пользователь. В этом случае мы пропускаем подсчет этих первых нескольких дней, которые открыты. Итак, частью моего решения было добавить first_open, который просто вычисляет DATEDIFF(ct1.start_date, {the given start date}).

Окончательная сумма

SELECT cj.property_id, 
IFNULL(SUM(cj.blocked_days), 0) as total_blocked, 
IFNULL(GREATEST(MAX(cj.open_days), MAX(cj.first_open)), 0) as consec_days_avail 
FROM {the calculator} as cj 

Как я уже говорил, здесь, где у меня есть проблемы. Выбор MAX(cj.first_open) явно не сработает для меня. У меня нет уникального идентификатора, потому что доступность представляет собой комбинацию из двух таблиц, где идентификаторы могут столкнуться. И MySQL не имеет функции FIRST(). Но в основном я забочусь о самых больших доступных последовательных днях, потому что нам просто все равно, когда происходят последовательные дни, просто они происходят между датами начала и окончания пользователя.

Так есть лучший способ структурировать этот запрос? Я попытался изучить методы, чтобы получить только первую строку в калькуляторе на самом деле DATEDIFF(), а все остальные - 0, но проблема, с которой я столкнулся, IF(ct1.start_date = MIN(ct1.start_date), DATEDIFF(...), 0), заключалась в том, что первые две строки будут иметь значение не 0, и мне нужно только первое , И я думаю, что это имеет какое-то отношение к тому, как я присоединяюсь к таблице.

Любая помощь приветствуется. Благодарю.

Редактировать

Для любопытных сторон вот вопрос все в одном куске. Сейчас это работает (насколько я могу судить), как и предполагалось. Теперь мне просто интересно, есть ли лучший способ или есть какие-то советы.

SELECT p.* as id, IFNULL(cd.total_blocked, 0) as total_blocked, IFNULL(cd.consec_days_avail, 0) as consec_days_avail 
FROM properties AS p 
LEFT JOIN (
SELECT cj.property_id, IFNULL(SUM(cj.blocked_days), 0) as total_blocked, IFNULL(GREATEST(MAX(cj.open_days), MAX(cj.first_open)), 0) as consec_days_avail 
FROM (
SELECT IFNULL(DATEDIFF(IFNULL(ct2.start_date2, {user_end_date}), ct1.end_date) - 1, 0) as open_days,IF(MIN(ct1.start_date) = ct1.start_date, DATEDIFF(ct1.start_date, {user_start_date}), 0) as first_open,IFNULL(DATEDIFF(LEAST(ct1.end_date, {user_end_date}), GREATEST(ct1.start_date, {user_start_date})) + 1, 0) as blocked_days,ct1.property_id as property_id 
FROM ((SELECT c.id,c.property_id,c.start_date,c.end_date FROM property_calendar as c WHERE c.start_date <= {user_end_date} AND c.end_date >= {user_start_date}) UNION (SELECT l.id,l.property_id,l.start_date,l.end_date FROM lease as l WHERE l.start_date <= {user_end_date} AND l.end_date >= {user_start_date} AND l.status < 6) ORDER BY start_date ASC) as ct1 
LEFT JOIN ((SELECT c.id as id2,c.property_id as property_id2,c.start_date as start_date2,c.end_date as end_date2 FROM property_calendar as c WHERE c.start_date <= {user_end_date} AND c.end_date >= {user_start_date}) UNION (SELECT l.id,l.property_id,l.start_date,l.end_date FROM lease as l WHERE l.start_date <= {user_end_date} AND l.end_date >= {user_start_date} AND l.status < 6) ORDER BY start_date2 ASC) as ct2 ON ct2.property_id2 = ct1.property_id AND ct2.start_date2 > ct1.end_date 
GROUP BY ct1.property_id,ct1.start_date) as cj 
GROUP BY cj.property_id) as cd on cd.property_id = p.id 
WHERE p.state = 1 
GROUP BY p.id 
HAVING total_blocked < DATEDIFF({user_end_date},{user_start_date}) + 1 AND (consec_days_avail >= {user_days_avail} OR total_blocked = 0) 
ORDER BY p.id asc 
+0

Я бы предпочел только некоторые данные и желаемый результат - по крайней мере, это показывает, что вы пытаетесь – Strawberry

+0

@Strawberry Я получаю ya. Извините, что работала над этим в течение нескольких дней, и я подумал, что это будет легче читать разломанным. Я немного придумаю скрипку и обновлю. – Squeegy

+0

Просто лакомый кусочек. 'MIN (datestamp)' и 'MAX (datestamp)' отлично работают в качестве агрегатных функций, возвращая первую и последнюю дату. Кроме того, вы можете неправильно использовать нестандартное расширение MySQL для 'GROUP BY', которое может привести вас в бешенство. https://dev.mysql.com/doc/refman/5.6/en/group-by-handling.html –

ответ

0

Hello!
решение для этой проблемы является SQL Функция называется MIN и работает следующим образом:

SELECT MIN(primary_key_column),the_other_columns FROM table_name; 

Как вы можете видеть, в начале запроса (После того, как слово SELECT) вы просто Вызовите функцию MIN и укажите столбец, который также является основным ключом таблицы.
Поскольку эта функция находит минимальное количество регистров таблицы. Я имею в виду, что если выбранный столбец является INTEGER, он будет искать строку с наименьшим номером в этом столбце

Если вы используете PHP есть функция, чтобы сделать это называется mysql_fetch_array, для выполнения этой функции вы должны сделать сначала QUY с другим PHP функция называется mysql_query и использовать его как этот

$myQuery = mysql_query("SELECT * FROM tablename",$conectionVariable)or die(mysql_error); 

Тогда мы называем функцию mysql_fetch_ массив и хранить его в переменной, как это:

$myQueryArray = mysql_getch_array($myQuery)or die(mysql_error()); 

Теперь для использования его нужно вызвать его как обычный массив:

$myQueryArray['COLUMN_NAME'] И вернуть вам значение этого столбца является первой строки

Ну, это все.

Спасибо!

Смежные вопросы