Возможный реализовать ручной инкремент только с простым SQL ВСТАВЛЯЮТ?

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

document.addEventListener('wheel', doStg, false)
let isExecuting = false;
let numb = 0

function doStg() {
    if(isExecuting) return; // exit if there is already executing something

    isExecuting = true; // prevent next call
    console.log(numb++)
    // do something
    isExecuting = false; // enable for next
}
6
задан cdeszaq 27 April 2009 в 18:26
поделиться

7 ответов

Вы понимаете, что у вас будут правильные коллизии?

вам нужно сделать что-то подобное, и это может привести к тупикам, так что будьте очень уверены, что вы пытаетесь сделать здесь

DECLARE @id int
BEGIN TRAN

    SELECT @id = MAX(id) + 1 FROM Table1 WITH (UPDLOCK, HOLDLOCK)
    INSERT INTO Table1(id, data_field)
    VALUES (@id ,'[blob of data]')
COMMIT TRAN

Объяснить Что касается коллизий, я предоставил некоторый код

, сначала создайте эту таблицу и вставьте одну строку

CREATE TABLE Table1(id int primary key not null, data_field char(100))
GO
Insert Table1 values(1,'[blob of data]')
Go

Теперь откройте два окна запроса и запустите это одновременно

declare @i int
set @i =1
while @i < 10000
begin
BEGIN TRAN

INSERT INTO Table1(id, data_field)
SELECT MAX(id) + 1, '[blob of data]' FROM Table1

COMMIT TRAN;
set @i =@i + 1
end

Вы увидите кучу этих

Серверов : Сообщение 2627, уровень 14, состояние 1, строка 7 Нарушение ограничения PRIMARY KEY 'PK__Table1__3213E83F2962141D'. Невозможно вставить дубликат ключа в объект 'dbo.Table1'. Заявление было прекращено.

10
ответ дан 8 December 2019 в 17:27
поделиться

Попробуйте вместо этого:

INSERT INTO Table1 (id, data_field)
SELECT id, '[blob of data]' FROM (SELECT MAX(id) + 1 as id FROM Table1) tbl

Я бы не рекомендовал делать это таким образом по ряду причин (производительность, безопасность транзакций и т. Д.)

2
ответ дан 8 December 2019 в 17:27
поделиться

Это может быть из-за отсутствия записей, поэтому подзапрос возвращает NULL ... try

INSERT INTO tblTest(RecordID, Text) 
VALUES ((SELECT ISNULL(MAX(RecordID), 0) + 1 FROM tblTest), 'asdf')
1
ответ дан 8 December 2019 в 17:27
поделиться

Если вы делаете это в триггере, вы можете убедиться, что это триггер «INSTEAD OF», и сделать это в паре операторов:

DECLARE @next INT
SET @next = (SELECT (MAX(id) + 1) FROM Table1)

INSERT INTO Table1
VALUES (@next, inserted.datablob)

Единственное, что у вас будет быть осторожным с параллелизмом - если две строки вставляются одновременно, они могут попытаться использовать одно и то же значение для @next, что приведет к конфликту.

Достигает ли это того, чего вы хотите?

0
ответ дан 8 December 2019 в 17:27
поделиться

Кажется очень странным делать подобные вещи без столбца IDENTITY (автоинкремент), что заставляет меня подвергать сомнению саму архитектуру. Я имею в виду, серьезно, это идеальная ситуация для столбца IDENTITY. Это может помочь нам ответить на ваш вопрос, если вы объясните причину этого решения. =)

Сказав это, некоторые варианты:

  • использование триггера INSTEAD OF для этой цели. Итак, вы бы сделали INSERT (оператор INSERT не должен был бы передавать ID). Код триггера будет обрабатывать вставку соответствующего идентификатора. Вам нужно будет использовать синтаксис WITH (UPDLOCK, HOLDLOCK), используемый другим ответчиком, чтобы удерживать блокировку на время триггера (который неявно переносится в транзакции) и повышать тип блокировки с «общего» до «обновления» Блокировка (IIRC).
  • Вы можете использовать идею выше, но иметь таблицу, цель которой - сохранить последнее, максимальное значение, вставленное в таблицу. Таким образом, после настройки таблицы вам больше не придется каждый раз выполнять SELECT MAX (ID). Вы бы просто увеличили значение в таблице. Это безопасно при условии, что вы используете соответствующую блокировку (как обсуждалось). Опять же, это позволяет избежать повторного сканирования таблицы каждый раз, когда вы ВСТАВЛЯЕТЕ.
  • вместо идентификаторов используют GUID. Гораздо проще объединять таблицы между базами данных, поскольку идентификаторы GUID всегда будут уникальными (тогда как записи в базах данных будут иметь конфликтующие целочисленные идентификаторы). Чтобы избежать разбиения страницы, можно использовать последовательные идентификаторы GUID. Это полезно только в том случае, если вам может потребоваться объединить базу данных.
  • Вместо хранимого триггера используйте хранимый процесс (поскольку по какой-то причине следует избегать триггеров). Вы' У меня все еще есть проблемы с блокировкой (и проблемы с производительностью, которые могут возникнуть). Но sprocs предпочтительнее, чем динамический SQL (в контексте приложений), и зачастую они гораздо более производительны.

Извините за бессмысленность. Надеюсь, это поможет.

0
ответ дан 8 December 2019 в 17:27
поделиться
declare @nextId int
set @nextId = (select MAX(id)+1 from Table1)

insert into Table1(id, data_field) values (@nextId, '[blob of data]')

commit;

Но, возможно, лучшим подходом будет использование скаляра функция getNextId ('table1')

0
ответ дан 8 December 2019 в 17:27
поделиться

Это должно работать:

INSERT INTO Table1 (id, data_field)
SELECT (SELECT (MAX(id) + 1) FROM Table1), '[blob of data]';

Или вот это (заменить LIMIT для других платформ):

INSERT INTO Table1 (id, data_field)
SELECT TOP 1
    MAX(id) + 1, '[blob of data]'
FROM
   Table1
ORDER BY
   [id] DESC;
-1
ответ дан 8 December 2019 в 17:27
поделиться
Другие вопросы по тегам:

Похожие вопросы: