Вывод нескольких SELECT-ов в одну таблицу
можно воспользоваться объединением запросов (union):
select "запрос 1", count(*) from . where . union select "запрос 2", count(*) from . where . union .
Отслеживать
ответ дан 29 ноя 2016 в 6:39
aleksandr barakin aleksandr barakin
67.9k 216 216 золотых знаков 77 77 серебряных знаков 219 219 бронзовых знаков
Предложу такой вариант: Написать процедуру, в которой: 1) Будет создаваться таблица, определяющая Вашу результирующую таблицу 2) Делать выборки исходной таблицы 3) Проходится по каждой выборки и вставлять данные в таблицу, созданную в 1 пункте
Отслеживать
ответ дан 29 ноя 2016 в 0:44
2,015 4 4 золотых знака 27 27 серебряных знаков 53 53 бронзовых знака
Вот как решил проблему
SELECT "request_1" AS "Запрос 1", "request_2" AS "Запрос 2", "request_3" AS "Запрос 3", "request_4" AS "Запрос 4" FROM ( -- Исполняем запрос 1 SELECT count("customer"."id") FROM "customer" WHERE "customer"."unsubscribed_types" = 'daily_weekdays' OR "customer"."unsubscribed_types" = 'daily_weekends' OR "customer"."unsubscribed_types" = 'weekly_free' OR "customer"."unsubscribed_types" = 'weekly_best_weekly' OR "customer"."unsubscribed_types" = 'special_partner' OR "customer"."unsubscribed_types" = 'bonus_activation' ) AS "request_1", ( -- Исполняем запрос 2 SELECT count("customer"."id") FROM "customer" WHERE "customer"."unsubscribed_types" ISNULL OR "customer"."unsubscribed_types" = '<>' ) AS "request_2", ( -- Исполняем запрос 3 SELECT count("customer"."id") FROM "customer" WHERE "customer"."unsubscribed_types" = 'daily_weekdays' AND "customer"."unsubscribed_types" = 'daily_weekends' AND "customer"."unsubscribed_types" = 'weekly_free' AND "customer"."unsubscribed_types" = 'weekly_best_weekly' AND "customer"."unsubscribed_types" = 'special_partner' AND "customer"."unsubscribed_types" = 'bonus_activation' ) AS "request_3", ( -- Исполняем запрос 4 SELECT count("customer"."id") FROM "customer" WHERE "unsubscribed_types" = 'daily_weekdays' ) AS "request_4", ;
Отслеживать
ответ дан 29 ноя 2016 в 1:09
Sergey SHevchenko Sergey SHevchenko
49 1 1 золотой знак 1 1 серебряный знак 9 9 бронзовых знаков
- sql
- postgresql
- запрос-в-запросе
-
Важное на Мете
Похожие
Подписаться на ленту
Лента вопроса
Для подписки на ленту скопируйте и вставьте эту ссылку в вашу программу для чтения RSS.
Дизайн сайта / логотип © 2023 Stack Exchange Inc; пользовательские материалы лицензированы в соответствии с CC BY-SA . rev 2023.11.15.1019
Нажимая «Принять все файлы cookie» вы соглашаетесь, что Stack Exchange может хранить файлы cookie на вашем устройстве и раскрывать информацию в соответствии с нашей Политикой в отношении файлов cookie.
Bablosoft
Как в SQL сделать сразу несколько запросов в одном действии
Запланировано Прикреплена Закрыта Перенесена Поддержка
64 Сообщения 6 Posters 825 Просмотры
Эта тема была удалена. Только пользователи с правом управления темами могут её видеть.
ответил Bigma в отредактировано
Щас глянуть не могу, что он возвращает в ответ, но можно писать ведь не 1 а номер потока к примеру, или рендом. И по этому числу искать запись. Проверю завтра.
Да многое можно, а потом посмотреть на свой код и понять, что ты сделал функционал SELECT FOR UPDATE .
P.S.
У меня была такая история.
ответил sergerdn в отредактировано
@sergerdn Как ты уже написал, она лочит всю таблицу, имей это ввиду.
ответил Bigma в отредактировано
@sergerdn Как ты уже написал, она лочит всю таблицу, имей это ввиду.
Я же сам это написал, конечно я имею в виду. И так же добавил, что эта информация может быть устаревшая и надо ее проверять. Может у современных реализаций INNODB немного не так. Может лочится только одна запись в таблице на чтение. Чтобы другой поток не захватил ее.
Под капотом БД многое что делается, другое дело, что ты не знаешь об этом и «спишь спокойно».
написал в отредактировано
Друзья, вопрос же не в частном случае. В справке написано что можно несколько строк, вот мой вопрос и сводится к тому — как сделать чтобы в кубике работало несколько строк. А вы в какие то дербри полезли
ответил Shogo в отредактировано GhostZ
@Shogo, многострочный запрос и несколько запросов в одном, это не одно и тоже, модуль поддерживает многострочные запросы, но не поддерживает несколько запросов в одном, так как либо они не поддерживаются в конкретном диалекте или отключены по умолчанию. Например в MySQL и MariaDB, несколько запросов в одном отключены по умолчанию, а чтобы их включить нужно добавить multipleStatements: true в настройки диалекта.
Как отправить в sql несколько запрос в одном пакете?
Вообщем есть код который отправляет запросы в sql, проблема в том что отправляет только по одному запросу, как только вставляю 2 запроса выпадает ошибка. Подскажите пожалуйста как можно оптимизировать и отправить пакет с несколькими запросами?
Текст = "UPD ATE `oc_category` SE T `parent_id` = '3' WHERE `oc_category`.`category_id` = 1; |UPDATE `oc_category` SE T `parent_id` = '4' WHERE `oc_category`.`category_id` = 2;"; Результат.CommandText = Текст; Результат.Execute();
Ошибка:
: Ошибка при вызове метода контекста (Execute)
Результат.Execute();
по причине:
Произошла исключительная ситуация (Microsoft OLE DB Provider for ODBC Drivers): [MySQL][ODBC 5.3(w) Driver][mysqld-5.7.30-log]You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘UPDATE `oc_category` SE T `parent_id` = ‘4’ WHERE `oc_category`.`category_id` = 2′ at line 2
По теме из базы знаний
- Обзор имеющихся библиотек OneScript
- Расширение для интеграции с маркетплейсами из одного окна: Озон, ВБ, Яндекс, Сбер, Али, ЛаМода для 1С:УНФ, УТ, КА, ERP
- Дата
- Дата
- Рейтинг всех уровней
- Рейтинг 1-го уровня
- Древо развёрнутое
- Древо свернутое
Свернуть все
2. nomad_irk 67 12.06.20 09:50 Сейчас в теме
(1)1. Почему вы решили, что так вообще можно делать?
2. Запихивать значения полей в текст запроса — моветон.
4. GennadiyN 12.06.20 10:09 Сейчас в теме
(2) А так нельзя? подскажите как правильно)
5. nomad_irk 67 12.06.20 10:26 Сейчас в теме
(4)
Именно через Command — нельзя, либо циклически выполняйте по одному запросу.
Можно через изменение RecordSet, методом UpdateBatch
10. GennadiyN 12.06.20 14:07 Сейчас в теме
Я с sql на «Вы», можете направление подробное дать, как работать с методом UpdateBatch)
Пытался найти что то по UpdateBatch, пока что то толкого не нашел. UpdateBatch также работает как Command?
12. nomad_irk 67 12.06.20 14:14 Сейчас в теме
6. Xershi 1427 12.06.20 12:27 Сейчас в теме
(1) а какой смысл делать 2 пакета?
Отправь в 1 запросе все или 2 запроса.
У вас разная логика, такую команду нужно 2 запросами делать.
Хотя вон пишут есть другая команда, но это уже учите sql. В таком виде в 1 запросе не работает.
9. GennadiyN 12.06.20 14:05 Сейчас в теме
(6)
Два запроса не производительно, просто потом будет 10 тыс. отправлять)
а как в одном запросе можно это отправить?
13. Xershi 1427 12.06.20 14:16 Сейчас в теме
(9) либо учитесь, либо делайте как правильно (умете). Я не специалист по sql.
7. independ 1473 12.06.20 12:48 Сейчас в теме
(1) может между запросами вставить GO?
11. GennadiyN 12.06.20 14:08 Сейчас в теме
(7) не работает
14. independ 1473 16.06.20 18:49 Сейчас в теме
15. GennadiyN 18.06.20 15:11 Сейчас в теме
(14) Спасибо! Через Вашу ссылку нашел документацию http://www.script-coding.com/ADO.html , которая разъяснила ситуацию)
3. МихаилМ 12.06.20 10:06 Сейчас в теме
используйте UpdateBatch
8. GennadiyN 12.06.20 14:03 Сейчас в теме
Я с sql на «Вы», можете направление подробное дать, как работать с методом UpdateBatch)
Пытался найти что то по UpdateBatch, пока что то толкого не нашел. UpdateBatch также работает как Command?
16. GennadiyN 18.06.20 15:24 Сейчас в теме
Вообщем может кому пригодится:
&НаСервере Процедура ЗагрузитьНаСайтТоварыНаСервере() //Здесь подключение к sql Соединение = СоздатьПодключение(); Команд = Новый COMОбъект("ADODB.Command"); Команд.ActiveConnection = Соединение; // работаем через это соединение Команд.CommandTimeOut = Соединение.CommandTimeOut; // таков тайм-аут Команд.CommandType = "adCmdText"; //сначало делаем запрос в sql //получаем данные из таблиц ТаблицаКатегорий = ПолучитьТаблицуТоваровССайта(Команд); //потом объединяем всю номенклатуру с полученной таблицей и определяем док колонкой какие данные будем добавлять, а какие обновлять ТаблицаКатегорий = СоединитьТовары1С(ТаблицаКатегорий); //собственно в этой процедуре разделяем данные которые будут обновляться а какие добавляться ДобавлениеИОбновлениеНаСайтТовары(Соединение, ТаблицаКатегорий); КонецПроцедуры &НаСервере Процедура ДобавлениеИОбновлениеНаСайтТовары(Соединение, ТЗ) Command = Новый COMОбъект("ADODB.RecordSet"); Command.activeConnection = Соединение; Command.CacheSize = 3000; Command.Open("ps_product",Соединение,3,4,2); //получаем таблицу для обновления sql ОтборUPDATE = Новый Структура("ТипОперации", "UPDATE"); UPDATE = ТЗ.Скопировать(ОтборUPDATE); //здесь удаляем лишние колонки UPDATE = УдалитьКолонки(UPDATE); //собственно процедура обновляет таблицу sql, передаем туда только те колонки которые нужно обновить и которые есть в sql, лишних колонок не должно быть ПроцедураUPDATE(Command, UPDATE, "id_product"); //получаем таблицу для добавления в sql ОтборINS ERT = Новый Структура("ТипОперации", "INS ERT"); INS ERT = ТЗ.Скопировать(ОтборINS ERT); INS ERT.Колонки.Удалить("ТипОперации"); //собственно процедура добавляет дынные в таблицу sql, передаем туда только те колонки которые нужно обновить и которые есть в sql, лишних колонок не должно быть ПроцедураINS ERT(Command, INS ERT); КонецПроцедуры //Процедура Обновления и Добавления данных &НаСервере Процедура ПроцедураUPDATE(Command, Таблица, ИмяПоиска) СчетчикЛ = 0; Счетчик = 0; Пока не Command.EOF Цикл Отбор = Новый Структура(ИмяПоиска, Command.Fields(ИмяПоиска).Value); НайденыйЭлемент = Таблица.НайтиСтроки(Отбор); Если НайденыйЭлемент.Количество()>0 Тогда Для j=0 По Таблица.Колонки.Количество() -1 Цикл Value = НайденыйЭлемент[0][j]; Если ЗначениеЗаполнено(Value) Тогда //Сообщить(""+Таблица.Колонки[j].Имя+" ["+Value+"]"); Если (ТипЗнч(Value) = Тип("Число")) или (ТипЗнч(Value) = Тип("Дата")) тогда Command.Fields(Таблица.Колонки[j].Имя).Value=Value; Иначе // Сообщить(Таблица.Колонки[j].Имя); Попытка Command.Fields(Таблица.Колонки[j].Имя).Value=Строка(Value); Исключение Сообщить(Таблица.Колонки[j].Имя+ " "+Строка(Value)); КонецПопытки; КонецЕсли; КонецЕсли; КонецЦикла; КонецЕсли; Command.MoveNext(); Если СчетчикЛ = 3000 Тогда СчетчикЛ = 0; Command.UpdateBatch(); //4,false); Счетчик = Счетчик + 1; Иначе СчетчикЛ = СчетчикЛ + 1; КонецЕсли; КонецЦикла; КонецПроцедуры &НаСервере Процедура ПроцедураINS ERT(Command, Таблица) СчетчикЛ = 0; Для i=0 По Таблица.Количество() -1 Цикл Command.AddNew(); Для j=0 По Таблица.Колонки.Количество() -1 Цикл Value = ?(Таблица[i][j]= null, 0, Таблица[i][j]); Если Val ue <> Неопределено Тогда //Сообщить(""+Таблица.Колонки[j].Имя+" ["+Val ue+"]"); Если (ТипЗнч(Val ue) = Тип("Число")) или (ТипЗнч(Val ue) = Тип("Дата")) тогда Command.Fields(Таблица.Колонки[j].Имя).Val ue=Value; Иначе // Сообщить(Таблица.Колонки[j].Имя); Попытка Command.Fields(Таблица.Колонки[j].Имя).Val ue=Строка(Val ue); Исключение Сообщить(Таблица.Колонки[j].Имя+ " "+Строка(Val ue)); КонецПопытки; КонецЕсли; КонецЕсли; КонецЦикла; Если СчетчикЛ = 3000 Тогда СчетчикЛ = 0; Command.UpdateBatch(); //4,false); //Счетчик = Счетчик + 1; Иначе СчетчикЛ = СчетчикЛ + 1; КонецЕсли; //Command.update(); КонецЦикла; Попытка Command.UpdateBatch(); Command.Close(); Исключение Сообщить(ОписаниеОшибки()); //Сообщить(NameTable); КонецПопытки; КонецПроцедуры
Как сделать несколько запросов в одном запросе sql
WITH предоставляет способ записывать дополнительные операторы для применения в больших запросах. Эти операторы, которые также называют общими табличными выражениями (Common Table Expressions, CTE ), можно представить как определения временных таблиц, существующих только для одного запроса. Дополнительным оператором в предложении WITH может быть SELECT , INSERT , UPDATE или DELETE , а само предложение WITH присоединяется к основному оператору, которым также может быть SELECT , INSERT , UPDATE или DELETE .
7.8.1. SELECT в WITH
Основное предназначение SELECT в предложении WITH заключается в разбиении сложных запросов на простые части. Например, запрос:
WITH regional_sales AS ( SELECT region, SUM(amount) AS total_sales FROM orders GROUP BY region ), top_regions AS ( SELECT region FROM regional_sales WHERE total_sales > (SELECT SUM(total_sales)/10 FROM regional_sales) ) SELECT region, product, SUM(quantity) AS product_units, SUM(amount) AS product_sales FROM orders WHERE region IN (SELECT region FROM top_regions) GROUP BY region, product;
выводит итоги по продажам только для передовых регионов. Предложение WITH определяет два дополнительных оператора regional_sales и top_regions так, что результат regional_sales используется в top_regions , а результат top_regions используется в основном запросе SELECT . Этот пример можно было бы переписать без WITH , но тогда нам понадобятся два уровня вложенных подзапросов SELECT . Показанным выше способом это можно сделать немного проще.
Необязательное указание RECURSIVE превращает WITH из просто удобной синтаксической конструкции в средство реализации того, что невозможно в стандартном SQL. Используя RECURSIVE , запрос WITH может обращаться к собственному результату. Очень простой пример, суммирующий числа от 1 до 100:
WITH RECURSIVE t(n) AS ( VALUES (1) UNION ALL SELECT n+1 FROM t WHERE n < 100 ) SELECT sum(n) FROM t;
В общем виде рекурсивный запрос WITH всегда записывается как не рекурсивная часть, потом UNION (или UNION ALL ), а затем рекурсивная часть, где только в рекурсивной части можно обратиться к результату запроса. Такой запрос выполняется следующим образом:
Вычисляется не рекурсивная часть. Для UNION (но не UNION ALL ) отбрасываются дублирующиеся строки. Все оставшиеся строки включаются в результат рекурсивного запроса и также помещаются во временную рабочую таблицу.
Вычисляется рекурсивная часть так, что рекурсивная ссылка на сам запрос обращается к текущему содержимому рабочей таблицы. Для UNION (но не UNION ALL ) отбрасываются дублирующиеся строки и строки, дублирующие ранее полученные. Все оставшиеся строки включаются в результат рекурсивного запроса и также помещаются во временную промежуточную таблицу.
Примечание
Строго говоря, этот процесс является итерационным, а не рекурсивным, но комитетом по стандартам SQL был выбран термин RECURSIVE .
В показанном выше примере в рабочей таблице на каждом этапе содержится всего одна строка и в ней последовательно накапливаются значения от 1 до 100. На сотом шаге, благодаря условию WHERE , не возвращается ничего, так что вычисление запроса завершается.
Рекурсивные запросы обычно применяются для работы с иерархическими или древовидными структурами данных. В качестве полезного примера можно привести запрос, находящий все непосредственные и косвенные составные части продукта, используя только таблицу с прямыми связями:
WITH RECURSIVE included_parts(sub_part, part, quantity) AS ( SELECT sub_part, part, quantity FROM parts WHERE part = 'our_product' UNION ALL SELECT p.sub_part, p.part, p.quantity FROM included_parts pr, parts p WHERE p.part = pr.sub_part ) SELECT sub_part, SUM(quantity) as total_quantity FROM included_parts GROUP BY sub_part
Работая с рекурсивными запросами, важно обеспечить, чтобы рекурсивная часть запроса в конце концов не выдала никаких кортежей (строк), в противном случае цикл будет бесконечным. Иногда для этого достаточно применять UNION вместо UNION ALL , так как при этом будут отбрасываться строки, которые уже есть в результате. Однако часто в цикле выдаются строки, не совпадающие полностью с предыдущими: в таких случаях может иметь смысл проверить одно или несколько полей, чтобы определить, не была ли текущая точка достигнута раньше. Стандартный способ решения подобных задач — вычислить массив с уже обработанными значениями. Например, рассмотрите следующий запрос, просматривающий таблицу graph по полю link :
WITH RECURSIVE search_graph(id, link, data, depth) AS ( SELECT g.id, g.link, g.data, 1 FROM graph g UNION ALL SELECT g.id, g.link, g.data, sg.depth + 1 FROM graph g, search_graph sg WHERE g.id = sg.link ) SELECT * FROM search_graph;
Этот запрос зациклится, если связи link содержат циклы. Так как нам нужно получать в результате « depth » , одно лишь изменение UNION ALL на UNION не позволит избежать зацикливания. Вместо этого мы должны как-то определить, что уже достигали текущей строки, пройдя некоторый путь. Для этого мы добавляем два столбца path и cycle и получаем запрос, защищённый от зацикливания:
WITH RECURSIVE search_graph(id, link, data, depth, path, cycle) AS ( SELECT g.id, g.link, g.data, 1, ARRAY[g.id], false FROM graph g UNION ALL SELECT g.id, g.link, g.data, sg.depth + 1, path || g.id, g.id = ANY(path) FROM graph g, search_graph sg WHERE g.id = sg.link AND NOT cycle ) SELECT * FROM search_graph;
Помимо предотвращения циклов, значения массива часто бывают полезны сами по себе для представления « пути » , приведшего к определённой строке.
В общем случае, когда для выявления цикла нужно проверять несколько полей, следует использовать массив строк. Например, если нужно сравнить поля f1 и f2 :
WITH RECURSIVE search_graph(id, link, data, depth, path, cycle) AS ( SELECT g.id, g.link, g.data, 1, ARRAY[ROW(g.f1, g.f2)], false FROM graph g UNION ALL SELECT g.id, g.link, g.data, sg.depth + 1, path || ROW(g.f1, g.f2), ROW(g.f1, g.f2) = ANY(path) FROM graph g, search_graph sg WHERE g.id = sg.link AND NOT cycle ) SELECT * FROM search_graph;
Подсказка
Часто для распознавания цикла достаточного одного поля и тогда ROW() можно опустить. При этом будет использоваться не массив данных составного типа, а простой массив, что более эффективно.
Подсказка
Этот алгоритм рекурсивного вычисления запроса выдаёт в результате узлы, упорядоченные по пути погружения. Чтобы получить результаты, отсортированные по глубине, можно добавить во внешний запрос ORDER BY по столбцу « path » , полученному, как показано выше.
Для тестирования запросов, которые могут зацикливаться, есть хороший приём — добавить LIMIT в родительский запрос. Например, следующий запрос зациклится, если не добавить предложение LIMIT :
WITH RECURSIVE t(n) AS ( SELECT 1 UNION ALL SELECT n+1 FROM t ) SELECT n FROM t LIMIT 100;
Но в данном случае этого не происходит, так как в PostgreSQL запрос WITH выдаёт столько строк, сколько фактически принимает родительский запрос. В производственной среде использовать этот приём не рекомендуется, так как другие системы могут вести себя по-другому. Кроме того, это не будет работать, если внешний запрос сортирует результаты рекурсивного запроса или соединяет их с другой таблицей, так как в подобных случаях внешний запрос обычно всё равно выбирает результат запроса WITH полностью.
Запросы WITH имеют полезное свойство — они вычисляются только раз для всего родительского запроса, даже если этот запрос или соседние запросы WITH обращаются к ним неоднократно. Таким образом, сложные вычисления, результаты которых нужны в нескольких местах, можно выносить в запросы WITH в целях оптимизации. Кроме того, такие запросы позволяют избежать нежелательных вычислений функций с побочными эффектами. Однако есть и обратная сторона — оптимизатор не может распространить ограничения родительского запроса на запрос WITH так, как он делает это для обычного подзапроса. Запрос WITH обычно выполняется буквально и возвращает все строки, включая те, что потом может отбросить родительский запрос. (Но как было сказано выше, вычисление может остановиться раньше, если в ссылке на этот запрос затребуется только ограниченное число строк.)
Примеры выше показывают только предложение WITH с SELECT , но таким же образом его можно использовать с командами INSERT , UPDATE и DELETE . В каждом случае он по сути создаёт временную таблицу, к которой можно обратиться в основной команде.
7.8.2. Изменение данных в WITH
В предложении WITH можно также использовать операторы, изменяющие данные ( INSERT , UPDATE или DELETE ). Это позволяет выполнять в одном запросе сразу несколько разных операций. Например:
WITH moved_rows AS ( DELETE FROM products WHERE "date" >= '2010-10-01' AND "date" < '2010-11-01' RETURNING * ) INSERT INTO products_log SELECT * FROM moved_rows;
Этот запрос фактически перемещает строки из products в products_log . Оператор DELETE в WITH удаляет указанные строки из products и возвращает их содержимое в предложении RETURNING ; а затем главный запрос читает это содержимое и вставляет в таблицу products_log .
Следует заметить, что предложение WITH в данном случае присоединяется к оператору INSERT , а не к SELECT , вложенному в INSERT . Это необходимо, так как WITH может содержать операторы, изменяющие данные, только на верхнем уровне запроса. Однако при этом применяются обычные правила видимости WITH , так что к результату WITH можно обратиться и из вложенного оператора SELECT .
Операторы, изменяющие данные, в WITH обычно дополняются предложением RETURNING (см. Раздел 6.4), как показано в этом примере. Важно понимать, что временная таблица, которую можно будет использовать в остальном запросе, создаётся из результата RETURNING , а не целевой таблицы оператора. Если оператор, изменяющий данные, в WITH не дополнен предложением RETURNING , временная таблица не создаётся и обращаться к ней в остальном запросе нельзя. Однако такой запрос всё равно будет выполнен. Например, допустим следующий не очень практичный запрос:
WITH t AS ( DELETE FROM foo ) DELETE FROM bar;
Он удалит все строки из таблиц foo и bar . При этом число задействованных строк, которое получит клиент, будет подсчитываться только по строкам, удалённым из bar .
Рекурсивные ссылки в операторах, изменяющих данные, не допускаются. В некоторых случаях это ограничение можно обойти, обратившись к конечному результату рекурсивного WITH , например так:
WITH RECURSIVE included_parts(sub_part, part) AS ( SELECT sub_part, part FROM parts WHERE part = 'our_product' UNION ALL SELECT p.sub_part, p.part FROM included_parts pr, parts p WHERE p.part = pr.sub_part ) DELETE FROM parts WHERE part IN (SELECT part FROM included_parts);
Этот запрос удаляет все непосредственные и косвенные составные части продукта.
Операторы, изменяющие данные в WITH , выполняются только один раз и всегда полностью, вне зависимости от того, принимает ли их результат основной запрос. Заметьте, что это отличается от поведения SELECT в WITH : как говорилось в предыдущем разделе, SELECT выполняется только до тех пор, пока его результаты востребованы основным запросом.
Вложенные операторы в WITH выполняются одновременно друг с другом и с основным запросом. Таким образом, порядок, в котором операторы в WITH будут фактически изменять данные, непредсказуем. Все эти операторы выполняются с одним снимком данных (см. Главу 13), так что они не могут « видеть » , как каждый из них меняет целевые таблицы. Это уменьшает эффект непредсказуемости фактического порядка изменения строк и означает, что RETURNING — единственный вариант передачи изменений от вложенных операторов WITH основному запросу. Например, в данном случае:
WITH t AS ( UPDATE products SET price = price * 1.05 RETURNING * ) SELECT * FROM products;
внешний оператор SELECT выдаст цены, которые были до действия UPDATE , тогда как в запросе
WITH t AS ( UPDATE products SET price = price * 1.05 RETURNING * ) SELECT * FROM t;
внешний SELECT выдаст изменённые данные.
Неоднократное изменение одной и той же строки в рамках одного оператора не поддерживается. Иметь место будет только одно из нескольких изменений и надёжно определить, какое именно, часто довольно сложно (а иногда и вовсе невозможно). Это так же касается случая, когда строка удаляется и изменяется в том же операторе: в результате может быть выполнено только обновление. Поэтому в общем случае следует избегать подобного наложения операций. В частности, избегайте подзапросов WITH , которые могут повлиять на строки, изменяемые основным оператором или операторами, вложенные в него. Результат действия таких запросов будет непредсказуемым.
В настоящее время, для оператора, изменяющего данные в WITH , в качестве целевой нельзя использовать таблицу, для которой определено условное правило или правило ALSO или INSTEAD , если оно состоит из нескольких операторов.
| Пред. | Наверх | След. |
| 7.7. Списки VALUES | Начало | Глава 8. Типы данных |
