Additional
dbCAP
AnyDAC
ThinDAC
NCOCI8
Topic: GetLastAutoGenValue и MSSQL200
[1 2 |Next ]
GetLastAutoGenValue и MSSQL200
Posted: 2007/08/09 01:32
 
Приветствую.

Использую D7, AnyDAC 1.12.2., MSSQL2000 (MSDE).

Хронически не работает GetLastAutoGenValue.
Делаю "рукотворный" INSERT, строка в таблицу добавляется, затем выполняю GetLastAutoGenValue - возвращает NULL.
Внутри GetLastAutoGenValue после

 oCmd.Fetch(oTab);

oTab.Rows.Count = 1, но

 oTab.Rows[0].GetData(0)

возвращает NULL.
При выполнении в Executor-е INSERT-а и SELECT SCOPE_IDENTITY() в log-е пишет

 SELECT SCOPE_IDENTITY()  ...                     Unnamed1                             Done [78 ms]



Executor с последней правкой не пересобирал. Лог из монитора прилагаю. Какие-то там странные BADMEM-ы.

Кстати, может быть у меня что-то с драйверами не то. Explorer при подключении пишет:
================================
Client info
================================
Driver Manager version = 03.52.1117.0000
================================
Session info
================================
Driver name = SQLSRV32.DLL
Driver version = 03.85.1117
Driver conformance = 3
DBMS name = Microsoft SQL Server
DBMS version = 08.00.0194
File Attachment:
File name: Trace_070809_1120.zip
File size:1850 bytes
Re:GetLastAutoGenValue и MSSQL200
Posted: 2007/08/09 03:39
 
Заменил SCOPE_IDENTITY() на @@IDENTITY. Теперь работает.
Re:GetLastAutoGenValue и MSSQL200
Posted: 2007/08/09 04:04
 
1) Советую вам вернуться обратно к SCOPE_IDENTITY(). Иначе если у вас есть триггер вставляющий данные в другую таблицу с identity колонкой, то @@IDENTITY будет возвращать именно то значение, а не то, что вы ожидаете получить. Детали - смотрите в MSSQL Books Online.

2) А зачем вам GetLastAutoGenValue ? Может быть все делается проще ?
Re:GetLastAutoGenValue и MSSQL200
Posted: 2007/08/09 04:23
 
Я заменил SCOPE_IDENTITY() на @@IDENTITY не со скуки, а потому, что иначе не работает. Разницу между ними я выяснил перед тем как заменять. В данный момент мне она не критична, хотя я надеюсь, что проблема со SCOPE_IDENTITY как-нибудь разрешится.

Я использую значение автоинкрементного поля как уникальный идентификатор объекта и получаю его сразу после добавления объекта в базу. На MySQL тот же код работает. Если предложите другой работоспособный метод получить значение последнего добавленного автоинкрементного поля - я с удовольствием его использую.

По поводу неработы SELECT SCOPE_IDENTITY() будут комментарии?

PS. С MS SQL 2000 глюков - море. Не до смеха. Кстати, как там проблема с монитором? Его очень не хватает.
Re:GetLastAutoGenValue и MSSQL200
Posted: 2007/08/09 05:09
 
ak wrote:
что проблема со SCOPE_IDENTITY как-нибудь разрешится.
Проблема в том, что AnyDAC генерирует для Insert & Post запрос:

 INSERT INTO TabWithIdentityField (...) VALUES (...); SELECT SCOPE_IDENTITY() AS IdentityField


И это работат корректно для ситуаций с тригерами. И SCOPE_IDENTITY()не работает если используется вне такого батча. Вне можно использовать @@IDENTITY, оно может возвратить не то, что ожидается. Так или иначе, в 2.0 будет использоваться SCOPE_IDENTITY для батча и @@IDENTITY вне его.

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

 ADQuery1.SQL.Text := 'select * from TabWithIdentityField'; ADQuery1.Open; ADQuery1.Append; ADQuery1.Fields[1].AsString := 'qweqwe'; ADQuery1.Post;


То после Post значение identity поля будет автоматически перечитано. Т.е. просто читайте значение этого поля.

PS. С MS SQL 2000 глюков - море.
Давайте список.

Кстати, как там проблема с монитором? Его очень не хватает.Отвечу отдельным письмом.
Re:GetLastAutoGenValue и MSSQL200
Posted: 2007/08/09 06:04
 
Делаю "рукотворный" INSERT - т.е.:

SQL.Text := 'INSERT...'
после выполнения запроса делаю
GetLastAutoGenValue

Не пойму, почему это не может работать так как я ожидаю.

Глюки и непонятки пока неисследованные. Могу изложить некоторые в виде жалоб:
1. первое слово запроса не может быть макросом,
2. в UPDATE целочисленному полю не присваивается NULL,
3. можно ли присваивать в UPDATE блобы в MSSQL - не знаю, во всяком случае - не работает,
4. BATCH-INSERT отвергается сервером ('ошибка рядом с INTO') - без монитора не вижу во что разворачивается запрос (а трассировка - вводит в ступор

Кстати, вычитал в документации про макрос
{if (Oracl, TO_CHAR, MSSQL, CONVERT)}
Предполагаю, что если оно работает, то можно использовать для TOP-ов и LIMIT-ов ?
Re:GetLastAutoGenValue и MSSQL200
Posted: 2007/08/09 07:42
 
Не пойму, почему это не может работать так как я ожидаю.
Потому что, если у таблице X в INSERT будет триггер на вставку и он будет вставлять запись в другую таблицу Y с identity полем, то @@IDENTITY вернет последнее identity для Y а не для X.
SQL.Text := 'INSERT...'
Используйте:

   with ADQuery1 do begin     SQL.Text := 'INSERT INTO ADQA_Identity_tab (descr) VALUES (:P1); SELECT SCOPE_IDENTITY()';     Params[0].AsString := 'asaasa';     Open;     ShowMessage(Fields[0].AsString);   end;



1. первое слово запроса не может быть макросом,
Да запросто:

 SQL.Text := '&S INTO ADQA_Identity_tab (descr) VALUES (:P1); SELECT SCOPE_IDENTITY()'; Macros[0].AsRaw := 'INSERT';


Возможно вы использовали не AsRaw а AsString или иначе.

2. в UPDATE целочисленному полю не присваивается NULL,
3. можно ли присваивать в UPDATE блобы в MSSQL - не знаю, во всяком случае - не работает,
Нужен ваш код. Я пробую - присваивается и в 1.12 и в 2.0.

4. BATCH-INSERT отвергается сервером ('ошибка рядом с INTO') - без монитора не вижу во что разворачивается запрос (а трассировка - вводит в ступор В 1.12 не работала обработка ошибок для array execution. Но записи вставлялись. По возможности то же - приведите ваш код.
Re:GetLastAutoGenValue и MSSQL200
Posted: 2007/08/09 08:08
 
Diman wrote:
Потому что, если у таблице X в INSERT будет триггер на вставку и он будет вставлять запись в другую таблицу Y с identity полем, то @@IDENTITY вернет последнее identity для Y а не для X.
Возможно я недостаточно вразумительно объясняю ситуацию. Поробую все с начала. Забудем про @@IDENTITY.

Делаю "рукотворный" INSERT - т.е.:
SQL.Text := 'INSERT...'
после выполнения запроса делаю
GetLastAutoGenValue
Первозданный код GetLastAutoGenValue возвращает NULL.
Пробую выполнить в Executor-e последовательность

 INSERT ... SELECT SCOPE_IDENTITY()


запись добавляется, SELECT не возвращает ниодной строки.
Вот эту проблему давайте и разберем.
Та же последовательность в EMS SQL Manager выполняется "на Ура".


Используйте:

   with ADQuery1 do begin     SQL.Text := 'INSERT INTO ADQA_Identity_tab (descr) VALUES (:P1); SELECT SCOPE_IDENTITY()';     Params[0].AsString := 'asaasa';     Open;     ShowMessage(Fields[0].AsString);   end;


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

Остальное - отдельными постами.
Re:GetLastAutoGenValue и MSSQL200
Posted: 2007/08/09 08:39
 
Diman wrote:
3. можно ли присваивать в UPDATE блобы в MSSQL - не знаю, во всяком случае - не работает,Нужен ваш код. Я пробую - присваивается и в 1.12 и в 2.0.

 SQL.Text := 'UPDATE tablename SET BLOB_FIELD = :A0 WHERE ID_FIELD = :A1' Params[1].AsInteger := A_ID; Params[0].AsBlob := '';


Попадаю в

 function TODBCVariable.GetDataPtr(AIndexSQLUIntegerout ApDataSQLPointer;   out ASizeSQLIntegerout ApIndPSQLInteger): PSQLPointer; ...     ASSERT((ASize SQL_LEN_DATA_AT_EXEC_OFFSET) or (ASize >= 0));

Re:GetLastAutoGenValue и MSSQL200
Posted: 2007/08/09 08:41
 

 INSERT ... ; SELECT SCOPE_IDENTITY()


ADExecutor разбивает это на две команды = два батча. Так как ';' для ADExecutor - разделитель скрипта на команды. Выполните вот это:

 -- $DEFINE DELIMITER GO INSERT INTO ADQA_Identity_tab (descrVALUES ('zzz');  SELECT SCOPE_IDENTITY() GO


GetLastAutoGenValue
Короче, оставьте @@IDENTITY. С выходом 2.0 проблема отпадет.
[1 2 |Next ]