powered by simpleCommunicator - 2.0.59     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Проблема с временной таблицей
15 сообщений из 15, страница 1 из 1
Проблема с временной таблицей
    #39501809
NumberOne
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Здравствуйте, хочу спросить совета.
Собственно проблема:
Существует функция в которой создаются временные таблицы и происходит работа с ними. При повторном обращении к этой функции, если предыдущий вызов функции еще в работе, то происходит работа с теми же таблицами которые были созданы при первом обращении к функции и не успели удалиться ( либо ошибка повторного создания таблицы с тем же именем, в зависимости от команды создания таблицы). Как сделать так, чтобы для каждого вызова функции использовалась своя временная таблица?
З.Ы. динамические запросы с созданием уникальных имен таблиц не годятся, так как теряется тот выигрыш производительности ради которого была написана функция.

Оба вызова должны происходить в одной и той же сессии.

Вот пример подобного случая. Удаление временных таблиц в конце функций убрал специально, чтобы было видно, что по завершению работ обоих функций они работали с одной и той же таблицей.
Код: 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.
CREATE OR REPLACE FUNCTION tst(id1 uuid)
RETURNS TABLE (obj_id uuid, test_id uuid) AS $$
BEGIN

	CREATE TEMP TABLE test2 (old_id uuid, new_id uuid);
        INSERT INTO test2 VALUES('b564c518-025f-4d82-a99e-edb8b47e23bc', 'b564c518-025f-4d82-a99e-edb8b47e23bc');
	RETURN;
    
END; $$ LANGUAGE plpgsql;

CREATE OR REPLACE FUNCTION tst2(id1 uuid)
RETURNS TABLE (obj_id uuid, test_id uuid) AS $$
BEGIN
    CREATE TEMP TABLE IF NOT EXISTS test2 (old_id uuid, new_id uuid);
    INSERT INTO test2 VALUES('b564c518-025f-4d82-a99e-edb8b47e23bc', 'b564c518-025f-4d82-a99e-edb8b47e23bc');
    RETURN;
    
END; $$ LANGUAGE plpgsql;


SELECT tst('b564c518-025f-4d82-a99e-edb8b47e23bc');
SELECT tst2('b564c518-025f-4d82-a99e-edb8b47e23bc');


SELECT * FROM test2;
DROP TABLE test2;



Запрос SELECT * FROM test2; выдает две строки. Если вызов IF NOT EXISTS во второй функции убрать, просто будет ошибка "отношение существует".
...
Рейтинг: 0 / 0
Проблема с временной таблицей
    #39501845
Ролг Хупин
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
NumberOneЗдравствуйте, хочу спросить совета.
Собственно проблема:
Существует функция в которой создаются временные таблицы и происходит работа с ними. При повторном обращении к этой функции, если предыдущий вызов функции еще в работе, то происходит работа с теми же таблицами которые были созданы при первом обращении к функции и не успели удалиться ( либо ошибка повторного создания таблицы с тем же именем, в зависимости от команды создания таблицы). Как сделать так, чтобы для каждого вызова функции использовалась своя временная таблица?
З.Ы. динамические запросы с созданием уникальных имен таблиц не годятся, так как теряется тот выигрыш производительности ради которого была написана функция.

Оба вызова должны происходить в одной и той же сессии.

Вот пример подобного случая. Удаление временных таблиц в конце функций убрал специально, чтобы было видно, что по завершению работ обоих функций они работали с одной и той же таблицей.
Код: 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.
CREATE OR REPLACE FUNCTION tst(id1 uuid)
RETURNS TABLE (obj_id uuid, test_id uuid) AS $$
BEGIN

	CREATE TEMP TABLE test2 (old_id uuid, new_id uuid);
        INSERT INTO test2 VALUES('b564c518-025f-4d82-a99e-edb8b47e23bc', 'b564c518-025f-4d82-a99e-edb8b47e23bc');
	RETURN;
    
END; $$ LANGUAGE plpgsql;

CREATE OR REPLACE FUNCTION tst2(id1 uuid)
RETURNS TABLE (obj_id uuid, test_id uuid) AS $$
BEGIN
    CREATE TEMP TABLE IF NOT EXISTS test2 (old_id uuid, new_id uuid);
    INSERT INTO test2 VALUES('b564c518-025f-4d82-a99e-edb8b47e23bc', 'b564c518-025f-4d82-a99e-edb8b47e23bc');
    RETURN;
    
END; $$ LANGUAGE plpgsql;


SELECT tst('b564c518-025f-4d82-a99e-edb8b47e23bc');
SELECT tst2('b564c518-025f-4d82-a99e-edb8b47e23bc');


SELECT * FROM test2;
DROP TABLE test2;



Запрос SELECT * FROM test2; выдает две строки. Если вызов IF NOT EXISTS во второй функции убрать, просто будет ошибка "отношение существует".

используйте разные имена, вы сами уперлись в свой дизайн. Определитесь - вам нужна одна и та же таблица или разные?
...
Рейтинг: 0 / 0
Проблема с временной таблицей
    #39501862
NumberOne
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Ролг ХупинNumberOneЗдравствуйте, хочу спросить совета.
Собственно проблема:
Существует функция в которой создаются временные таблицы и происходит работа с ними. При повторном обращении к этой функции, если предыдущий вызов функции еще в работе, то происходит работа с теми же таблицами которые были созданы при первом обращении к функции и не успели удалиться ( либо ошибка повторного создания таблицы с тем же именем, в зависимости от команды создания таблицы). Как сделать так, чтобы для каждого вызова функции использовалась своя временная таблица?
З.Ы. динамические запросы с созданием уникальных имен таблиц не годятся, так как теряется тот выигрыш производительности ради которого была написана функция.

Оба вызова должны происходить в одной и той же сессии.

Вот пример подобного случая. Удаление временных таблиц в конце функций убрал специально, чтобы было видно, что по завершению работ обоих функций они работали с одной и той же таблицей.
Код: 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.
CREATE OR REPLACE FUNCTION tst(id1 uuid)
RETURNS TABLE (obj_id uuid, test_id uuid) AS $$
BEGIN

	CREATE TEMP TABLE test2 (old_id uuid, new_id uuid);
        INSERT INTO test2 VALUES('b564c518-025f-4d82-a99e-edb8b47e23bc', 'b564c518-025f-4d82-a99e-edb8b47e23bc');
	RETURN;
    
END; $$ LANGUAGE plpgsql;

CREATE OR REPLACE FUNCTION tst2(id1 uuid)
RETURNS TABLE (obj_id uuid, test_id uuid) AS $$
BEGIN
    CREATE TEMP TABLE IF NOT EXISTS test2 (old_id uuid, new_id uuid);
    INSERT INTO test2 VALUES('b564c518-025f-4d82-a99e-edb8b47e23bc', 'b564c518-025f-4d82-a99e-edb8b47e23bc');
    RETURN;
    
END; $$ LANGUAGE plpgsql;


SELECT tst('b564c518-025f-4d82-a99e-edb8b47e23bc');
SELECT tst2('b564c518-025f-4d82-a99e-edb8b47e23bc');


SELECT * FROM test2;
DROP TABLE test2;



Запрос SELECT * FROM test2; выдает две строки. Если вызов IF NOT EXISTS во второй функции убрать, просто будет ошибка "отношение существует".

используйте разные имена, вы сами уперлись в свой дизайн. Определитесь - вам нужна одна и та же таблица или разные?

Это в примере я привел две разные функции, чтобы было нагляднее. На деле функция одна, но может вызывается несколько раз в одно и то же время, соответственно и у таблиц названия будут одинаковые. Если название временной таблицы генерировать в каждом вызове уникальное, с помощью динамических запросов, то теряется производительность, как я уже писал.
...
Рейтинг: 0 / 0
Проблема с временной таблицей
    #39501869
p2.
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
NumberOneесли предыдущий вызов функции еще в работеВременные таблицы "не нужны".
...
Рейтинг: 0 / 0
Проблема с временной таблицей
    #39501875
Ролг Хупин
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
NumberOneРолг Хупинпропущено...


используйте разные имена, вы сами уперлись в свой дизайн. Определитесь - вам нужна одна и та же таблица или разные?

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

"Как сделать так, чтобы для каждого вызова функции использовалась своя временная таблица? "

и так плохо, и так плохо.
...
Рейтинг: 0 / 0
Проблема с временной таблицей
    #39501886
NumberOne
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Ролг ХупинNumberOneпропущено...


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

"Как сделать так, чтобы для каждого вызова функции использовалась своя временная таблица? "

и так плохо, и так плохо.

p2.NumberOneесли предыдущий вызов функции еще в работеВременные таблицы "не нужны".

Как обойтись без временных таблиц, если происходит копирование сущностей со множеством связей на другие таблицы, в том числе рекурсивными, особенно, если требуется предварительная проверка на то, что сущность уже существует (доскональная проверка всех ее связей, в том числе рекурсивных, если есть какие-то расхождения, то копирование вообще не должно происходить).
...
Рейтинг: 0 / 0
Проблема с временной таблицей
    #39501939
p2.
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
NumberOneКак обойтись без Возвращать результат непосредственно из функции, как и заявлено в приведенной тобой декларации.
И поменьше фантазировать по поводу существования временной таблицы в "одно и то же время".
...
Рейтинг: 0 / 0
Проблема с временной таблицей
    #39501944
NumberOne
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Решил попробовать переписать с использованием WITH. Столкнулся с проблемой. Во временную таблицу вставляются некоторые данные, затем в этих данных обновлялось некое поле, после проводилась проверка, что если хоть в одной строке таблицы в этом поле будет NULL то производился выход из функции с возвратом кода ошибки. Если все было нормально, то данные из временной таблицы копировались в нужную таблицу. Так вот с конструкцией WITH вместо вставки во временную таблицу делаю WITH temp_table AS ( SELECT ...), up_table (UPDATE temp_table ...), XXX INSERT INTO chosen_table FROM temp_table. Так вот, как вместо этих XXX, устроить проверку на NULL, и в случае не выполнения условия не допустить вставки в таблицу chosen_table.
...
Рейтинг: 0 / 0
Проблема с временной таблицей
    #39501949
NumberOne
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
p2.NumberOneКак обойтись без Возвращать результат непосредственно из функции, как и заявлено в приведенной тобой декларации.
И поменьше фантазировать по поводу существования временной таблицы в "одно и то же время".

т.е. не может одна функция быть запущена несколько раз в одно и тоже время в одной сессии?
...
Рейтинг: 0 / 0
Проблема с временной таблицей
    #39501955
Фотография Maxim Boguk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
NumberOnep2.пропущено...
Возвращать результат непосредственно из функции, как и заявлено в приведенной тобой декларации.
И поменьше фантазировать по поводу существования временной таблицы в "одно и то же время".

т.е. не может одна функция быть запущена несколько раз в одно и тоже время в одной сессии?

Нет конечно. Это физически не возможно.
В одно время в одной сессии только что то одно может работать.

--
Maxim Boguk
dataegret.ru - лучшая русскоязычная поддержка PostgreSQL
...
Рейтинг: 0 / 0
Проблема с временной таблицей
    #39501985
NumberOne
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Maxim BogukNumberOneпропущено...


т.е. не может одна функция быть запущена несколько раз в одно и тоже время в одной сессии?

Нет конечно. Это физически не возможно.
В одно время в одной сессии только что то одно может работать.

--
Maxim Boguk
dataegret.ru - лучшая русскоязычная поддержка PostgreSQL

Спасибо за информацию. Все равно решил попробовать избавиться от временных таблиц, так что повторю вопрос из прошлого поста.

Решил попробовать переписать с использованием WITH. Столкнулся с проблемой. Во временную таблицу вставляются некоторые данные, затем в этих данных обновлялось некое поле, после проводилась проверка, что если хоть в одной строке таблицы в этом поле будет NULL то производился выход из функции с возвратом кода ошибки. Если все было нормально, то данные из временной таблицы копировались в нужную таблицу. Так вот с конструкцией WITH вместо вставки во временную таблицу делаю WITH temp_table AS ( SELECT ...), up_table (UPDATE temp_table ...), XXX INSERT INTO chosen_table FROM temp_table. Так вот, как вместо этих XXX, устроить проверку на NULL, и в случае не выполнения условия не допустить вставки в таблицу chosen_table.
...
Рейтинг: 0 / 0
Проблема с временной таблицей
    #39501989
Фотография Maxim Boguk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
NumberOne,
эээ а добавить в INSERT условие WHERE чегоужвамтамнадо IS NOT NULL?
...
Рейтинг: 0 / 0
Проблема с временной таблицей
    #39502006
NumberOne
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Maxim BogukNumberOne,
эээ а добавить в INSERT условие WHERE чегоужвамтамнадо IS NOT NULL?
IS NOT NULL не подойдет потому, что в случае, если хотя бы один NULL в какой-то строке, то уже не надо вставлять все строки, а не только ту в которой нашелся NULL. Предположим если я сделаю дополнительный код в WITH , вроде ..., null_count AS (SELECT COUNT(*) AS ncount FROM temp_table WHERE my_var IS NULL, а потом при вставке в WITH к нему буду обращаться, вроде ... INSERT chosen_table FROM temp_table, null_count WHERE null_count.ncount >0. Синтаксис не правильный, наверно, но примерный. Не знаю, вообще можно ли, как-нибудь так написать. Но, в общем, даже, если это сработает. Как, в случае, если там все-таки были NULL'ы потом завершить функцию с соответствующим кодом ошибки, а не обычным образом. (Проверкой, что в chosen_table добавились новые строки?) При том, что необходимо вставить данные в этом же WITH еще в несколько таблиц связанных, и так же должно пройти еще несколько проверок (в этом же with) на подобие проверок на NULL.
...
Рейтинг: 0 / 0
Проблема с временной таблицей
    #39503627
NumberOne
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
NumberOneMaxim BogukNumberOne,
эээ а добавить в INSERT условие WHERE чегоужвамтамнадо IS NOT NULL?
IS NOT NULL не подойдет потому, что в случае, если хотя бы один NULL в какой-то строке, то уже не надо вставлять все строки, а не только ту в которой нашелся NULL. Предположим если я сделаю дополнительный код в WITH , вроде ..., null_count AS (SELECT COUNT(*) AS ncount FROM temp_table WHERE my_var IS NULL, а потом при вставке в WITH к нему буду обращаться, вроде ... INSERT chosen_table FROM temp_table, null_count WHERE null_count.ncount >0. Синтаксис не правильный, наверно, но примерный. Не знаю, вообще можно ли, как-нибудь так написать. Но, в общем, даже, если это сработает. Как, в случае, если там все-таки были NULL'ы потом завершить функцию с соответствующим кодом ошибки, а не обычным образом. (Проверкой, что в chosen_table добавились новые строки?) При том, что необходимо вставить данные в этом же WITH еще в несколько таблиц связанных, и так же должно пройти еще несколько проверок (в этом же with) на подобие проверок на NULL.

Да, то что я написал выше работает, но мне необходим совет для решения следующих проблем. Ниже приведен упрощенный (неработающий) вариант функции.
Происходит копирование некой сущности (objects) с подчиненными данными (first_table, second_table).
Некоторые таблицы подчиненных данных не копируются в том случае если такие же подчиненные данные уже существуют в данной таблице. Тогда происходит только запоминание соответствий idшников.
Функция должна вернуть таблицу: в случае успешного копирования должно быть две строки (в приведенном ниже примере) об успехе двух инсертов, в случае неуспеха одна строка с ошибкой.

Теперь вопросы:
1) После определения count_table.null_count, если значение не нулевое то дальнейшие вставки не нужны, а только вывод строки с ошибкой, сейчас вставки и не происходят благодаря приписыванию "FROM count_table WHERE count_table.null_count = 0" или "JOIN count_table ON count_table.null_count = 0". Но получается происходят ненужные проверки, так как функция уже ничего не должна делать. (В настоящей функции после этой проверки еще шагов 7 происходит со вставками(а в примере только 2)). Вопрос как приостановить выполнение из конструкции WITH или как переделать функцию, чтобы этого избежать?
2) Можно ли так UNION использовать "SELECT * FROM return_error_string UNION SELECT * FROM return_string1 UNION SELECT * FROM return_string2" для заполнения возвращаемой таблицы?

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
DECLARE new_object_id uuid = uuid_generate_v1();
DECLARE something_information varchar(60) = 'something text';

RETURN QUERY WITH RECURSIVE id_matching AS ( SELECT t1.id AS id1, t2.id AS id2 FROM first_table t1 LEFT JOIN first_table t2 t1 ON t1.par = t2.par WHERE t1.object_id = код_копируемого_объекта),

count_table AS (SELECT COUNT(*)  AS null_count FROM id_matching WHERE id2 IS NULL),

return_error_string AS (SELECT 'несоответствие подчиненных данных' FROM count_table WHERE count_table.null_count <> 0),

inserting1 AS (INSERT INTO second_table (first_id, something_information) SELECT id_matching.id2, second_table.something_information
FROM JOIN count_table ON count_table.null_count = 0 second_table LEFT JOIN id_matching ON second_table.first_id = id_matching.id1),

return_string1 AS (SELECT 'подчиненные данные вставлены' FROM count_table WHERE count_table.null_count = 0),

inserting2 AS (INSERT INTO objects (id, something_information) SELECT new_object_id, something_information FROM count_table WHERE count_table.null_count = 0),

return_string2 AS (SELECT 'объект скопирован'  FROM count_table WHERE count_table.null_count = 0)

SELECT * FROM return_error_string UNION SELECT * FROM return_string1 UNION SELECT * FROM return_string2;
  
...
Рейтинг: 0 / 0
Проблема с временной таблицей
    #39510829
NumberOne
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
NumberOneNumberOneпропущено...

IS NOT NULL не подойдет потому, что в случае, если хотя бы один NULL в какой-то строке, то уже не надо вставлять все строки, а не только ту в которой нашелся NULL. Предположим если я сделаю дополнительный код в WITH , вроде ..., null_count AS (SELECT COUNT(*) AS ncount FROM temp_table WHERE my_var IS NULL, а потом при вставке в WITH к нему буду обращаться, вроде ... INSERT chosen_table FROM temp_table, null_count WHERE null_count.ncount >0. Синтаксис не правильный, наверно, но примерный. Не знаю, вообще можно ли, как-нибудь так написать. Но, в общем, даже, если это сработает. Как, в случае, если там все-таки были NULL'ы потом завершить функцию с соответствующим кодом ошибки, а не обычным образом. (Проверкой, что в chosen_table добавились новые строки?) При том, что необходимо вставить данные в этом же WITH еще в несколько таблиц связанных, и так же должно пройти еще несколько проверок (в этом же with) на подобие проверок на NULL.

Да, то что я написал выше работает, но мне необходим совет для решения следующих проблем. Ниже приведен упрощенный (неработающий) вариант функции.
Происходит копирование некой сущности (objects) с подчиненными данными (first_table, second_table).
Некоторые таблицы подчиненных данных не копируются в том случае если такие же подчиненные данные уже существуют в данной таблице. Тогда происходит только запоминание соответствий idшников.
Функция должна вернуть таблицу: в случае успешного копирования должно быть две строки (в приведенном ниже примере) об успехе двух инсертов, в случае неуспеха одна строка с ошибкой.

Теперь вопросы:
1) После определения count_table.null_count, если значение не нулевое то дальнейшие вставки не нужны, а только вывод строки с ошибкой, сейчас вставки и не происходят благодаря приписыванию "FROM count_table WHERE count_table.null_count = 0" или "JOIN count_table ON count_table.null_count = 0". Но получается происходят ненужные проверки, так как функция уже ничего не должна делать. (В настоящей функции после этой проверки еще шагов 7 происходит со вставками(а в примере только 2)). Вопрос как приостановить выполнение из конструкции WITH или как переделать функцию, чтобы этого избежать?
2) Можно ли так UNION использовать "SELECT * FROM return_error_string UNION SELECT * FROM return_string1 UNION SELECT * FROM return_string2" для заполнения возвращаемой таблицы?

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
DECLARE new_object_id uuid = uuid_generate_v1();
DECLARE something_information varchar(60) = 'something text';

RETURN QUERY WITH RECURSIVE id_matching AS ( SELECT t1.id AS id1, t2.id AS id2 FROM first_table t1 LEFT JOIN first_table t2 t1 ON t1.par = t2.par WHERE t1.object_id = код_копируемого_объекта),

count_table AS (SELECT COUNT(*)  AS null_count FROM id_matching WHERE id2 IS NULL),

return_error_string AS (SELECT 'несоответствие подчиненных данных' FROM count_table WHERE count_table.null_count <> 0),

inserting1 AS (INSERT INTO second_table (first_id, something_information) SELECT id_matching.id2, second_table.something_information
FROM JOIN count_table ON count_table.null_count = 0 second_table LEFT JOIN id_matching ON second_table.first_id = id_matching.id1),

return_string1 AS (SELECT 'подчиненные данные вставлены' FROM count_table WHERE count_table.null_count = 0),

inserting2 AS (INSERT INTO objects (id, something_information) SELECT new_object_id, something_information FROM count_table WHERE count_table.null_count = 0),

return_string2 AS (SELECT 'объект скопирован'  FROM count_table WHERE count_table.null_count = 0)

SELECT * FROM return_error_string UNION SELECT * FROM return_string1 UNION SELECT * FROM return_string2;
  



Решить удалось только с помощью использования массивов. Тему можно закрывать. Спасибо всем, кто помогал.
...
Рейтинг: 0 / 0
15 сообщений из 15, страница 1 из 1
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Проблема с временной таблицей
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]