Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2006.03.26;
Скачать: CL | DM;

Вниз

SCOPE_IDENTITY() не всегда корректно выполняется   Найти похожие ветки 

 
Serg2103   (2006-02-01 18:11) [0]

MS SQL 2005.
Существует программа, которая добавляет в главную таблицу данные. Затем вызывает функцию SCOPE_IDENTITY(), узнает ID только что добавленной строки, затем в другую таблицу добавляет данные, уже привязанные к этому ID.
Вроде все просто и стандартно. Так вот.
Копий этой программы работает одновременно много. И соответственно добавления данных происходить могут одновременно.
Вообщем, стал замечать, что порой (не всегда) функция SCOPE_IDENITY() определяет ID не той строки, которая была добавлена в текущей программе, а какой-то другой, и, соответственно, данные начинают привязыватся не к той строке.
Я чего-то не понимаю? Ведь вроде SCOPE_IDENTITY() должно работать только в пределах текущей сессии, т.е. насколько я могу понять - в пределах текущего подключения. Почему-то это не всегда срабатывает. Подскажите, пожалуйста, в чем может юыть проблема?


 
Ega23 ©   (2006-02-01 18:32) [1]


> то порой (не всегда) функция SCOPE_IDENITY() определяет
> ID не той строки, которая была добавлена в текущей программе,
>  а какой-то другой, и, соответственно, данные начинают привязыватся
> не к той строке.


Надеюсь, ты это в рамках одной транзакции делаешь? Или несколько запросов с клиента?


 
Nikolay M. ©   (2006-02-01 18:46) [2]


> в чем может юыть проблема?


Например, в


> MS SQL 2005.


Я так и не рискнул на него переезжать до выхода первого пака.


 
Serg2103   (2006-02-01 22:28) [3]


> Надеюсь, ты это в рамках одной транзакции делаешь? Или несколько
> запросов с клиента?


К своему стыду сообщу, что я наверно не совсем хорошо представляю суть вашего вопроса... :[ Вроде, SQL изучил, работать удавалось, а вот в теорию глубоко не вдавался... Наверное, не в рамках одной. Там код примерно так идет:

Query1.SQL.Text:="INSERT ...";
Query1.ExecSQL;
Строчка нейтрального кода
Строчка нейтрального кода
Строчка нейтрального кода
Строчка нейтрального кода
Query1.SQL.Text:="SELECT SCOPE_IDENTITY() AS GUID";
Query1.Open;
GUID:=Query1.FieldByName("GUID").AsString;

Вообщем, вот этот GUID не всегда корректно определяется. Подскажите, в чем моя ошибка?


 
sniknik ©   (2006-02-01 23:53) [4]

> Там код примерно так идет:
сделай так
Строчка нейтрального кода
Строчка нейтрального кода
Строчка нейтрального кода
Строчка нейтрального кода
ADODataSet1.CommandText:=
 "INSERT ..."#13#10+
 "SELECT SCOPE_IDENTITY() AS GUID";
ADODataSet1.Open;
GUID:= ADODataSet1.FieldByName("GUID").AsInteger;


так должно быть всегда коректно.


 
sniknik ©   (2006-02-01 23:56) [5]

но на самом деле поискал бы еще варианты "узких мест" в программе. этот вариант сомнительный какойто.


 
Fay ©   (2006-02-02 09:26) [6]

2 Nikolay M. ©   (01.02.06 18:46) [2]
> Надеюсь, ты это в рамках одной транзакции делаешь?
А какая разница?


 
Ega23 ©   (2006-02-02 09:46) [7]


> Fay ©   (02.02.06 09:26) [6]
>
> 2 Nikolay M. ©   (01.02.06 18:46) [2]
> > Надеюсь, ты это в рамках одной транзакции делаешь?
> А какая разница?
>


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


 
Ega23 ©   (2006-02-02 09:49) [8]

Я бы на твоём месте сделал всё это дело в рамках одной хранимой процедуры.


 
Fay ©   (2006-02-02 09:57) [9]

2 Ega23 ©   (02.02.06 09:46) [7]
> А разница такая, что если несколькими запросами это делать, ...
Извините, но я пока не уловил связи между транзакциями и запросами.


 
Nikolay M. ©   (2006-02-02 10:14) [10]


> 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?


 
msguns ©   (2006-02-02 10:16) [11]

>Ega23 ©   (02.02.06 09:49) [8]
>Я бы на твоём месте сделал всё это дело в рамках одной хранимой процедуры.

А я еще и переставил бы местами запросы: сначала делал бы холостую вставку, определение ID, удаление. После чего вставлял бы мастер-запись с уже известным ID, которое бы и возвращал "клиенту" для добавления в детал или куда там надо (или для перепозиционирования отображаемого НД)


 
ЮЮ ©   (2006-02-02 10:21) [12]

Thus, two statements are in the same scope if they are in the same stored procedure, function, or batch.

По-моему, SCOPE_IDENTITY здесь неуместно


 
Fay ©   (2006-02-02 10:21) [13]

2 Nikolay M. ©   (02.02.06 10:14) [10]
> А зачем ты говоришь это МНЕ?
Могу ли я надеяться, что ТЫ когда-нибудь сможешь простить меня?


 
Fay ©   (2006-02-02 10:22) [14]

2 ЮЮ ©   (02.02.06 10:21) [12]
Совершенно верно


 
Nikolay M. ©   (2006-02-02 10:24) [15]


> Fay ©   (02.02.06 10:21) [13]

Я не настолько жесток, чтобы отнимать у человека надежду.


> Могу ли я надеяться

Да! Конечно.


> ТЫ когда-нибудь сможешь простить меня?

НЕТ!

:-)))


 
Serg2103   (2006-02-02 11:04) [16]


> Во-первых, хотелось бы увидеть полный текст инсерта и "нейтральные
> строчки". А, во-вторых, чему равно 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 включен.


 
Fay ©   (2006-02-02 11:08) [17]

2 Serg2103   (01.02.06 22:28) [3]
Никаких ExecSQL. Просто Open для
set nocount on
insert....
select SCOPE_IDENTITY() as NewsID


 
ЮЮ ©   (2006-02-02 11:09) [18]

Ну и что мешает SELECT SCOPE_IDENTITY добавить в тот же пакет, где производится INSERT? Почему предпочитаешь отдельно?


 
Nikolay M. ©   (2006-02-02 11:10) [19]


> SCOPE_IDENTITY()

Замени на @@IDENTITY


 
Fay ©   (2006-02-02 11:14) [20]

2 Nikolay M. ©   (02.02.06 11:10) [19]
Такая замена не совсем корректна. SCOPE_IDENTITY() и @@IDENTITY возвращают разные значения (в общем случае).


 
Nikolay M. ©   (2006-02-02 11:26) [21]


> SCOPE_IDENTITY() и @@IDENTITY возвращают разные значения
> (в общем случае).

Конечно. Если есть тригеры. Если их нет, то сойдет.
Но самое правильное, конечно - это [17].


 
sniknik ©   (2006-02-02 11:34) [22]

нет, самое правильное это [4] т.к. это тоже самое но основано на " более правильном" компаненте.


 
Fay ©   (2006-02-02 11:37) [23]

2 sniknik ©   (02.02.06 11:34) [22]
Ой, я и не заметил [4]...
А что все тогда обсуждают? 8)


 
Nikolay M. ©   (2006-02-02 12:16) [24]


> sniknik ©   (02.02.06 11:34) [22]
> нет, самое правильное это [4] т.к. это тоже самое но основано
> на " более правильном" компаненте

КомпАнент здесь - дело десятое. Если скажешь, чем ADOQuery в данном случае "лучше" ADODataSet, буду рад узнать что-то новое.

Зато у тебя нет SET NOCOUNT ON, а в [17] он есть, и это более правильно, чем когда его нет, но компАнент "правильный" :)


 
sniknik ©   (2006-02-02 12:23) [25]

> Если скажешь, чем ADOQuery в данном случае "лучше" ADODataSet, буду рад узнать что-то новое.
вериш, уже устал это пояснять и чтото доказывать. может хоть ктото просто поверить на слово? или сделать поиск раз уж "буду рад узнать что-то новое" (в дайджестах например), или посмотреть в исходники ADODB сам?  

> Зато у тебя нет SET NOCOUNT ON
DataSet сам пропустит "пустышки" передваряющие наполненный рекордсет. особого смысла здесь в нем нет.


 
Nikolay M. ©   (2006-02-02 13:18) [26]


> sniknik ©   (02.02.06 12:23) [25]
> вериш, уже устал это пояснять и чтото доказывать. может
> хоть ктото просто поверить на слово? или сделать поиск раз
> уж "буду рад узнать что-то новое" (в дайджестах например),
>  или посмотреть в исходники ADODB сам?


Верю, что устал, потому что постоянно наблюдаю твою нелюбовь к ADOQuery и прочим производным :)
Честно говоря, разбираться в вопросе пока не было времени, потому что всегда пользуюсь ADOCommand и ADODataSet.


 
msguns ©   (2006-02-02 13:52) [27]

>Nikolay M. ©  

Ты, Коля, эта.. не спорь с профессором. Все равно в дурнях оставит, вот увидишь ;))


 
Nikolay M. ©   (2006-02-02 14:56) [28]


> msguns ©   (02.02.06 13:52) [27]

Я этого... буду заниматься тем, чем сочту нужным. Хоть профессоров в дураках оставлять, хоть наоборот...


 
Shirson ©   (2006-02-03 13:57) [29]

Из года в год тема 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... навсегда уйдут из вашей жизни :)



Страницы: 1 вся ветка

Текущий архив: 2006.03.26;
Скачать: CL | DM;

Наверх




Память: 0.55 MB
Время: 0.044 c
10-1115402391
Chattr
2005-05-06 21:59
2006.03.26
Объединение ячеек ввод формул в TExcelApplication


2-1141915164
dest81
2006-03-09 17:39
2006.03.26
BDE


15-1139987532
вразлет
2006-02-15 10:12
2006.03.26
Российский спорт пошел вверх?


15-1141724367
Антон К.
2006-03-07 12:39
2006.03.26
VPN


2-1141846999
asd
2006-03-08 22:43
2006.03.26
Поддержка символов в Memo