select t.tt, r.*
from reservation r
left join lateral generate_series(lower(r.during), upper(r.during), interval '15 min')t(tt) on true
with
all_ranges as (
SELECT tsrange(generate_series,
generate_series + interval '30' minute,
'()') as range
FROM generate_series(current_date::timestamp + interval '9' hour,
current_date::timestamp + interval '18' hour,
'30 minutes'))
select rooms.id as room_id,
concat(to_char(lower(ar.range), 'HH24:MI'),
' - ',
to_char(upper(ar.range), 'HH24:MI')) as timerange
from all_ranges as ar
cross join rooms
where not exists (select 1
from reservations as rt
where rooms.id=rt.room_id and
ar.range && rt.occurrence)
order by 1;
private ResultSet fetchRows() {
...
}
private JSONObject toJson(ResultSet rows) {
...
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
try (PrintWriter out = response.getWriter()) {
out.append(toJson(fetchRows()));
}
}
<div id="output"></div>
<button id="button">Нажми меня</button>
var output = document.getElementById('output');
var button = document.getElementById('button');
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState != 4) return;
if (xhr.status == 200) {
data = JSON.parse(xhr.responseText);
response = ['<table>', '<tr><th>Имя</th><th>Фамилия</th></tr>'];
for (var x = 0; x < data.persons.length; x++) {
response.push('<tr>');
response.push('<td>' + data.persons[x].firstName + '</td>');
response.push('<td>' + data.persons[x].lastName + '</td>');
response.push('</tr>');
}
response.push('</table>');
output.innerHTML = response.join('');
}
else {
alert('Ошибка! ' + xhr.statusText);
}
button.innerHTML = 'Нажми меня';
button.disabled = false;
};
button.addEventListener('click', function(event) {
this.innerHTML = 'Загружаю...';
this.disabled = true;
xhr.open('POST', '/some/servlet/url', true);
xhr.send();
});
SELECT CONCAT(`h`.`hour`, ':', `m`.`minute`, ':00')
FROM (
SELECT '09' AS `hour`
UNION SELECT '10'
UNION SELECT '11'
UNION SELECT '12'
UNION SELECT '13'
UNION SELECT '14'
UNION SELECT '15'
UNION SELECT '16'
UNION SELECT '17'
) AS `h`
JOIN (
SELECT '00' AS `minute`
UNION SELECT '15'
UNION SELECT '30'
UNION SELECT '45'
) AS `m`
SELECT t.event_date, -- атрибут таблицы типа datetime, для которого определяем интервал, выведен для того, чтобы наблюдать за процессом отладки
case -- SQL-конструкция вида "case when ... then ... else ... end", с помощью которой можно выводить не только конкретное значение атрибута, но и задавать условие, при котором конечное значение результата будет вычисляться по-разному в пределах одной выбранной записи.
when TIME_TO_SEC(t.event_date) >= inter.begin AND TIME_TO_SEC(t.event_date) <= inter.end -- если t.event_date, выраженное в суточных секундах, находится в отрезке [inter.begin, inter.end], также выраженных в суточных секундах,...
then floor((TIME_TO_SEC(t.event_date) - inter.begin) / inter.width) -- ... то вычисляем количество полных интервалов
else null -- иначе, если время не попадает в период отслеживания, то выводим "пусто", чтобы явно указать, что значение не находится в интересуемом периоде
end as full_interval_number -- кол-во прошедших полных интервалов, начинается с 0
FROM table t, -- ваша таблица
(select TIME_TO_SEC('09:00:00') as begin, -- начало дневного периода
TIME_TO_SEC('18:00:00') as end, -- конец дневного периода
TIME_TO_SEC('00:15:00') as width -- ширина интервала
) inter -- параметрический подзапрос, все настраиваемые константы в одном месте - удобно при отладке
DECLARE loop_date DATETIME; // изменяемая дата в цикле
DECLARE end_date DATETIME; // конечная дата
SET loop_date = DATE_ADD(end_date, INTERVAL -90 DAY);
WHILE DATE(loop_date) <= DATE(end_date) DO
INSERT INTO `times` (`id`, `date`, `time`) VALUES (NULL, loop_date, '08:00');
...
INSERT INTO `times` (`id`, `date`, `time`) VALUES (NULL, loop_date, '17:00');
SET loop_date = DATE_ADD(loop_date, INTERVAL 1 DAY);
END WHILE