Topic: Максимальный id

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

2 (edited by sparrow 2022-01-07 22:05:49)

Re: Максимальный id

Добрый,

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

SELECT * FROM SQLITE_SEQUENCE

Если таблиц в базе несколько, вытянете по имени таблицы нужное.


ну или конкретно

SELECT * FROM SQLITE_SEQUENCE WHERE name = '<table>';

Кроме того вы всегда можете получить ид последней операции записи.

3 (edited by sibprogsistem 2022-01-08 08:54:06)

Re: Максимальный id

sparrow wrote:
SELECT * FROM SQLITE_SEQUENCE WHERE name = '<table>';

спасибо, но без упоминания поля хранимого инкремент значение не выводит а только возвращает имя таблицы

так работает:

SQLExecute('SELECT seq FROM SQLITE_SEQUENCE WHERE name="a"');

Re: Максимальный id

SQLExecute возвращает только одно значение запроса, поэтому только имя таблицы.

Вы можете использовать SQLQuery с выводом через Results (var TDataSet)

Re: Максимальный id

sibprogsistem wrote:

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

Чисто из любопытства: зачем нужен id перед добавлением записи? Замечу, что для многопользовательских БД это может привести к ошибке из-за попытки добавления двух записей с одинаковыми ID.

Визуальное программирование: блог и телеграм-канал.

Re: Максимальный id

k245 wrote:

Чисто из любопытства: зачем нужен id перед добавлением записи? Замечу, что для многопользовательских БД это может привести к ошибке из-за попытки добавления двух записей с одинаковыми ID.

мне нужен был счетчик для того, что бы номер договора ни когда не повторялся, обычный счетчик (который есть по умолчанию) не подходит так как он может начаться заново если удалить записи.. будет странно если на руках будут разные договора с одинаковыми номерами..

Re: Максимальный id

sibprogsistem wrote:

мне нужен был счетчик для того, что бы номер договора ни когда не повторялся, обычный счетчик (который есть по умолчанию) не подходит так как он может начаться заново если удалить записи.. будет странно если на руках будут разные договора с одинаковыми номерами..

Повторюсь, что если система многопользовательская, то велика вероятность одновременного создания документов с одинаковым номером.


В этом случае нужна хранимая процедура, которая определяет нужный номер и прописывает его в базу в рамках одной транзакции.
Одним запросом это сделать не получится, так как MySQL не разрешает делать в одной команде обновление таблицы, из которой идет чтение данных.


Вот пример процедуры, которая создает уникальные номера (DocNum) в рамках одного календарного года (RegDate - дата документа) для каждого типа документа (id_folder)


CREATE PROCEDURE `updnum`( IN AIDdoc int )
BEGIN
  DECLARE tmpNextNumber INT;
  DECLARE tmpIDFolder;
  DECLARE tmpDate DATE;
  SELECT RegDate INTO tmpDate FROM doc WHERE id = AIDdoc;
  SELECT id_folder INTO tmpIDFolder FROM doc WHERE id = AIDdoc;
  SELECT coalesce( res.NNum, 1 ) INTO tmpNextNumber 
    FROM ( SELECT max(rd.DocNum)+1 as NNum FROM doc rd WHERE rd.id_Folder = tmpIDFolder AND YEAR( rd.RegDate ) = YEAR( tmpDate ) ) res;
  UPDATE doc SET DocNum = tmpNextNumber WHERE id = AIDdoc;
END

Вызывать её нужно после сохранения записи в базу:

procedure frmDocEdit_rbtOK_OnAfterClick(Sender: TObject);
var
  tmpID: string;
begin
  tmpID := IntToStr(frmDocEdit.rbtOK.dbGeneralTableId);
  SQLExecute( 'call updnum('+tmpID+') ' );
end;
Визуальное программирование: блог и телеграм-канал.

Re: Максимальный id

k245 wrote:
sibprogsistem wrote:

мне нужен был счетчик для того, что бы номер договора ни когда не повторялся, обычный счетчик (который есть по умолчанию) не подходит так как он может начаться заново если удалить записи.. будет странно если на руках будут разные договора с одинаковыми номерами..

Повторюсь, что если система многопользовательская, то велика вероятность одновременного создания документов с одинаковым номером.


В этом случае нужна хранимая процедура, которая определяет нужный номер и прописывает его в базу в рамках одной транзакции.
Одним запросом это сделать не получится, так как MySQL не разрешает делать в одной команде обновление таблицы, из которой идет чтение данных.


Вот пример процедуры, которая создает уникальные номера (DocNum) в рамках одного календарного года (RegDate - дата документа) для каждого типа документа (id_folder)


CREATE PROCEDURE `updnum`( IN AIDdoc int )
BEGIN
  DECLARE tmpNextNumber INT;
  DECLARE tmpIDFolder;
  DECLARE tmpDate DATE;
  SELECT RegDate INTO tmpDate FROM doc WHERE id = AIDdoc;
  SELECT id_folder INTO tmpIDFolder FROM doc WHERE id = AIDdoc;
  SELECT coalesce( res.NNum, 1 ) INTO tmpNextNumber 
    FROM ( SELECT max(rd.DocNum)+1 as NNum FROM doc rd WHERE rd.id_Folder = tmpIDFolder AND YEAR( rd.RegDate ) = YEAR( tmpDate ) ) res;
  UPDATE doc SET DocNum = tmpNextNumber WHERE id = AIDdoc;
END

Вызывать её нужно после сохранения записи в базу:

procedure frmDocEdit_rbtOK_OnAfterClick(Sender: TObject);
var
  tmpID: string;
begin
  tmpID := IntToStr(frmDocEdit.rbtOK.dbGeneralTableId);
  SQLExecute( 'call updnum('+tmpID+') ' );
end;

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

9 (edited by sparrow 2022-01-16 14:03:23)

Re: Максимальный id

k245 wrote:

Одним запросом это сделать не получится, так как MySQL не разрешает делать в одной команде обновление таблицы, из которой идет чтение данных.

Не свосем так. Можно решить через 1. вложеный подзапрос или 2.так называемую табличную форму. Такие решения приводят к созданию временной таблицы из которой проводится чтение и обновление основной.

Re: Максимальный id

sparrow wrote:
k245 wrote:

Одним запросом это сделать не получится, так как MySQL не разрешает делать в одной команде обновление таблицы, из которой идет чтение данных.

Не свосем так. Можно решить через 1. вложеный подзапрос или 2.так называемую табличную форму. Такие решения приводят к созданию временной таблицы из которой проводится чтение и обновление основной.

Очень любопытно. Буду признателен за пример.

Визуальное программирование: блог и телеграм-канал.

Re: Максимальный id

Если позволите я дам ссылку, чтоб не умничать
Решение как для UPDATE так и для DELETE.

https://sqlinfo.ru/articles/info/19.html

Вторая часть статьи тоже интересна.

12 (edited by k245 2022-01-17 12:27:28)

Re: Максимальный id

sparrow wrote:

Если позволите я дам ссылку, чтоб не умничать
Решение как для UPDATE так и для DELETE.

https://sqlinfo.ru/articles/info/19.html

Вторая часть статьи тоже интересна.

Спасибо, статья интересная. Для случая, если подзапрос находится в секции SET,  подходит метод оборачивания SELECT в другой SELECT.


Вот пример присвоения следующего номера для документа с ID=3

UPDATE doc SET DocNum = ( select * from ( select coalesce(max(rd.DocNum)+1,1) from doc rd  ) as t1 ) WHERE id = 3
Визуальное программирование: блог и телеграм-канал.