Форум программистов, компьютерный форум, киберфорум
PostgreSQL
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
0 / 0 / 1
Регистрация: 27.06.2013
Сообщений: 88

Подсчитать количество минут для каждого часа

30.07.2025, 13:38. Показов 1251. Ответов 8
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте дорогие ребята. Прошу вас подсказать мне в одном запросе.
у меня есть некоторая таблица с данными по времени. Я имею колонки start и end. И мне нужно для каждого часа рассчитать потраченное количество минут и вернуть таблицу где будут выравненные часы и их количество минут.
Пример моей таблицы:


Обратите внимание, что разница во времени для некоторых записей составляет более часа или окончание приходится на другой час, и эти минуты нужно записать в следующий час при расчёте. Я не знаю, как это сделать в SQL... Мне нужно получить такую таблицу:



Прошу, пожалуйста, подсказать как мне это сделать ?
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
30.07.2025, 13:38
Ответы с готовыми решениями:

Как схлопнуть 10-сек интервалы времени (они по порядку, но с пропусками) в группы в рамках 1 минуты, каждого часа, дня?
Здравствуйте, возможно кто-то сталкивался с таким квестом. Имеются исторические данные...

Получить ФИО всех жоккеев, а также сумму оплаты труда каждого из них (сумма оплаты = ранг *1,3 * стоимость часа)
SELECT Name, Salary /*Какого оператора здесь не хватает, чтобы посчитать зарплату?*/ FROM...

Подсчитать максимальное количество записей в интервале 2-х минут
Есть таблица в ней записи как можно подсчитать максимальное количество записей в интервале 2 минут....

8
 Аватар для Дядя Виля
41 / 33 / 9
Регистрация: 12.06.2024
Сообщений: 165
30.07.2025, 15:13
SQL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
CREATE TABLE my_table(id serial,f_date DATE,f_start TIME,f_end TIME);
 
WITH time_ranges AS (
  SELECT
    id,
    f_date,
    f_start,
    f_end,
    date_trunc('hour', f_date + f_start)::TIME AS hour_start,
    (date_trunc('hour', f_date + f_end) +
     CASE WHEN (f_end > date_trunc('hour', f_date + f_end)::TIME)
          THEN INTERVAL '1 hour' ELSE INTERVAL '0' END)::TIME AS hour_end
  FROM my_table
),
expanded_hours AS (
  SELECT
    id,
    f_date,
    generate_series(
      (f_date + hour_start)::TIMESTAMP,
      (f_date + hour_end - INTERVAL '1 hour')::TIMESTAMP,
      INTERVAL '1 hour'
    )::TIME AS hour_slot,
    f_start,
    f_end,
    hour_start AS first_hour,
    hour_end - INTERVAL '1 hour' AS last_hour
  FROM time_ranges
)
SELECT
  id,
  f_date,
  hour_slot AS aligned_hour,
  hour_slot AS aligned_hour_start,
  (hour_slot + INTERVAL '1 hour')::TIME AS aligned_hour_end,
  CASE
    WHEN date_trunc('hour', f_date + f_start)::TIME = date_trunc('hour', f_date + f_end)::TIME THEN
      EXTRACT(MINUTE FROM f_end - f_start)::INTEGER
    WHEN hour_slot = date_trunc('hour', f_date + f_start)::TIME THEN
      60 - EXTRACT(MINUTE FROM f_start)::INTEGER
    WHEN hour_slot = (date_trunc('hour', f_date + f_end)::TIME) THEN
      EXTRACT(MINUTE FROM f_end)::INTEGER
    ELSE 60
  END AS minutes_used,
  f_start,
  f_end
FROM expanded_hours
ORDER BY id, f_date, hour_slot;
0
 Аватар для Аватар
5393 / 1465 / 513
Регистрация: 31.05.2012
Сообщений: 5,153
30.07.2025, 16:44
SQL
1
2
3
4
5
6
CREATE TABLE mytable (id INT, "date" DATE, START TIME WITHOUT TIME zone, "end" TIME WITHOUT TIME zone);
 
INSERT INTO mytable VALUES (325,'2025-05-21','15:43:00','16:04:00'),(326,'2025-05-21','09:15:00','09:28:00'),
  (327,'2025-05-21','08:01:00','08:24:00'),(328,'2025-05-21','08:32:00','08:47:00'),(329,'2025-05-21','10:05:00','10:55:00'),
  (330,'2025-05-21','08:17:00','09:34:00'),(331,'2025-05-28','09:38:00','11:01:00'),(332,'2025-05-28','12:10:00','14:32:00'),
  (333,'2025-05-19','12:18:00','13:40:00'),(334,'2025-05-19','22:18:00','01:40:00');
iddatestartend
3252025-05-2115:43:0016:04:00
3262025-05-2109:15:0009:28:00
3272025-05-2108:01:0008:24:00
3282025-05-2108:32:0008:47:00
3292025-05-2110:05:0010:55:00
3302025-05-2108:17:0009:34:00
3312025-05-2809:38:0011:01:00
3322025-05-2812:10:0014:32:00
3332025-05-1912:18:0013:40:00
3342025-05-1922:18:0001:40:00
SQL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
WITH RECURSIVE cte AS (
    SELECT id,DATE,START,"end",
        CASE WHEN EXTRACT(HOUR FROM "end")<EXTRACT(HOUR FROM START) THEN 24 ELSE 0 END hadd,
        EXTRACT(HOUR FROM START) hstart,DATE rdate,
        CASE WHEN EXTRACT(HOUR FROM START)=EXTRACT(HOUR FROM "end")
             THEN EXTRACT(MINUTE FROM "end")-EXTRACT(MINUTE FROM START) 
             ELSE 60-EXTRACT(MINUTE FROM START) END mstart
      FROM mytable
    UNION 
    SELECT m.id,m.date,m.start,m."end",cte.hadd,cte.hstart+1 hstart,
        CASE WHEN cte.hstart=23 THEN cte.rdate+INTEGER '1' ELSE cte.rdate END rdate,
        CASE WHEN cte.hstart+1<EXTRACT(HOUR FROM m."end")+cte.hadd THEN 60 ELSE EXTRACT(MINUTE FROM m."end") END AS mstart
      FROM mytable m JOIN cte ON 
           m.id=cte.id AND 
           ((cte.hadd=0 AND cte.hstart+1<=EXTRACT(HOUR FROM m."end") OR
            (cte.hadd=24 AND cte.hstart+1<=24+EXTRACT(HOUR FROM m."end"))))
  )
SELECT id,rdate DATE,make_time(hstart::INTEGER-CASE WHEN hstart>23 THEN 24 ELSE 0 END,0,0) START,
    make_time(hstart::INTEGER-CASE WHEN hstart>23 THEN 24 ELSE 0 END,0,0)+INTERVAL '1 hour' AS "end", 
    mstart minytes 
  FROM cte ORDER BY id,rdate,hstart;
iddatestartendminytes
iddatestartendminytes
3252025-05-2115:00:0016:00:0017
3252025-05-2116:00:0017:00:004
3262025-05-2109:00:0010:00:0013
3272025-05-2108:00:0009:00:0023
3282025-05-2108:00:0009:00:0015
3292025-05-2110:00:0011:00:0050
3302025-05-2108:00:0009:00:0043
3302025-05-2109:00:0010:00:0034
3312025-05-2809:00:0010:00:0022
3312025-05-2810:00:0011:00:0060
3312025-05-2811:00:0012:00:001
3322025-05-2812:00:0013:00:0050
3322025-05-2813:00:0014:00:0060
3322025-05-2814:00:0015:00:0032
3332025-05-1912:00:0013:00:0042
3332025-05-1913:00:0014:00:0040
3342025-05-1922:00:0023:00:0042
3342025-05-1923:00:0000:00:0060
3342025-05-2000:00:0001:00:0060
3342025-05-2001:00:0002:00:0040
0
0 / 0 / 1
Регистрация: 27.06.2013
Сообщений: 88
30.07.2025, 17:21  [ТС]
спасибо огромное вам ребята! Буду пробовать)) непростые запросы, постарюсь в них разобраться) я вам очень благодарна за вашу отзывчивость!
0
 Аватар для Аватар
5393 / 1465 / 513
Регистрация: 31.05.2012
Сообщений: 5,153
31.07.2025, 10:04
здесь со скобками напутал. но напутал без искажения результата
SQL
1
2
           ((cte.hadd=0 AND cte.hstart+1<=EXTRACT(HOUR FROM m."end") OR
            (cte.hadd=24 AND cte.hstart+1<=24+EXTRACT(HOUR FROM m."end"))))
