![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
SCOPE_IDENTITY() не всегда корректно выполняется [D7, MSSQL]
Serg2103 © (2006-02-01 18:11:00)MS SQL 2005.
Существует программа, которая добавляет в главную таблицу данные. Затем вызывает функцию SCOPE_IDENTITY(), узнает ID только что добавленной строки, затем в другую таблицу добавляет данные, уже привязанные к этому ID.
Вроде все просто и стандартно. Так вот.
Копий этой программы работает одновременно много. И соответственно добавления данных происходить могут одновременно.
Вообщем, стал замечать, что порой (не всегда) функция SCOPE_IDENITY() определяет ID не той строки, которая была добавлена в текущей программе, а какой-то другой, и, соответственно, данные начинают привязыватся не к той строке.
Я чего-то не понимаю? Ведь вроде SCOPE_IDENTITY() должно работать только в пределах текущей сессии, т.е. насколько я могу понять - в пределах текущего подключения. Почему-то это не всегда срабатывает. Подскажите, пожалуйста, в чем может юыть проблема?
Shirson (2006-02-03 13:57:00) [1]Из года в год тема SCOPE_IDENTITY() и @@IDENTITY поднимается с завидной постоянностью и мигрирует из темы в тему. Почему перед использованием той или иной методы вопрошающие не сомотрят в T_SQL Help, который можно вызвать из меню Query Analiser, совершенно загадочно.
Serg2103, для отлова последнего вставленного identity в таблицу, как верно заметили, следует смотреть SCOPE_IDENTITY() в том же запросе, в котором и производится insert. В идеале, на сервере создаётся SP, в которую передаются параметры для insert, а результатом возвращается identity. В случае динамического формирования запроса, его тоже можно передавать в SP и получать identity, а если не хочется извращаться, то делать как в [17].
Если же вам необходимо получать последний identity, который был вставлен в конкретную таблицу, незваисимо от того, кем и когда это было сделанно, стоит обратить внимание на IDENT_CURRENT.
P.S. И еще, Serg2103, мой вам совет. Потрате немного времени на хелп по T_SQL и постигните Дзен такой прекрасной вещи какADOQuery.Parameters.ParamValues. Тогда такие ужасы и катастрофы какAnsiReplaceText(Format('INSERT INTO %s...навсегда уйдут из вашей жизни :)
Nikolay M. (2006-02-02 14:56:00) [2]
> msguns © (02.02.06 13:52) [27]
Я этого... буду заниматься тем, чем сочту нужным. Хоть профессоров в дураках оставлять, хоть наоборот...
msguns (2006-02-02 13:52:00) [3]>Nikolay M. ©
Ты, Коля, эта.. не спорь с профессором. Все равно в дурнях оставит, вот увидишь ;))
Nikolay M. (2006-02-02 13:18:00) [4]
> sniknik © (02.02.06 12:23) [25]
> вериш, уже устал это пояснять и чтото доказывать. может
> хоть ктото просто поверить на слово? или сделать поиск раз
> уж "буду рад узнать что-то новое" (в дайджестах например),
> или посмотреть в исходники ADODB сам?
Верю, что устал, потому что постоянно наблюдаю твою нелюбовь к ADOQuery и прочим производным :)
Честно говоря, разбираться в вопросе пока не было времени, потому что всегда пользуюсь ADOCommand и ADODataSet.
sniknik (2006-02-02 12:23:00) [5]> Если скажешь, чем ADOQuery в данном случае "лучше" ADODataSet, буду рад узнать что-то новое.
вериш, уже устал это пояснять и чтото доказывать. может хоть ктото просто поверить на слово? или сделать поиск раз уж "буду рад узнать что-то новое" (в дайджестах например), или посмотреть в исходники ADODB сам?
> Зато у тебя нет SET NOCOUNT ON
DataSet сам пропустит "пустышки" передваряющие наполненный рекордсет. особого смысла здесь в нем нет.
Nikolay M. (2006-02-02 12:16:00) [6]
> sniknik © (02.02.06 11:34) [22]
> нет, самое правильное это [4] т.к. это тоже самое но основано
> на " более правильном" компаненте
КомпАнент здесь - дело десятое. Если скажешь, чем ADOQuery в данном случае "лучше" ADODataSet, буду рад узнать что-то новое.
Зато у тебя нет SET NOCOUNT ON, а в [17] он есть, и это более правильно, чем когда его нет, но компАнент "правильный" :)
Fay (2006-02-02 11:37:00) [7]2 sniknik © (02.02.06 11:34) [22]
Ой, я и не заметил [4]...
А что все тогда обсуждают? 8)
sniknik (2006-02-02 11:34:00) [8]нет, самое правильное это [4] т.к. это тоже самое но основано на " более правильном" компаненте.
Nikolay M. (2006-02-02 11:26:00) [9]
> SCOPE_IDENTITY() и @@IDENTITY возвращают разные значения
> (в общем случае).
Конечно. Если есть тригеры. Если их нет, то сойдет.
Но самое правильное, конечно - это [17].
Fay (2006-02-02 11:14:00) [10]2 Nikolay M. © (02.02.06 11:10) [19]
Такая замена не совсем корректна. SCOPE_IDENTITY() и @@IDENTITY возвращают разные значения (в общем случае).
Nikolay M. (2006-02-02 11:10:00) [11]
> SCOPE_IDENTITY()
Замени на @@IDENTITY
ЮЮ (2006-02-02 11:09:00) [12]Ну и что мешает SELECT SCOPE_IDENTITY добавить в тот же пакет, где производится INSERT? Почему предпочитаешь отдельно?
Fay (2006-02-02 11:08:00) [13]2 Serg2103 (01.02.06 22:28) [3]
Никаких ExecSQL. Просто Open для
set nocount on
insert....
select SCOPE_IDENTITY() as NewsID
Serg2103 (2006-02-02 11:04:00) [14]
> Во-первых, хотелось бы увидеть полный текст инсерта и "нейтральные
> строчки". А, во-вторых, чему равно ADOConnection.KeepConnection?
>
Такой вот код:
Query3.SQL.Text:=Trim(AnsiReplaceText(Format('INSERT INTO %s.dbo.News (SiteID, ClippingID, NewsTitle, NewsCreateDate, NewsTrueCreateDate, NewsFindDate, NewsURL) VALUES (''%s'', ''%s'', ''%s'', ''%s'', ''%s'', ''%s'', ''%s'')', [Base+TableDatePrist(CurNews.NewsDate), Mainform.SiteID, CurClippingID, Kav(CurNews.NewsTitle), CurNews.NewsDate, TrueNewsDate, CurNews.NewsFindDate, CurURL]), #13#10, ' '));
Query3.ExecSQL;
Query3.SQL.Text:='SELECT SCOPE_IDENTITY() as NewsID';
Query3.Open;
MonthNewsID:=Query3.FieldByName('NewsID').AsString;
Объяснять, что вставляется - думаю не принципиально. INSERT корректный.
На самом деле, вчера, когда писал, кода под рукой не было - потому и не выложил. Сейчас вижу, что между двумя запросами - "нейтрального" кода нет.
KeepConnection у TADOConnection включен.
Nikolay M. (2006-02-02 10:24:00) [15]
> Fay © (02.02.06 10:21) [13]
Я не настолько жесток, чтобы отнимать у человека надежду.
> Могу ли я надеяться
Да! Конечно.
> ТЫ когда-нибудь сможешь простить меня?
НЕТ!
:-)))
Fay (2006-02-02 10:22:00) [16]2 ЮЮ © (02.02.06 10:21) [12]
Совершенно верно
Fay (2006-02-02 10:21:00) [17]2 Nikolay M. © (02.02.06 10:14) [10]
> А зачем ты говоришь это МНЕ?
Могу ли я надеяться, что ТЫ когда-нибудь сможешь простить меня?
ЮЮ (2006-02-02 10:21:00) [18]Thus, two statements are in the same scope if they are in the same stored procedure, function, or batch.
По-моему, SCOPE_IDENTITY здесь неуместно
msguns (2006-02-02 10:16:00) [19]>Ega23 © (02.02.06 09:49) [8]
>Я бы на твоём месте сделал всё это дело в рамках одной хранимой процедуры.
А я еще и переставил бы местами запросы: сначала делал бы холостую вставку, определение ID, удаление. После чего вставлял бы мастер-запись с уже известным ID, которое бы и возвращал "клиенту" для добавления в детал или куда там надо (или для перепозиционирования отображаемого НД)
Nikolay M. (2006-02-02 10:14:00) [20]
> Fay © (02.02.06 09:26) [6]
> 2 Nikolay M. © (01.02.06 18:46) [2]
> > Надеюсь, ты это в рамках одной транзакции делаешь?
> А какая разница?
А зачем ты говоришь это МНЕ?
> Query1.SQL.Text:= 'INSERT ...';
> Query1.ExecSQL;
> Строчка нейтрального кода
> Строчка нейтрального кода
> Строчка нейтрального кода
> Строчка нейтрального кода
> Query1.SQL.Text:='SELECT SCOPE_IDENTITY() AS GUID';
> Query1.Open;
> GUID:=Query1.FieldByName('GUID').AsString;
Во-первых, хотелось бы увидеть полный текст инсерта и "нейтральные строчки". А, во-вторых, чему равно ADOConnection.KeepConnection?