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

Перевод функции с MS SQL на Postgre SQL

24.03.2023, 19:57. Показов 363. Ответов 0
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Всем привет!
Помогите пожалуйста найти ошибку в функции по подсчету рабочего времени.
На данный момент, функция при подстановке любых дат всегда выдает 0.

Например:
SQL
1
SELECT rdwh.worktime('2022-01-11 08:03:24.000' :: TIMESTAMP, '2022-01-11 10:31:49.000':: TIMESTAMP)
Результат должен быть 1.5 но получается 0.

Данную функцию переводила из MS SQL на Postgre SQL.
Код функции на Postgre SQL:

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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
CREATE OR REPLACE FUNCTION rdwh.worktime(v_dt_begin TIMESTAMP,v_dt_end TIMESTAMP)
    RETURNS DOUBLE PRECISION
    LANGUAGE plpgsql
    VOLATILE
AS $$
 
DECLARE
    v_dt_begin TIMESTAMP;
    v_dt_end TIMESTAMP;
    v_result float8 := 0;
    v_begin_work float8;
    v_end_work float8;
    v_begin_rest float8;
    v_end_rest float8;
    v_rest_cur float8;
    v_begin_cur float8;
    v_end_cur float8;
    v_work_time_beg float8 := 9;
    v_work_time_end float8 := 18;
    v_work_time_end_fr float8 := 17;
    v_rest_time float8 := NULL;
    v_dt_begin_trunc TIMESTAMP := v_dt_begin :: DATE;
    v_dt_end_trunc TIMESTAMP := v_dt_end :: DATE;
    v_dt_begin_float float8 := (EXTRACT(epoch FROM v_dt_begin) / 86400);
    v_dt_end_float float8 := (EXTRACT(epoch FROM v_dt_end) / 86400);
    v_current_day TIMESTAMP := v_dt_begin_trunc;
    v_number_day INT;
 
BEGIN
 
    DROP TABLE IF EXISTS t_load_calendar;
    CREATE TEMP TABLE t_load_calendar (
        dt TIMESTAMP
       ,is_work INT
       ,is_holiday INT
    );
 
    INSERT INTO t_load_calendar
    SELECT DISTINCT c.dt
          ,c.is_work
          ,CASE WHEN c.is_work = 0 THEN 1
           ELSE 0 END AS is_is_holiday
    FROM dict.calendar AS c
    WHERE c.lev = 4
      AND c.dt BETWEEN v_dt_begin AND v_dt_end;
 
    IF (v_dt_begin >= v_dt_end)
        THEN v_result := 0;
    END IF;
 
    WHILE (v_current_day <= v_dt_end_trunc)
        LOOP
            v_number_day := EXTRACT(dow FROM v_current_day);
        
            IF (NOT EXISTS (SELECT dt
                            FROM t_load_calendar
                            WHERE is_holiday = 1
                              AND dt = v_current_day))
                THEN
                    v_begin_work := (CASE WHEN v_number_day IN (1,2,3,4,5) THEN v_work_time_beg --'Понедельник'- 'Пятница'
                                          WHEN v_number_day IN (6,0) THEN v_rest_time --'Суббота' - 'Воскресенье'
                                     END);
 
                IF v_begin_work IS NOT NULL
                    THEN
                        v_begin_work := (v_begin_work / 24) :: float8;
                        v_end_work := (COALESCE((CASE WHEN v_number_day IN (1,2,3,4) THEN v_work_time_end --'Понедельник'- 'Четверг'
                                                     WHEN v_number_day = 5 THEN v_work_time_end_fr --'Пятница'
                                                     WHEN v_number_day IN (6,0) THEN v_rest_time --'Суббота' - 'Воскресенье'
                                                END),24) / 24) :: float8;
                        v_begin_rest := (v_rest_time / 24) :: float8;
                        v_end_rest = (v_rest_time / 24) :: float8;
 
                IF (v_current_day = v_dt_begin_trunc)
                    THEN
                        v_begin_cur := (v_dt_begin_float - (EXTRACT(epoch FROM v_dt_begin_trunc) / 86400)) :: float8;
                ELSE
                    v_begin_cur := 0;
                END IF;
 
                IF (v_current_day = v_dt_end_trunc)
                    THEN
                        v_end_cur := (v_dt_end_float - (EXTRACT(epoch FROM v_dt_end_trunc) / 86400)) :: float8;
                ELSE
                    v_end_cur := 1;
                END IF;
 
                v_begin_work := (CASE WHEN v_begin_work > v_begin_cur THEN v_begin_work
                                      WHEN v_begin_cur > v_end_work THEN v_end_work
                                 ELSE v_begin_cur END) :: float8;
                v_end_work := (CASE WHEN v_end_cur < v_begin_work THEN v_begin_work
                                    WHEN v_end_work < v_end_cur THEN v_end_work
                               ELSE v_end_cur END) :: float8;
 
                IF v_begin_rest IS NOT NULL
                  AND v_end_rest IS NOT NULL
                  AND v_begin_rest < v_end_rest
                    THEN
                        v_rest_cur := (CASE WHEN v_begin_work = v_end_work THEN 0
                                            WHEN v_current_day = v_dt_begin_trunc
                                             AND v_current_day = v_dt_end_trunc
                                             AND v_begin_work <= v_begin_rest
                                             AND v_end_work >= v_end_rest THEN v_end_rest - v_begin_rest
                                            WHEN v_current_day = v_dt_begin_trunc
                                             AND v_current_day = v_dt_end_trunc
                                             AND v_begin_work > v_begin_rest
                                             AND v_end_work < v_end_rest THEN v_end_work - v_begin_work
                                            WHEN v_current_day = v_dt_begin_trunc
                                             AND v_current_day = v_dt_end_trunc
                                             AND v_begin_work <= v_begin_rest
                                             AND v_end_work <= v_begin_rest THEN 0
                                            WHEN v_current_day = v_dt_begin_trunc
                                             AND v_current_day = v_dt_end_trunc
                                             AND v_begin_work >= v_end_rest
                                             AND v_end_work >= v_end_rest THEN 0
                                            WHEN v_current_day = v_dt_begin_trunc
                                             AND v_current_day = v_dt_end_trunc
                                             AND v_begin_work <= v_begin_rest
                                             AND v_end_work BETWEEN v_begin_rest AND v_end_rest THEN v_end_work - v_begin_rest
                                            WHEN v_current_day = v_dt_begin_trunc
                                             AND v_current_day = v_dt_end_trunc
                                             AND v_begin_work BETWEEN v_begin_rest AND v_end_rest
                                             AND v_end_work >= v_end_rest THEN v_end_rest - v_begin_work
                                            WHEN v_current_day <> v_dt_begin_trunc
                                             AND v_current_day = v_dt_end_trunc
                                             AND v_end_work >= v_end_rest THEN v_end_rest - v_begin_rest
                                            WHEN v_current_day <> v_dt_begin_trunc
                                             AND v_current_day = v_dt_end_trunc
                                             AND v_end_work < v_end_rest
                                             AND v_end_work > v_begin_rest THEN v_end_work - v_begin_rest
                                            WHEN v_current_day <> v_dt_begin_trunc
                                             AND v_current_day = v_dt_end_trunc
                                             AND v_end_work < v_end_rest
                                             AND v_end_work <= v_begin_rest THEN 0
                                            WHEN v_current_day = v_dt_begin_trunc
                                             AND v_current_day <> v_dt_end_trunc
                                             AND v_begin_work <= v_begin_rest THEN v_end_rest - v_begin_rest
                                            WHEN v_current_day = v_dt_begin_trunc
                                             AND v_current_day <> v_dt_end_trunc
                                             AND v_begin_work > v_begin_rest
                                             AND v_begin_work < v_end_rest THEN v_end_rest - v_begin_work
                                            WHEN v_current_day = v_dt_begin_trunc
                                             AND v_current_day <> v_dt_end_trunc
                                             AND v_begin_work > v_begin_rest
                                             AND v_begin_work >= v_end_rest THEN 0
                                            WHEN v_current_day <> v_dt_begin_trunc
                                             AND v_current_day <> v_dt_end_trunc THEN v_end_rest - v_begin_rest
                                        ELSE 0 END) :: float8;
                ELSE
                    v_rest_cur := 0;
                END IF;
                v_result := (v_result + v_end_work - v_begin_work - v_rest_cur) :: float8;
            END IF;
        END IF;
        v_current_day := v_current_day + 1;
    END LOOP;
 
    v_result := (v_result * 24) :: float8;
 
    RETURN v_result;
 
END
 
