Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

SCOPE_IDENTITY() не всегда корректно выполняется [D7, MSSQL]


Страницы:   1 2

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?


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо