Как найти диапазон дат из бд и вывести только повторяющиеся?

Статус
В этой теме нельзя размещать новые ответы.

drkrol

Постоялец
Регистрация
6 Мар 2016
Сообщения
112
Реакции
11
Здравствуйте. Есть вот такой код.
PHP:
$nnomer = $_POST['nnomer'];
const SQL_GET_MENU_ITEM = '
SELECT datestart, dateend FROM main WHERE namenomer = :namenomer
';
try{
$pdo = new PDO("mysql:host=127.0.0.1;dbname=module;charset=utf8","root","");
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$stmt = $pdo->prepare(SQL_GET_MENU_ITEM);
$res = $stmt->execute([':namenomer' => $nnomer]);
$row = json_encode($stmt->fetchAll(PDO::FETCH_OBJ));
echo "$row";
}catch(PDOException  $e ){
exit( $e->getMessage());
}

Бд выглядит у меня вот таким образом:
1df143df96a548ca8a433400417fad81.PNG

Принцип работы скрипта: С сайта уходит ajax запрос с $_POST['nnomer']; (он равен lux), php подставляет его в pdo запрос к бд и достаёт ответ. Ответ - первая и последняя дата из диапазона дат. В моём случае ответ такой:
Код:
[{"datestart":"2016-11-29","dateend":"2016-12-03"},{"datestart":"2016-12-01","dateend":"2016-12-05"}]
Всего дат 4, но по факту их будет больше.
Так вот. Подскажите, как через php найти повторяющиеся даты? В моём случае повторяющиеся даты это: 2016-12-01, 2016-12-02 и 2016-12-03. Такое вообще возможно сделать?
 
Получить повторяющиеся даты не сложно. А что потом с ними сделать? Тебе прямо в твоем скрипте это нужно сделать? Или в отдельном по всей базе?
Самый простой вариант:

PHP:
//полученный массив
$aDataFetched =  $stmt->fetchAll(PDO::FETCH_OBJ);
//только значения
$aDataFetchedValues = array_values($aDataFetched);
//частота встречаемости каждого значения
$aValuesFreq = array_count_values($aDataFetchedValues);
 
Получить повторяющиеся даты не сложно. А что потом с ними сделать? Тебе прямо в твоем скрипте это нужно сделать? Или в отдельном по всей базе?
Да. Прямо в скрипте нужно сделать пересчет и сравнить.
Да пересчитать можно, а вот сравнить - не знаю как. Да и пересчитать я могу только тогда, как есть только 1 datestart и 1 dateend. Если больше - не знаю, как.
PHP:
$from = new DateTime('2016-01-30');
$to   = new DateTime('2016-02-04');
$period = new DatePeriod($from, new DateInterval('P1D'), $to);
$last_date = $period->getEndDate();
$last_date_string = $last_date->format('Y-m-d');
$array_dates = array_map(
    function($item){return $item->format('Y-m-d');},
    iterator_to_array($period)
);
array_push($array_dates,$last_date_string);
$date_string = implode("','",$array_dates);
$dat =  "'".$date_string."'";
var_dump($dat)
В конце я должен получить данные в таком виде ['2016-12-01', '2016-12-02', '2016-12-03'] . Потом я эти данные подставлю в js скрипт и он дальше будет с ними работать... Если, честно, я даже в уме не могу представить, как это работает. Прочёл уже много чего, но так и не могу понять, как такое сделать...
 
Повторяющиеся даты можно получить в рамках одного атрибута. (datestart, dateend)
group_by + count вам в помощь.
Код:
select * from blah group_by datestart having count(*) > 1
 
  • Нравится
Реакции: Yulo
Блин, всё равно не могу до конца понять, что тебе нужно сделать.
Вот у тебя есть набор дат вычисленных твоим скриптом. Есть несколько расчетов для разных диапазонов дат
Диапазон1
Начальная1 2016-01-30 и Конечная1 2016-02-04
На выходе имеем заполненный диапазон '2016-01-30','2016-01-31','2016-02-01','2016-02-02','2016-02-03','2016-02-04'
Таак, а если будет второй такой диапазон пересекающий первый:
Диапазон2
Начальная2 2016-02-01 и Конечная 2016-02-07
На выходе имеем '2016-02-01','2016-02-02','2016-02-03','2016-02-04','2016-02-05','2016-02-06','2016-02-07'

Получается, что первый и второй диапазон пересекаются следующими датами:
'2016-02-01','2016-02-02','2016-02-03','2016-02-04'

Эти пересекающиеся даты нужно получать?
 
Получается, что первый и второй диапазон пересекаются следующими датами:
'2016-02-01','2016-02-02','2016-02-03','2016-02-04'

Эти пересекающиеся даты нужно получать?
Да. Я вот тут вот до этого дошел. Оно, вроде, работает, но, если честно, страшно проверять)))

PHP:
$diaposons = array_map(
    function($e) { return array('datestart' => strtotime($e->datestart), 'dateend' => strtotime($e->dateend)); },
    json_decode('[{"datestart":"2016-11-29","dateend":"2016-12-03"},{"datestart":"2016-12-01","dateend":"2016-12-05"}]')
);
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 = 1; $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;
    }
}
?>
 
Первое что приходит на ум - схождение массивов Для просмотра ссылки Войди или Зарегистрируйся
Твою реализацию пока не смотрел, чуть позже взгляну.
 
смысл массив перебирать если есть group by и чтоб такого не было храните даты в формате now()
 
Оно?

SELECT max(datestart), min(dateend) FROM main WHERE namenomer = :namenomer and @begdate <= dateend AND @enddate >= datestart

на выходе имеем начало и конец пересечения периодов.

@begdate и @enddate начало и конец интересуемого периода. если нужны просто по всем namenomer, то соответственно перед первым запросом просто берем первый подходящий период, например:

SELECT TOP 1 @begdate =datestart, @enddate =dateend FROM main WHERE namenomer = :namenomer


SQL синтаксис под MSSQL, для MySQL я думаю аналогию провести просто будет :)

или вот без переменных

SELECT max(main.datestart), min(main.dateend) FROM main, (SELECT TOP 1 datestart, dateend FROM main) as t WHERE namenomer = :namenomer and t.datestart <= main.dateend AND t.dateend >= main.datestart
 
Последнее редактирование:
This answer is in english:

SELECT *
FROM database
WHERE start_date > NOW() - INTERVAL 30 DAY
ORDER BY start_date DESC

Or u can use too

select *
from database
where start_date between '2012-03-11 00:00:00' and '2012-05-11 23:59:00'
order by start_date desc;
 
Статус
В этой теме нельзя размещать новые ответы.
Назад
Сверху