нужно так
SQL
1
2
           ((cte.hadd=0 AND cte.hstart+1<=EXTRACT(HOUR FROM m."end")) OR
            (cte.hadd=24 AND cte.hstart+1<=24+EXTRACT(HOUR FROM m."end")))
0
1192 / 761 / 128
Регистрация: 10.03.2012
Сообщений: 4,912
31.07.2025, 10:54
SQL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
WITH RECURSIVE hours AS (
    SELECT 
        id,
        DATE,
        START AS hour_start,
        LEAST(DATE_TRUNC('hour', START) + INTERVAL '1 hour', END) AS hour_end,
        EXTRACT(EPOCH FROM LEAST(DATE_TRUNC('hour', START) + INTERVAL '1 hour', END) - START) / 60 AS minutes
    FROM 
        time_records
    WHERE 
        START < END 
    UNION ALL
    SELECT 
        id,
        DATE,
        hour_start + INTERVAL '1 hour',
        hour_end,
        EXTRACT(EPOCH FROM LEAST(hour_end, hour_start + INTERVAL '1 hour') - hour_start) / 60 AS minutes
    FROM 
        hours
    WHERE 
        hour_start < hour_end
)
SELECT 
    id,
    DATE,
    to_char(hour_start, 'YYYY-MM-DD HH24:00') AS START,
    to_char(hour_start + INTERVAL '1 hour', 'YYYY-MM-DD HH24:00') AS END,
    SUM(minutes) AS minutes
FROM 
    hours
GROUP BY 
    id, DATE, hour_start
ORDER BY 
    id, hour_start;
0
912 / 286 / 57
Регистрация: 01.06.2023
Сообщений: 810
01.08.2025, 10:17
SQL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
SELECT 
  id, 
  mytable.date,
  dHour::TIME  AS START,
  (dhour + INTERVAL '1' HOUR)::TIME AS END,
  --Продолжительность часового периода
  (EXTRACT(epoch FROM  dEndPeriod - dStartPeriod) / 60)::INTEGER minutes
FROM 
  mytable,
  --Разбиваем период по часам
  generate_series(date_trunc('hour', DATE + mytable.start),DATE +  mytable.end,INTERVAL '1' HOUR) dHour,
  --Начало часового периода
  greatest(dHour, DATE + mytable.start) dStartPeriod,
  --Окончание часового периода
  least(dHour + INTERVAL '1' HOUR, DATE + mytable.end) dEndPeriod
0
0 / 0 / 1
Регистрация: 27.06.2013
Сообщений: 88
28.08.2025, 19:27  [ТС]
Здравсвуйте дорогие форумчане) благодарю вас за подсказки и предложенные решения. В итоге использовала код пользователя Аватр, так как он отработал действительно как требовалось. Но мне усложнили задачу и вот пока не смогла написать рабочий SQL скрипт который бы решал поставленную задачу. Прошу вас помочь мне ещё раз.
Опишу новые условия задачи. Теперь у меня есть такая таблица:

и в ней следующие данные:


Смысл задачи следующий:
необходимо получить таблицу-сводку из исходной таблицы, где данные все группировать в гранулы по 5 минут. Приведу пример, что имеем и что должны на выходе получить:
JSON
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
| Поле          | Значение                                   
|--------------|-------------------------------------------------------|
| Id              | 1
| shop_id      | fsaf6as7f6asfas
| date          | 2025-08-13
| start_time   | 18:40
| end_time    | 18:47
| info              |  {
                      "name": "Гель для душа",
                      "type": "Косметика",
                      "country": "Россия"
                    }
|---------------|-------------------------------------------------------|
| Id               | 2
| shop_id       | fsaf6as7f6asfas
| date          | 2025-08-13
| start_time   | 18:40
| end_time    | 18:43
| info              |  {
                      "name": "Крем для рук",
                      "type": "Косметика",
                      "country": "Россия"
                    }   
Результат: 
| Id              | 1
| shop_id      | fsaf6as7f6asfas
| date          | 2025-08-13
| start_time   | 18:40
| end_time    | 18:45
| info             |  [{
                      "name": "Гель для душа",
                      "type": "Косметика",
                      "country": "Россия",
                      "seconds": 300
                    },
                    {
                      "name": "Крем для рук",
                      "type": "Косметика",
                      "country": "Россия",
                      "seconds": 180
                    }
                    ]
|---------------|-------------------------------------------------------|
| Id               | 2
| shop_id      | fsaf6as7f6asfas
| date          | 2025-08-13
| start_time   | 18:45
| end_time    | 18:50
| info              |  [{
                      "name": "Гель для душа",
                      "type": "Косметика",
                      "country": "Россия",
                      "seconds": 120
                    }]
Т.е. нужно снова поработать с временем и помимо этого обновлять поле info. Если человек просматривал товар более 5 минут, то оставшееся время перенести в следующую гранулу, дополнив поле info. Для каждого товара указать время его просмотра в секундах.
Я пыталась применить запрос который приводили здесь в пример, но пока не смогла даже изменить его так, чтобы он по 5 минут группировал не по часу... И пока не понимаю как менять поле info? Оно типа jsonb.
Прошу вас помочь мне с этой задачей.
Есть у меня ещё идея, сделать это не в SQL, а в коде. Как вы думаете такой сложный запрос где лучше делать ?
Мне был удобен SQL, тем что ты выполнил и сразу видишь результат в виде таблицы. А в коде ещё нужно его выводить и отлаживаться, просматривая результат не так быстро как в том же pgAdmin. Выполнил скрипт и вот тебе уже удобо читаемый резьтат. Плюс я бы хранила уже эти предрасчитангные данные в другой таблицы, чтобы сервер быстрее возвращал данные по запросу.
Прошу кто может помочь мне написать такой SQL скрипт.
0
0 / 0 / 1
Регистрация: 27.06.2013
Сообщений: 88
31.08.2025, 18:45  [ТС]
Добрый вечер. Очень жду от вас ответа и помощи. Вот что у сменя получилось самой сделать:
SQL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
-- сначала для каждого пользователя на каждый день получу отрезок его рабочего времении
WITH time_ranges AS (SELECT MIN(start_time) AS start_time, MAX(end_time) AS end_time, DATE, employee_id
FROM pps.my_temp
GROUP BY DATE, employee_id
ORDER BY DATE ASC),
 
--далее разобъём этот отрезок на гранулы в 5 минут
expanded_hours AS (
SELECT
    employee_id,
    DATE,
    generate_series(
    CASE WHEN EXTRACT(MINUTE FROM start_time)::INTEGER % 5 = 0 THEN (DATE + start_time) 
    ELSE (DATE + make_time(EXTRACT(HOUR FROM start_time)::INTEGER, 
                   (EXTRACT(MINUTE FROM start_time)::INTEGER - MOD(EXTRACT(MINUTE FROM start_time)::INTEGER, 5)),
                   0
                   )) 
    END,
    CASE WHEN EXTRACT(MINUTE FROM end_time)::INTEGER % 5 = 0 THEN (DATE + end_time) 
    ELSE (DATE + make_time(EXTRACT(HOUR FROM end_time)::INTEGER, 
                   ( CASE WHEN (EXTRACT(MINUTE FROM end_time)::INTEGER + MOD(EXTRACT(MINUTE FROM end_time)::INTEGER, 5)) > 59 THEN 59
                   ELSE (EXTRACT(MINUTE FROM end_time)::INTEGER + MOD(EXTRACT(MINUTE FROM end_time)::INTEGER, 5)) END ),
                   0
                   )) 
    END,
    INTERVAL '5 minute'
    )::TIME AS granula_start
  FROM time_ranges),
 
granules AS (
SELECT
    employee_id,
    DATE,
    granula_start,
    granula_start +  INTERVAL '5 minute' AS granula_end
  FROM expanded_hours)
--select * from granules order by date asc
--- теперь полученные гранулы заполним данными о приложении из таблицы pps.my_temp
SELECT 
employee_id,
DATE,
granula_start,
granula_end,
 
(SELECT 
    array_agg(json_build_object('seconds', SUM( CASE 
                                      WHEN end_time > granula_end 
                                      THEN ((EXTRACT(MINUTE FROM granula_end) - EXTRACT(MINUTE FROM start_time))*60) 
                                      ELSE (CASE  WHEN EXTRACT(MINUTE FROM start_time) = EXTRACT(MINUTE FROM end_time) 
                                                  THEN 
                                                   EXTRACT(SECOND FROM end_time) - EXTRACT(SECOND FROM start_time)
                                                  ELSE
                                                   (EXTRACT(MINUTE FROM end_time) - EXTRACT(MINUTE FROM start_time)) * 60 
                                           END )
                                      END ),
                      'domain_site', m.app_info::jsonb->'domain_site',
                      'app_name', m.app_info::jsonb->'app_name',
                      'app_type', m.app_info::jsonb->'app_type' )) AS app_info
 FROM pps.my_temp m
 WHERE start_time >= granula_start AND start_time <= granula_end
 GROUP BY m.app_info::jsonb->'domain_site', m.app_info::jsonb->'app_name', m.app_info::jsonb->'app_type'
 )
 
FROM granules
Но в последнем запросе я получаю ошибку и никак не могу его доделать...
Я уже разбила для каждого пользователя на гранулы по 5 минут каждый день, это у меня в отдельной временной таблице. Далее я хочу выбрать из основной таблицы, используемые им программы в течении гранулы и сложить их в один json массив.
При этом мне нужно подсчитать кол-во времени в секундах в которое он использовал эту программу внутри гранулы. Необходимо ещё сгруппировать по имени программы и полю domain_site, резьтат группировки это json массив. Вот пример json который должен получиться:
JSON
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
        [
      {
        "app_name": "googlechrome",
        "path": "C:\\ProgramFiles\\google\\googlechrome.exe",
        "domain_site": "stackoverfloww.com",
        "count_seconds": 540,
        "titles": [
          {
"count_seconds": 320,
            "url": "https://stackoverflow.com/questions/40978290/construct-json-object-from-query-with-group-by-sum",
            "title": "Construct json object from query with group by / sum"
          },
          {
"count_seconds": 220,
            "url": "https://stackoverflow.com/questions/43117033/aggregate-function-calls-cannot-be-nested-postgresql",
            "title": "aggregate function calls cannot be nested postgresql"
          }
        ]
      }
    ]
Подскажите мне, пожалуйста, как мне правильно дописать свой последний запрос в моём коде ?
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
31.08.2025, 18:45
Помогаю со студенческими работами здесь

Написать запрос на подсчитывание количества часов
есть таблица &quot;ведомости&quot; где указаны столбцы &quot;номер_студбилета&quot;, &quot;код_предмета&quot; вторая таблица...

Как подсчитать количество определенных символов в каждом поле таблицы???
помогите пожалуйста, дали задание надо срочно сделать, задание такое: 3. Есть таблица вида ...

Подсчитать число\количество олимпиад, которые проводились и будут проводится в каждом месяц
запросы: 1)определить школьников, которые заняли призовые места на любых олимпиадах - это сделал....

Подсчитать количество строк в каждой группировке
Добрый вечер. Есть такая таблица: myTable (catId, Name) 1 | qwerty 1 | blablabla 3 | wwwww 4...

В каждом поле должно подсчитываться количество тех или иных записей за определенный период
Нужно сделать итоговый отчет, состоящий из множества полей. В каждом поле должно подсчитываться...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
9
Ответ Создать тему
Новые блоги и статьи
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу, и светлой Луне. В мире покоя нет и люди не могут жить в тишине. А жить им немного лет.
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила» «Время-Деньги» «Деньги -Пуля»
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL3_image
8Observer8 10.02.2026
Содержание блога Библиотека SDL3_image содержит инструменты для расширенной работы с изображениями. Пошагово создадим проект для загрузки изображения формата PNG с альфа-каналом (с прозрачным. . .
Установка Qt-версии Lazarus IDE в Debian Trixie Xfce
volvo 10.02.2026
В общем, достали меня глюки IDE Лазаруса, собранной с использованием набора виджетов Gtk2 (конкретно: если набирать текст в редакторе и вызвать подсказку через Ctrl+Space, то после закрытия окошка. . .
SDL3 для Web (WebAssembly): Работа со звуком через SDL3_mixer
8Observer8 08.02.2026
Содержание блога Пошагово создадим проект для загрузки звукового файла и воспроизведения звука с помощью библиотеки SDL3_mixer. Звук будет воспроизводиться по клику мышки по холсту на Desktop и по. . .
SDL3 для Web (WebAssembly): Основы отладки веб-приложений на SDL3 по USB и Wi-Fi, запущенных в браузере мобильных устройств
8Observer8 07.02.2026
Содержание блога Браузер Chrome имеет средства для отладки мобильных веб-приложений по USB. В этой пошаговой инструкции ограничимся работой с консолью. Вывод в консоль - это часть процесса. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru