Здравствуйте. Есть две таблицы. Первая main Вторая allnomer datestart и dateend - диапазон дат. Этот диапазон включает в себя все промежуточные даты. Мне нужно получить только те даты, которые повторились N раз. N - кол-во номеров в таблице allnomer. Lux встречается 3 раза, следовательно n = 3. Подробнее: id 44 включает в себя такие даты: 2016-12-21, 2016-12-22, 2016-12-23 id 45 включает в себя такие даты: 2016-12-21, 2016-12-22, 2016-12-23 id 44 включает в себя такие даты: 2016-12-22, 2016-12-23, 2016-12-24 3 Раза повторились такие даты: 2016-12-22, 2016-12-23 Получить N я могу, и делаю я это так: PHP: $nnomer = "lux"; const SQL_COUNT_NOMER = ' SELECT COUNT(1) FROM allnomer WHERE type = :type '; $pdo = new PDO($dsn, $user, $password); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $stmt = $pdo->prepare(SQL_COUNT_NOMER); $res = $stmt->execute([':type' => $nnomer]); $row = json_encode(array_pop($stmt->fetch()), JSON_NUMERIC_CHECK); // echo вернёт N А как получить повторяющиеся даты - я не знаю. Прошу вашей помощи.
@drkrol тут обычным запросом не обойдёшься. Придётся писать процедуру, например, такого плана. Я бы, скорее всего, перенес бы решение на плечи php, но решение за вами. P.S. array_pop тут лишнее. fetchAll с аргументом FETCH_COLUMN
Попробую привести другой пример. Вот такая база. http://sqlfiddle.com/#!9/83e77 . Этот модуль, который я с вашей помощью пытаюсь сделать, нужен для бронирования номеров в гостинице. Чтобы избежать повторяющейся брони на одни и те же даты, нужно знать, на какие даты уже номера забронированы. То есть, чтобы 2 разных человека не забронировали на одни и те же даты один и тот же номер. Когда я узнаю уже занятые даты, я могу запретить бронь на эти даты. Для визуализации нарисовал схему. Есть 3 номера lux: 301, 302 и 303. На изображении я отобразил овалами забронированные даты. В бд есть только первая и последняя дата, а, по факту, человек будет жить все дни. То есть, если дата заезда 11 числа, а дата выезда 14, то жить он будет 11,12,13 и 14 числа. На изображении 3 раза забронированы только такие даты: 12, 14 и 16. Поэтому я должен от php получить ответ: ["2016-12-12", "2016-12-14", "2016-12-16",]
@drkrol, PHP: <?php $query = "SELECT `numbernomer` FROM `main` WHERE `datestart` BETWEEN CAST('2016-12-17' AS DATE) AND CAST('2016-12-20' AS DATE) OR `dateend` BETWEEN CAST('2016-12-17' AS DATE) AND CAST('2016-12-20' AS DATE) GROUP BY `numbernomer`"; Таким образом, вы вычислите номера, которые уже забронированы и их даты попадают в диапазон с 2016-12-17 по 2016-12-20
@Deonis зачем мне номера? Мне даты нужны))) Я потом подставлю эти даты под array https://jsfiddle.net/jw01gosb/60/ и затемню занятые. В фидле 12, 14 и 16 даты - неактивны.
Это для вас очевидно. Вытаскивайте не номера, а даты, генерируете массив для каждого диапазона и можно идти на пиво: PHP: <?php function getDatesFromRange($start, $end, $format = 'Y-m-d') { $array = []; $interval = new DateInterval('P1D'); $realEnd = new DateTime($end); $realEnd->add($interval); $period = new DatePeriod(new DateTime($start), $interval, $realEnd); foreach($period as $date) { $array[] = $date->format($format); } return $array; } print_r(getDatesFromRange('2016-12-12', '2016-12-18')); PHP: Array ( [0] => 2016-12-12 [1] => 2016-12-13 [2] => 2016-12-14 [3] => 2016-12-15 [4] => 2016-12-16 [5] => 2016-12-17 [6] => 2016-12-18 )
А я номера хотел? У меня просто голова кругом идёт. Я перечитал свой вопрос. Я не просил помочь узнать номера, только даты хотел. А зачем в скрипте даты указывать? Нужно достать только те даты, которые повторились 3 раза , где namenomer равен lux. Еще раз. Есть вот такая бд http://sqlfiddle.com/#!9/83e77 . Какой нужно сделать запрос в бд или написать скрипт, чтобы ответ был вот такой: ["2016-12-12", "2016-12-14", "2016-12-16",] ?
Похоже, что вы пытаетесь этим недугом заразить и других Пока могу предложить такой вариант - выбираете из БД даты. Например те, которые попадают в диапазон текущего месяца и `namenomer` = 'lux'. Дальше: PHP: <?php // Результат выборки из БД $query_result = [ ['datestart' => '2016-12-12', 'dateend' => '2016-12-18'], ['datestart' => '2016-12-11', 'dateend' => '2016-12-14'], ['datestart' => '2016-12-16', 'dateend' => '2016-12-19'], ['datestart' => '2016-12-12', 'dateend' => '2016-12-12'], ['datestart' => '2016-12-14', 'dateend' => '2016-12-16'] ]; $tmp = []; foreach($query_result as $row) { // Фунцкия getDatesFromRange в комментарии выше $tmp = array_merge($tmp, getDatesFromRange($row['datestart'], $row['dateend'])); } // считаем количество одинаковых дат $same_number_dates = array_count_values($tmp); // Фильтруем те, у который кол-во == 3 $result = array_filter($same_number_dates, function($v){ return $v == 3; }); print_r($result); PHP: Array ( [2016-12-12] => 3 [2016-12-14] => 3 [2016-12-16] => 3 )
@Deonis сейчас у меня есть вот такой код: PHP: $diaposons = array_map( function($e) { return array('datestart' => strtotime($e->datestart), 'dateend' => strtotime($e->dateend)); }, json_decode('[{"datestart":"2016-12-12","dateend":"2016-12-18"},{"datestart":"2016-12-11","dateend":"2016-12-14"},{"datestart":"2016-12-16","dateend":"2016-12-19"},{"datestart":"2016-12-12","dateend":"2016-12-12"},{"datestart":"2016-12-14","dateend":"2016-12-16"}]') ); usort($diaposons, function($a, $b) { return $a['datestart'] - $b['datestart']; }); $result = []; $left = $diaposons[0]['datestart']; $right = $diaposons[0]['dateend']; $num = count($diaposons); $day = 24 * 60 * 60; for ($i = 3; $i < $num; ++$i) { if ($diaposons[$i]['datestart'] > $right) { $right = $diaposons[$i]['dateend']; continue; } $end = min($right, $diaposons[$i]['dateend']); $result[] = array( 'start' => max($left + $day, $diaposons[$i]['datestart']), 'end' => $end ); $left = $end; $right = max($right, $diaposons[$i]['dateend']); } foreach ($result as $r) { for ($i = $r['start']; $i <= $r['end']; $i += $day) { echo date('Y-m-d', $i), PHP_EOL; } } Но он работает с ошибкой. Он возвращает мне 2016-12-14 2016-12-16 , а должен возвращать 2016-12-12 2016-12-14 2016-12-16. Третья строчка, как раз и есть структура моей бд. @Deonis, если я правильно понял, вашем случае я должен на каждый месяц отправлять запрос в бд. Не целесообразно это. Где ошибка в моём скрипте, почему он теряет первое совпадение?
Неправильно. Условие ставите то, какое вам нужно. Можете выбирать хоть за неделю, хоть за десять лет назад + десять лет вперёд.
@Deonis, подскажите пожалуйста, как привести ответ вот в такой вид: ["2016-12-12", "2016-12-14", "2016-12-16",] ?
Тебе надо искать пересечение диапазонов дат, а не считать какие-то непонятные повторы. Один диапазон это желаемые даты бронирования, то что ввёл пользователь. Другой диапазон это то что у тебя в таблице резервирований. Диапазоны a..b и x..y пересекаются если Код (Text): (a <= y) and (x <= b) Например, узнать нет ли записей о занятости номера 301 в период с 14го по 16е декабря: Код (Text): SELECT 1 FROM main WHERE (numbernomer = '301') AND ('2016-12-14' <= dateend) AND (datestart <= '2016-12-16') если вернулась запись с 1, значит занято. Если пустой набор, то свободно. --- Добавлено --- P.S. мешать в названии рус и eng это фуууууууууууууууууууууууу. numbernomer, OH MY БОХ!