$$
EXECUTE ON ANY;
Код функции на MS SQL (точно работает правильно):

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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
USE [ProDB_DataMart]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
 
 
ALTER FUNCTION [dbo].[GetWorkingTime]
(
    @Prm_Date_Begin datetime,
    @Prm_Date_End datetime
)
RETURNS FLOAT
AS
BEGIN
    
    DECLARE @Calendar TABLE ([DateValue] datetime NOT NULL,[IsWorkday] INT,[Holiday] INT);
 
    INSERT INTO @Calendar
    SELECT [Dt_report]
          ,CASE WHEN v.[vacant_dateformat] IS NOT NULL THEN 0
                WHEN [Is_Holiday] IS NULL THEN 1
           ELSE 0 END AS [IsWorkday]
          ,CASE WHEN v.[vacant_dateformat] IS NOT NULL THEN 1
           ELSE ISNULL([Is_Holiday],0) END AS [Holiday]
    FROM [ProDB_DataMart].[dbo].[Dict_Calendar] AS c WITH (NOLOCK)
    LEFT JOIN [ProDB_BWC].[dbo].[portal_krm_vacations] AS v ON CAST(c.[Dt_report] AS DATE) = v.[vacant_dateformat]
    WHERE [Dt_report] BETWEEN @Prm_Date_Begin AND @Prm_Date_End;
 
    -- возвращает рабочее время в днях
    DECLARE @Current_Day datetime
           ,@RESULT FLOAT = 0.0
           ,@fBeginWork FLOAT
           ,@fEndWork FLOAT
           ,@fBeginRest FLOAT
           ,@fEndRest FLOAT
           ,@fRestCur FLOAT
           ,@fBeginCur FLOAT
           ,@fEndCur FLOAT
           ,@work_time_beg AS FLOAT = 9.0
           ,@work_time_end AS FLOAT = 18.0
           ,@work_time_end_fr AS FLOAT = 17.0
           ,@rest_time AS FLOAT = NULL;
 
    IF (@Prm_Date_Begin >= @Prm_Date_End) RETURN 0.0;
 
    DECLARE @Prm_Date_Begin_Trunc AS datetime = CAST(@Prm_Date_Begin AS DATE)
    DECLARE @Prm_Date_End_Trunc AS datetime = CAST(@Prm_Date_End AS DATE);
    DECLARE @Prm_Date_Begin_Float AS FLOAT = CAST(@Prm_Date_Begin AS FLOAT);
    DECLARE @Prm_Date_End_Float AS FLOAT = CAST(@Prm_Date_End AS FLOAT);
 
    SET @Current_Day = @Prm_Date_Begin_Trunc
 
    DECLARE @DPC AS INT;
    
    while (@Current_Day <= @Prm_Date_End_Trunc)
    BEGIN
        SET @DPC = (DatePart(WEEKDAY,@Current_Day)+@@DATEFIRST)%7;
        
        IF (NOT EXISTS (SELECT [DateValue] FROM @Calendar WHERE [Holiday] = 1 AND [DateValue] = @Current_Day))
        BEGIN
            SET @fBeginWork = (CASE WHEN @DPC IN (2,3,4,5,6) THEN @work_time_beg --'Понедельник'- 'Пятница'
                                    WHEN @DPC IN (0,1) THEN @rest_time --'Суббота' - 'Воскресенье'
                               END);
 
            IF @fBeginWork IS NOT NULL
            BEGIN
                SET @fBeginWork = @fBeginWork / 24.0
                
                SET @fEndWork = isnull((CASE WHEN @DPC IN (2,3,4,5) THEN @work_time_end --'Понедельник'- 'Четверг'
                                             WHEN @DPC = 6 THEN @work_time_end_fr --'Пятница'
                                             WHEN @DPC IN (0,1) THEN @rest_time --'Суббота' - 'Воскресенье'
                                        END), 24.0) / 24.0;
 
                SET @fBeginRest = @rest_time / 24.0;
 
                SET @fEndRest = @rest_time / 24.0;
 
                IF (@Current_Day = @Prm_Date_Begin_Trunc)
                BEGIN
                    SET @fBeginCur = CAST(@Prm_Date_Begin_Float AS FLOAT) - CAST(@Prm_Date_Begin_Trunc AS FLOAT);
                END
                ELSE
                BEGIN
                    SET @fBeginCur = 0.0;
                END;
                
                IF (@Current_Day = @Prm_Date_End_Trunc)
                BEGIN
                    SET @fEndCur = CAST(@Prm_Date_End_Float AS FLOAT) - CAST(@Prm_Date_End_Trunc AS FLOAT);
                END
                ELSE
                BEGIN
                    SET @fEndCur = 1.0;
                END;
                
                SET @fBeginWork = (CASE WHEN @fBeginWork > @fBeginCur THEN @fBeginWork WHEN @fBeginCur > @fEndWork THEN @fEndWork ELSE @fBeginCur END);
                SET @fEndWork = (CASE WHEN @fEndCur < @fBeginWork THEN @fBeginWork WHEN @fEndWork < @fEndCur THEN @fEndWork ELSE @fEndCur END);
                
                IF @fBeginRest IS NOT NULL AND @fEndRest IS NOT NULL AND @fBeginRest < @fEndRest
                BEGIN
                    SET @fRestCur = CAST((CASE WHEN @fBeginWork = @fEndWork THEN 0.0
                                               WHEN @Current_Day = @Prm_Date_Begin_Trunc
                                                AND @Current_Day = @Prm_Date_End_Trunc
                                                AND @fBeginWork <= @fBeginRest
                                                AND @fEndWork >= @fEndRest THEN @fEndRest - @fBeginRest
                                               WHEN @Current_Day = @Prm_Date_Begin_Trunc
                                                AND @Current_Day = @Prm_Date_End_Trunc
                                                AND @fBeginWork > @fBeginRest
                                                AND @fEndWork < @fEndRest THEN @fEndWork - @fBeginWork
                                               WHEN @Current_Day = @Prm_Date_Begin_Trunc
                                                AND @Current_Day = @Prm_Date_End_Trunc
                                                AND @fBeginWork <= @fBeginRest
                                                AND @fEndWork <= @fBeginRest THEN 0.0
                                               WHEN @Current_Day = @Prm_Date_Begin_Trunc
                                                AND @Current_Day = @Prm_Date_End_Trunc
                                                AND @fBeginWork >= @fEndRest
                                                AND @fEndWork >= @fEndRest THEN 0.0
                                               WHEN @Current_Day = @Prm_Date_Begin_Trunc
                                                AND @Current_Day = @Prm_Date_End_Trunc
                                                AND @fBeginWork <= @fBeginRest
                                                AND @fEndWork BETWEEN @fBeginRest AND @fEndRest THEN @fEndWork - @fBeginRest
                                               WHEN @Current_Day = @Prm_Date_Begin_Trunc
                                                AND @Current_Day = @Prm_Date_End_Trunc
                                                AND @fBeginWork BETWEEN @fBeginRest AND @fEndRest
                                                AND @fEndWork >= @fEndRest THEN @fEndRest - @fBeginWork
                                               WHEN @Current_Day <> @Prm_Date_Begin_Trunc
                                                AND @Current_Day = @Prm_Date_End_Trunc
                                                AND @fEndWork >= @fEndRest THEN @fEndRest - @fBeginRest
                                               WHEN @Current_Day <> @Prm_Date_Begin_Trunc
                                                AND @Current_Day = @Prm_Date_End_Trunc
                                                AND @fEndWork < @fEndRest
                                                AND @fEndWork > @fBeginRest THEN @fEndWork - @fBeginRest
                                               WHEN @Current_Day <> @Prm_Date_Begin_Trunc
                                                AND @Current_Day = @Prm_Date_End_Trunc
                                                AND @fEndWork < @fEndRest
                                                AND @fEndWork <= @fBeginRest THEN 0.0
                                               WHEN @Current_Day = @Prm_Date_Begin_Trunc
                                                AND @Current_Day <> @Prm_Date_End_Trunc
                                                AND @fBeginWork <= @fBeginRest THEN @fEndRest - @fBeginRest
                                               WHEN @Current_Day = @Prm_Date_Begin_Trunc
                                                AND @Current_Day <> @Prm_Date_End_Trunc
                                                AND @fBeginWork > @fBeginRest
                                                AND @fBeginWork < @fEndRest THEN @fEndRest - @fBeginWork
                                               WHEN @Current_Day = @Prm_Date_Begin_Trunc
                                                AND @Current_Day <> @Prm_Date_End_Trunc
                                                AND @fBeginWork > @fBeginRest
                                                AND @fBeginWork >= @fEndRest THEN 0.0
                                               WHEN @Current_Day <> @Prm_Date_Begin_Trunc
                                               AND @Current_Day <> @Prm_Date_End_Trunc THEN @fEndRest - @fBeginRest
                                          ELSE 0.0 END) AS FLOAT);
                END
                ELSE
                BEGIN
                    SET @fRestCur = 0;
                END;
                
                SET @RESULT = @RESULT + @fEndWork - @fBeginWork - @fRestCur;
            END;
        END;
        SET @Current_Day = @Current_Day + 1;
    END;
 
    SET @RESULT = @RESULT * 24.0;
 
    RETURN @RESULT;
END
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
24.03.2023, 19:57
Ответы с готовыми решениями:

Ошибка при выполнении функции по подсчету времени на Postgre SQL
Всем привет! Помогите пожалуйста разобраться с ошибкой при выполнении функции по подсчету рабочего времени. Создала функцию, код...

PostGre SQL 9_3_4_1_1C - не пускает под postgres
Доброе время суток. Установил вышеуказанную версию PostGreSQL, сборка от 1С. Системному пользователю postgres установил пароль: passwd...

Выполнить три запроса подряд к Postgre SQL
Доброе утро. мне надо открыть сессию, сделать апдейт таблицы и закрыть сессию. если делать в PgAdmin, DBeaver, то получается ( в первом...

0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
24.03.2023, 19:57
Помогаю со студенческими работами здесь

Функция по подсчету рабочего времени на Postgre SQL
Всем привет! Помогите пожалуйста разобраться с функцией по подсчету рабочего времени. Функция при подстановке любых дат всегда выдает...

Подскажите как переконвертировать реляционную схему из visio в sql для Postgre
Подскажите, пожалуйста, как автоматически переконвертировать реляционную схему из visio в sql, желательно для Postgre. Спасибо большое.

Перевод из Oracle SQL в MS SQL
Всем доброго времени суток. Как перевезти это на MS SQL Server. В основном оно ругается на cursor, then и return. Буду очень...

Перевод из t-sql в pl/sql
Добрый день. Очень нужна помощь, дело в том что мне нужно готовые функции и процедуры перевести на язык pls sql с sql server Сроки...

У кого-нибудь есть база данных TSQL2012.sql из книги: Ицек Бен-Ген "Высокопроизводительный код T-SQL. Оконные функции"?
У кого-нибудь есть база данных TSQL2012.sql из книги: Ицек Бен-Ген &quot;Высокопроизводительный код T-SQL. Оконные функции&quot;? Сайт с...


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

Или воспользуйтесь поиском по форуму:
1
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Обработчик клика мыши в браузере ПК и касания экрана в браузере на мобильном устройстве
8Observer8 02.02.2026
Содержание блога Для начала пошагово создадим рабочий пример для подготовки к экспериментам в браузере ПК и в браузере мобильного устройства. Потом напишем обработчик клика мыши и обработчик. . .
Философия технологии
iceja 01.02.2026
На мой взгляд у человека в технических проектах остается роль генерального директора. Все остальное нейронки делают уже лучше человека. Они не могут нести предпринимательские риски, не могут. . .
SDL3 для Web (WebAssembly): Вывод текста со шрифтом TTF с помощью SDL3_ttf
8Observer8 01.02.2026
Содержание блога В этой пошаговой инструкции создадим с нуля веб-приложение, которое выводит текст в окне браузера. Запустим на Android на локальном сервере. Загрузим Release на бесплатный. . .
SDL3 для Web (WebAssembly): Сборка C/C++ проекта из консоли
8Observer8 30.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
SDL3 для Web (WebAssembly): Установка Emscripten SDK (emsdk) и CMake для сборки C и C++ приложений в Wasm
8Observer8 30.01.2026
Содержание блога Для того чтобы скачать Emscripten SDK (emsdk) необходимо сначало скачать и уставить Git: Install for Windows. Следуйте стандартной процедуре установки Git через установщик. . . .
SDL3 для Android: Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 29.01.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами. Версия v3 была полностью переписана на Си, в. . .
Инструменты COM: Сохранение данный из VARIANT в файл и загрузка из файла в VARIANT
bedvit 28.01.2026
Сохранение базовых типов COM и массивов (одномерных или двухмерных) любой вложенности (деревья) в файл, с возможностью выбора алгоритмов сжатия и шифрования. Часть библиотеки BedvitCOM Использованы. . .
SDL3 для Android: Загрузка PNG с альфа-каналом с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 28.01.2026
Содержание блога SDL3 имеет собственные средства для загрузки и отображения PNG-файлов с альфа-каналом и базовой работы с ними. В этой инструкции используется функция SDL_LoadPNG(), которая. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru