12 июня 2023

Сколько строк обработал оператор DML?

    После выполнения оператора DML модифицирующего данные иногда бывает необходимо узнать, сколько строк им было обработано. Это может быть полезно, например для определения успешности выполнения оператора или для ведения журнала операций. Каждая СУБД реализует такую функциональную возможность по-своему.

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

CREATE TABLE xyz
(
  id   INT PRIMARY KEY, 
  name VARCHAR(255)
);

CREATE TABLE xyz_copy
(
  id   INT PRIMARY KEY, 
  name VARCHAR(255)
);

INSERT INTO xyz(id, name) VALUES (1, 'Borland');
INSERT INTO xyz(id, name) VALUES (2, 'CodeGear');
INSERT INTO xyz(id, name) VALUES (3, 'Embarcadero Technologies');

    У MS SQL Server для определения количества строк, обработанных последней DML-командой, есть специальные системные функции: @@ROWCOUNT (возвращает int) и ROWCOUNT_BIG (возвращает bigint и применяется, если число строк превышает 2 миллиарда).

Функции @@ROWCOUNT и ROWCOUNT_BIG у MS SQL Server

    У Oracle количество строк, обработанных последней DML-командой, хранится в атрибуте ее курсора SQL%ROWCOUNT (для каждой DML-команды СУБД автоматически открывает неявный курсор (implicit cursor)).

Атрибут курсора SQL%ROWCOUNT у Oracle

    У PostgreSQL данный функционал реализован, как мне кажется, немного неудобно. Необходимо воспользоваться командой GET DIAGNOSTICS:

GET [CURRENT | STACKED] DIAGNOSTICS переменная { = | := } элемент [ , ... ];
Эта команда позволяет получить в переменную системные индикаторы состояния выполнения кода. Модификаторы CURRENT и STACKED определяют интересующий программиста момент выполнения: CURRENT указывает на текущее состояние, а STACKED на состояние в момент последней ошибки и используется для получения детальной информации об ошибке при обработке исключений. Для нашей задачи необходим CURRENT. У него, в отличие от STACKED, всего два варианта элементов:
  1. PG_CONTEXT – описание текущего стек вызовов в текстовом виде (возвращает text).
  2. ROW_COUNT – число строк, обработанных последней командой SQL (возвращает bigint).
Так как модификатор CURRENT используется по умолчанию, то его можно не указывать.
GET DIAGNOSTICS ROW_COUNT у PostgreSQL
Я написал о реализации с использованием GET DIAGNOSTICS "немного неудобно", т.к. эта команда работает только внутри процедуры/функции или анонимного блока кода, и для ее вызова обязательно необходимо объявить переменную. У PostgreSQL существует еще один способ решения нашей задачи. Воспользуемся тем, что, дополнив команды INSERT, UPDATE и DELETE параметром RETURNING, можно получить обработанные ими строки. Обернем копирование в CTE (Common Table Expressions, Обобщенные табличные выражения) и посчитаем количество возвращаемых RETURNING строк.
ROW_COUNT у PostgreSQL используя CTE

    У MySQL и MariaDB количество строк, обработанных последней DML-командой, возвращает одна из информационных функций – ROW_COUNT().

Функция ROW_COUNT у PostgreSQL
Но у MySQL и MariaDB, как и у PostgreSQL, есть команда GET DIAGNOSTICS. Она позволяет получить доступ к области диагностики, которая заполняется при выполнении любого SQL-оператора и содержит информацию о его выполнении: SQLSTATE, код и сообщение об ошибках, предупреждения... и интересующее нас количество строк. Элемент области диагностики ROW_COUNT имеет то же самое значение, как и функция ROW_COUNT.
GET DIAGNOSTICS ROW_COUNT у MySQL и MariaDB

    У каждой СУБД свой способ получения количества строк, обработанных последней DML-командой. Общее только одно – они работают в рамках текущей сессии. Мне кажется, что хуже всего с этой задачей справились авторы PostgreSQL. Они скопировали множество функционала других СУБД, но поленились позаимствовать у MySQL вместе с GET DIAGNOSTICS функцию ROW_COUNT. Возможно, такая обертка над GET DIAGNOSTICS с ROW_COUNT им показалась синтаксическим сахаром.

Комментариев нет:

Отправить комментарий