Russian Qt Forum

Qt => Базы данных => Тема начата: roman-ktn от Ноябрь 10, 2008, 14:42



Название: Получить значение идентификатора при добавлении строки
Отправлено: roman-ktn от Ноябрь 10, 2008, 14:42
Здравствуйте

Использую MS SQL Server

На пример у меня есть таблица table1 с полями: i_key, field1
i_key — идентификатор записи, значение которого определяется базой данных

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


Название: Re: Получить значение идентификатора при добавлении строки
Отправлено: kirill от Ноябрь 11, 2008, 07:52
Код:

         QSqlQuery insert_query;
         insert_query.prepare("INSERT INTO table1 (field1) VALUES (:field1)");
         insert_query.bindValue(":field1", "field1");         
         if (insert_query.exec())
         {
               QString sKey = QVariant(insert_query.lastInsertId()).toString();
          }



Название: Re: Получить значение идентификатора при добавлении строки
Отправлено: roman-ktn от Ноябрь 11, 2008, 11:33
Спасибо


Название: Re: Получить значение идентификатора при добавлении строки
Отправлено: roman-ktn от Ноябрь 14, 2008, 00:24
Попробовал пример, MS SQL возвращает пустую строку  :'( .
А есть еще какой-нибудь способ?


Название: Re: Получить значение идентификатора при добавлении строки
Отправлено: ритт от Ноябрь 14, 2008, 00:43
как работаешь с MS SQL? через ODBC? тогда, конечно, пустая строка, т.к. lastInsertId() вернёт невалидный вариант.
ищи нормальный драйвер (и нормальную бд)


Название: Re: Получить значение идентификатора при добавлении строки
Отправлено: roman-ktn от Ноябрь 14, 2008, 01:10
Да подключаюсь через ODBC
Цитировать
ищи нормальный драйвер (и нормальную бд)
  :)
БД пока, и в бижайшем будущем поменять не могу.  :'(
Подскажите, пожалуйста, на счет подключения и драйвера, как вариант


Название: Re: Получить значение идентификатора при добавлении строки
Отправлено: ритт от Ноябрь 14, 2008, 01:16
если не ошибаюсь, где-то что-то по поводу м$ скл тут пробегало - попробуй поискать. мб ещё гугль чем-нибудь подсобит.


Название: Re: Получить значение идентификатора при добавлении строки
Отправлено: Alex03 от Ноябрь 14, 2008, 08:45
А в етом MS SQL нет чегонить типа
INSERT INTO XXXXX XXXXX XXXXX RETURNING xxxxx
як в firebird 2.x ?


Название: Re: Получить значение идентификатора при добавлении строки
Отправлено: roman-ktn от Ноябрь 14, 2008, 11:00
Цитировать
А в етом MS SQL нет чегонить типа
INSERT INTO XXXXX XXXXX XXXXX RETURNING xxxxx
як в firebird 2.x ?
Есть, можно сделать запрос:
Код:
INSERT INTO table1 (field1) 
OUTPUT inserted.*
VALUES (1)
Он возвращает добавленную запись, но до Qt доходит только пустая таблица


Название: Re: Получить значение идентификатора при добавлении строки
Отправлено: roman-ktn от Ноябрь 14, 2008, 11:10
Цитировать
Он возвращает добавленную запись, но до Qt доходит только пустая таблица
И в добавок сбивается подключение


Название: Re: Получить значение идентификатора при добавлении строки
Отправлено: spirit от Ноябрь 14, 2008, 11:29
я делал собственный метод и для Oracle и для PostgeSql, который возвращает последний добавленный id.
какие-то бока были с QSqlQuery::lastInsertId уже не помню. так что, имхо, сделайте тоже сами такой метод.


Название: Re: Получить значение идентификатора при добавлении строки
Отправлено: roman-ktn от Ноябрь 14, 2008, 12:20
Цитировать
И в добавок сбивается подключение
Нет, подключение не сбивается, но пустеют таблицы, но это неважно
Цитировать
делал собственный метод и для Oracle и для PostgeSql, который возвращает последний добавленный id.
какие-то бока были с QSqlQuery::lastInsertId уже не помню. так что, имхо, сделайте тоже сами такой метод.
Не понимаю, как его можно сделать. Набираю код:
Код:
QSqlQueryModel *model = new QSqlQueryModel;
model->setQuery(tr("exec proc1 "), database);
QTableView *view = new QTableView;
view->setModel(model);
view->show();
Процедура proc1 выводит таблицу. А у меня в результате пустая таблица. Поля все на месте, а записей нет.  :-\
Я так понимаю, что он кроме SELECT, INSERT, UPDATE и DELETE ни с чем работать не хочет.
Сейчас наверно по нему стукну  :)
Я использую версию 4.1.1., с учебника, если скачать более новую, то это может помочь?


Название: Re: Получить значение идентификатора при добавлении строки
Отправлено: spirit от Ноябрь 14, 2008, 12:24
Цитировать
делал собственный метод и для Oracle и для PostgeSql, который возвращает последний добавленный id.
какие-то бока были с QSqlQuery::lastInsertId уже не помню. так что, имхо, сделайте тоже сами такой метод.
Не понимаю, как его можно сделать. Набираю код:
в оракле создается последовательность для генерации нового id, в постргесе есть спец. таблицы где хранится последний добавленный id. следовательно, что-то подобное должно быть в MS SQL, читайте доку по нему.  :)


Название: Re: Получить значение идентификатора при добавлении строки
Отправлено: ритт от Ноябрь 14, 2008, 12:34
Я использую версию 4.1.1., с учебника, если скачать более новую, то это может помочь?

Qt 4.1.1 ?! срочно обновляйся! :)
потом напишешь изменилась ли ситуация...


Название: Re: Получить значение идентификатора при добавлении строки
Отправлено: spirit от Ноябрь 17, 2008, 11:10
по идее должно. но имхо должна быть табла(или последовательность) отвечающая за генерацию значения.


Название: Re: Получить значение идентификатора при добавлении строки
Отправлено: Tonal от Ноябрь 19, 2008, 12:02
select max(i_key) from table1
это будет не равносильно?
А теперь представь что будет если работают несколько пользователей одновременно...


Название: Re: Получить значение идентификатора при добавлении строки
Отправлено: Пантер от Ноябрь 19, 2008, 20:51
Если в пределах транзакции, то все должно быть нормально.


Название: Re: Получить значение идентификатора при добавлении строки
Отправлено: Tonal от Ноябрь 20, 2008, 09:55
Если не вклинится другой поток, хотя тут я не в курсе - можно ли в Qt + ODBC + MS расшаривать транзакцию на несколько потоков.

А по поводу работоспособности QSqlQuery::lastInsertId, нужно дёргать QSqlDriver::hasFeature() и смотреть установлен ли флаг QSqlDriver::LastInsertId.


Название: Re: Получить значение идентификатора при добавлении строки
Отправлено: Hellraiser от Ноябрь 20, 2008, 10:18
по идее должно. но имхо должна быть табла(или последовательность) отвечающая за генерацию значения.
Так оно и есть. Из системной переменной @@IDENTITY можно получить значение идентификатора, сформированное в результате применения последнего оператора. Наиболее удобный способ - писать процедуру, внутри которой и происходит заполнение полей реальных таблиц.
Очень много интересного можно найти в книге по программированию на MSSQL http://www.axifile.com/?8684781


Название: Re: Получить значение идентификатора при добавлении строки
Отправлено: spirit от Ноябрь 20, 2008, 10:29
куль, буду знать. с этим сервером никогда не работал :)


Название: Re: Получить значение идентификатора при добавлении строки
Отправлено: roman-ktn от Ноябрь 20, 2008, 14:04
С системной переменной @@IDENTITY заработало
А функция SCOPE_IDENTITY() в qt у меня выводила пустое значение
Всем спасибо


Название: Re: Получить значение идентификатора при добавлении строки
Отправлено: masha от Март 16, 2010, 18:56
лучше
SELECT IDENT_CURRENT('имя_таблицы')


Название: Re: Получить значение идентификатора при до&#
Отправлено: IgorK от Февраль 17, 2012, 14:02
С системной переменной @@IDENTITY заработало
А функция SCOPE_IDENTITY() в qt у меня выводила пустое значение
Всем спасибо

Мы не всегда можем использовать INSERT INTO ...; SELECT @@IDENTITY и INSERT INTO ... OUTPUT inserted.id , и никогда не можем их использовать, если б/д создана и используется не нами, т.к. никто не гарантирует, что к таблице не привяжут триггер на вставку:
Код:
SCOPE_IDENTITY and @@IDENTITY will return last identity values generated in any table in the current session. However, SCOPE_IDENTITY returns values inserted only within the current scope; @@IDENTITY is not limited to a specific scope.

For example, you have two tables, T1 and T2, and an INSERT trigger defined on T1. When a row is inserted to T1, the trigger fires and inserts a row in T2. This scenario illustrates two scopes: the insert on T1, and the insert on T2 as a result of the trigger.

Assuming that both T1 and T2 have IDENTITY columns, @@IDENTITY and SCOPE_IDENTITY will return different values at the end of an INSERT statement on T1.

@@IDENTITY will return the last IDENTITY column value inserted across any scope in the current session, which is the value inserted in T2.

SCOPE_IDENTITY() will return the IDENTITY value inserted in T1, which was the last INSERT that occurred in the same scope. The SCOPE_IDENTITY() function will return the NULL value if the function is invoked before any insert statements into an identity column occur in the scope.

Таким образом у нас остается только SCOPE_IDENTITY(), который в отдельном запросе возвращает нам ничего (т.к. для сервера это будет уже другой scope), либо SCOPE_IDENTITY() вернет верное значение, но ODBC драйвер его не вернет (т.к. он не шибко умный), если мы попытаемся выкинуть что-то типа:
Код:
QSqlQuery sql(QSqlDatabase::database());
sql.exec("INSERT INTO someone VALUES (somefings); select SCOPE_IDENTITY()");

Но выход есть: с помощью команды MS SQL EXECUTE() маскируем два запроса "INSERT INTO someone VALUES (somefings)" и "select SCOPE_IDENTITY()" в один и получаем практически безкостыльную рабочую строчку:
Код:
QSqlQuery sql(QSqlDatabase::database());
sql.exec("EXEC('INSERT INTO someone VALUES (somefings); select SCOPE_IDENTITY()')");
sql.next();
int id = sql.value(0).toInt();


Название: Re: Получить значение идентификатора при добавлении строки
Отправлено: RVZ от Март 19, 2012, 20:16
Вообще тема весьма сомнительна...
Добавление строк к в таблицы реляционной БД вопрос весьма не простой и как правило ответственность за это действие передается хранимым процедурам а также процесс удаления строк тоже.
Это связанно с тем что
1) надо обеспечивать корректное добавление с ведением логов, вставкой внешних ключей, вычисляемых столбцов.
2) при изменении структуры таблицы или связей проще править хранимую процедуру чем пере собирать проект и инсталить его на пачке машин.
3) незачем гонять туда сюда промежуточную информацию (вся работа на стороне сервера)
А вот с возвернутом ID записи (после выполнения хранимой процедуры работать просто)
Пример для MS SQL 2005 (есть еще подобный для PostgreSQL)
Код
SQL
CREATE TABLE [my].[Myt](
[MytID] [bigint] IDENTITY(1,1) NOT NULL,
[Surname] [nvarchar](20) NOT NULL,
[FirstName] [nvarchar](20) NOT NULL,
[PersonalTypeID] [smallint] NOT NULL CONSTRAINT [DF_Myt_PersonalTypeID]  DEFAULT ((1)),
[RegistrationDate] [datetime] NOT NULL,
 CONSTRAINT [PK_Myt] PRIMARY KEY CLUSTERED(
[MytID] ASC
 )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]
 
 
CREATE PROCEDURE [my].[AddRecMyt]
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO my.Myt
(Surname, FirstName, Patronymic, PersonalTypeID, RegistrationDate)
VALUES
('Не определено', 'Не определено', 'Не определено', 1, GETDATE())
SELECT SCOPE_IDENTITY()
END
 

Пример конструктора для формы создания новой записи.
Код
C++ (Qt)
Data::Data(QWidget *parent, int MytID):QWidget(parent),ui(new Ui::Data){
   ui->setupUi(this);
   if(MytID == 0){
       QSqlQuery query;
       query.exec("my.AddRecMyt");
       if(query.first()){
         MytID = query.value(0).toInt();
         qDebug()<<"Add MytID = "<<MytID;
       }
       query.clear();
   }
   ......
}
 

Не совсем по сути вопроса... но может получиться отговорить разработчика :) вешать SQL сопли в приложении.