Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Базы";
Текущий архив: 2006.03.26;
Скачать: [xml.tar.bz2];

Вниз

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;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.53 MB
Время: 0.04 c
2-1142245192
dabreezy
2006-03-13 13:19
2006.03.26
TstringList - глюк на глюке.


2-1141820098
Fenix
2006-03-08 15:14
2006.03.26
Форма и ДЛЛ


2-1141896174
kyn66
2006-03-09 12:22
2006.03.26
Проверка активности элементов


15-1141036082
Loginov Dmitry
2006-02-27 13:28
2006.03.26
Про сайт...


4-1135390132
Grinder
2005-12-24 05:08
2006.03.26
Добавить пункт в чужое меню





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский