Михаиллл
Михаиллл18 сентября 2019 г. 7:25

Можно ли в SQL при команде Inser узнать id , в который записалось.

Добрый день.
Можно ли при команде Inser узнать id , в который записалось.
Пологаю можно в какое-нибудь поле записать уникальное число и потом по нему искать id, но хотелась бы узнать, есть варианты пологичней и с меньшими затратами системы?
Записываю так

    QSqlQuery query(db);
    query.prepare("insert into UESRS (NAME) "
                  "values (:NAME)");
    query.bindValue(":NAME", "UserNotRegistered");

    if(!query.exec())
    {
        emit sig_error(query.lastError().text());
        qDebug()<<"не записалось";
        qDebug()<<"query.lastError().text() : "<<query.lastError().text();
        msg = "false";
    }
    else {
        qDebug()<<"Ok";
        msg = "true";
    }
Рекомендуем хостинг TIMEWEB
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.

Вам это нравится? Поделитесь в социальных сетях!

38
AlexanderBardin
  • 18 сентября 2019 г. 7:29

https://docs.microsoft.com/en-us/sql/t-sql/functions/scope-identity-transact-sql?redirectedfrom=MSDN&view=sql-server-2017

    Ruslan Polupan
    • 18 сентября 2019 г. 7:30
    • (ред.)

    CREATE TABLE USERS в студию.
    И вообще для чего используется таблица?
    у меня такая таблица пользователей например:

    --Таблица пользователей
    CREATE TABLE IF NOT EXISTS `users` (
            `user_id`   INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
            `fio`   TEXT NOT NULL,
            `password`  TEXT,
            `isactive`  TEXT NOT NULL DEFAULT 'true'
    );
    
      Михаиллл
      • 18 сентября 2019 г. 7:35
      • (ред.)

      Таблица хранит данные пользователй
      Вот код таблицы:

      CREATE GENERATOR GEN_UESRS_ID;
      
      CREATE TABLE UESRS (
          ID          INTEGER NOT NULL,
          PHONE       CHAR(1024),
          NAME        CHAR(1024),
          "PASSWORD"  CHAR(1024),
          RATING      FLOAT
      );
      
      
      
      
      /******************************************************************************/
      /***                              Primary keys                              ***/
      /******************************************************************************/
      
      ALTER TABLE UESRS ADD PRIMARY KEY (ID);
      

      Еще у ID есть автоинкримент.
      Работа с базой идет в многопоточном режиме.

        Ruslan Polupan
        • 18 сентября 2019 г. 7:56

        А что дальше надо делать с id пользователя?

          AlexanderBardin
          • 18 сентября 2019 г. 8:19

          Два варианта
          1)
          Если есть поддержка автоинкримента, значит есть тригер и генератор, значит:
          Первым действием получать новый ID например - SELECT GEN_ID( , ) FROM RDB$DATABASE; (пример от СУБД будет отличаться, смотри доку по своей СУБД)
          Далее вставляешь куда угодно, при этом обеспечиваешь уникальность (за этим следит СУБД и дублирования не будет), даже если будет ошибка вставки твой ID просто останется не учтенным, но это без разницы, главная задача уникальности будет обеспечина

          2) Делать вставку и сразу чтение в одной транзакции, т.е. записал данные и прочитал их (с MSSQL так делали, проблем не было)

          А вообще
          - Какая у вас СУБД (от нее зависит много например в MySQL есть команда LAST_INSERT_ID)
          - На чем пишете (Например в Django после сохранении данных сразу можно обратиться и получить ID, без проблем)
          - Задачу бы более шире узнать, т.к. решение может быть проще и вообще лежать в другой плоскости

            Михаиллл
            • 18 сентября 2019 г. 9:01

            Я пишу на с++ в Qt.
            База данных Firebird.
            Нужно заргистрировать пользователя без данных, после этого вернуть id, под которым пользователь зарегистрирован. Больше ничего делать не нужно.

              AlexanderBardin
              • 18 сентября 2019 г. 9:09

              Вариант 1 используйте - SELECT GEN_ID(my_gen , incr) FROM RDB$DATABASE (https://firebirdsql.org/refdocs/langrefupd20-genid.html)

              Когда пишу под FB делаю именно так, проблем не встречал
              пример таблицы и тригера ниже

              CREATE GENERATOR GEN_USERS_ID;
              
              CREATE TABLE USERS (
                  ID                        DT_ID /* DT_ID = INTEGER NOT NULL */,
                  NAME                      VARCHAR(500),
                  LOGIN                     VARCHAR(50),
                  PWD                       VARCHAR(50),
                  PROF                      VARCHAR(50),
              
              );
              
              
              /******************************************************************************/
              /***                              Primary keys                              ***/
              /******************************************************************************/
              
              ALTER TABLE USERS ADD CONSTRAINT PK_USERS PRIMARY KEY (ID);
              
              
              /******************************************************************************/
              /***                                Indices                                 ***/
              /******************************************************************************/
              
              CREATE INDEX USERS_ID ON USERS (ID);
              CREATE INDEX USERS_NAME ON USERS (NAME);
              
              
              /******************************************************************************/
              /***                                Triggers                                ***/
              /******************************************************************************/
              
              
              
              SET TERM ^ ;
              
              
              
              /******************************************************************************/
              /***                          Triggers for tables                           ***/
              /******************************************************************************/
              
              
              
              /* Trigger: USERS_BI */
              CREATE OR ALTER TRIGGER USERS_BI FOR USERS
              ACTIVE BEFORE INSERT POSITION 0
              as
              begin
                if (new.id is null) then
                  new.id = gen_id(gen_users_id,1);
              end
              ^
              
                Ruslan Polupan
                • 18 сентября 2019 г. 9:40

                Думаю если будете делать в потоках то мне кажется что просле INSERT сдулать SELECT u.id FROM users u WHERE u.name = 'UserName' и вернуть Id из потока.

                  AlexanderBardin
                  • 18 сентября 2019 г. 9:49

                  Мне кажется плохая идея для FB, впрочем я не знаком с тонкостями работы C++ для MySQL где-то читал там такая фишка работает, но почему-то у меня сложилось мнение что именно MySQL обеспечивает изоляцию. В любом случае по ресурсоемкости будет одно и тоже, мой вариант, он однозначен как топор - будет работать, проблем с уникальностью не будет, а вот с поотками еще вопрос... Только время и нагрузка покажет)

                    Михаиллл
                    • 18 сентября 2019 г. 10:47

                    При такой записи имена всех юзеров будут одинаковыми.
                    В таком случае выдаст наверно первый id из базы, а не последний

                    SELECT u.id FROM users WHERE u.name = 'UserName'  
                    
                      AlexanderBardin
                      • 18 сентября 2019 г. 10:50

                      вам написали рецепт, если идей лучше нет делайте по рецепту. так как вы написали идентифицировать id нельзя

                        Михаиллл
                        • 18 сентября 2019 г. 10:53

                        Да, спасибо буду пытаться сделать по Вашему варианту.

                          AlexanderBardin
                          • 18 сентября 2019 г. 10:58

                          у вас два запрлса первый получает id второй вставляет новую запись используя полученный в первом запросе id. Все это вы делаете в С++ так сказать. не забудьте дописать нужный тригер и создать ненератор, если его нет, если делать базу через ibEpert и поставить флаг автоинкримент, то оно все само сделает

                            Михаиллл
                            • 18 сентября 2019 г. 11:08

                            Попробовал Ваш запрос

                            SELECT GEN_ID(GEN_UESRS_ID , 1) FROM UESRS
                            

                            Но получаю ошибку

                            value: not positioned on a valid record
                            

                            Скажите пожалуйста что не так в моем запросе?
                            Ниже полный код моей таблицы:

                            /******************************************************************************/
                            /***               Generated by IBExpert 18.09.2019 18:59:25                ***/
                            /******************************************************************************/
                            
                            /******************************************************************************/
                            /***      Following SET SQL DIALECT is just for the Database Comparer       ***/
                            /******************************************************************************/
                            SET SQL DIALECT 3;
                            
                            
                            
                            /******************************************************************************/
                            /***                                 Tables                                 ***/
                            /******************************************************************************/
                            
                            
                            CREATE GENERATOR GEN_UESRS_ID;
                            
                            CREATE TABLE UESRS (
                                ID          INTEGER NOT NULL,
                                PHONE       CHAR(1024),
                                NAME        CHAR(1024),
                                "PASSWORD"  CHAR(1024),
                                RATING      FLOAT
                            );
                            
                            
                            
                            
                            /******************************************************************************/
                            /***                              Primary keys                              ***/
                            /******************************************************************************/
                            
                            ALTER TABLE UESRS ADD PRIMARY KEY (ID);
                            
                            
                            /******************************************************************************/
                            /***                                Triggers                                ***/
                            /******************************************************************************/
                            
                            
                            
                            SET TERM ^ ;
                            
                            
                            
                            /******************************************************************************/
                            /***                          Triggers for tables                           ***/
                            /******************************************************************************/
                            
                            
                            
                            /* Trigger: UESRS_BI */
                            CREATE OR ALTER TRIGGER UESRS_BI FOR UESRS
                            ACTIVE BEFORE INSERT POSITION 0
                            as
                            begin
                              if (new.id is null) then
                                new.id = gen_id(gen_uesrs_id,1);
                            end
                            ^
                            
                            SET TERM ; ^
                            
                            
                            
                            /******************************************************************************/
                            /***                               Privileges                               ***/
                            /******************************************************************************/
                            
                            
                              Михаиллл
                              • 18 сентября 2019 г. 11:49

                              А если в базе выполняю эту команду, то получаю 3 числа в столбик, но никак не одно.
                              Скажите пожалуйста, почему так?

                              SELECT GEN_ID(GEN_UESRS_ID , 1) FROM UESRS
                              
                                Михаиллл
                                • 18 сентября 2019 г. 12:05

                                Оно похоже пробегает ко всему столбцу и добавляет столько значений, сколько есть в таблице.
                                Если делать так, то добавляет только 1 значение к последнему, но как прописать последнее значение?

                                SELECT GEN_ID(GEN_UESRS_ID , 1) FROM UESRS  WHERE id = 20
                                
                                  AlexanderBardin
                                  • 18 сентября 2019 г. 12:16

                                  напишите завтра в телеграмм разберемся, потом тут выложите готовый рецепт @Bardin_A_A

                                    Михаиллл
                                    • 19 сентября 2019 г. 1:45

                                    Такой запрос в базе работает

                                    SELECT GEN_ID(GEN_UESRS_ID , 1) FROM RDB$DATABASE
                                    

                                    Но в Qt такой код возвращает 0. Скажите пожалуйста, что не так в этом коде?

                                    query.prepare("SELECT GEN_ID(GEN_UESRS_ID , 1) FROM RDB$DATABASE");
                                    
                                        if(!query.exec())
                                        {
                                            emit sig_error(query.lastError().text());
                                            qDebug()<<"не записалось";
                                            qDebug()<<"query.lastError().text() : "<<query.lastError().text();
                                            msg = "false";
                                        }
                                        else {
                                            qDebug()<<"Ok";
                                            qDebug()<<"query.value(0):"<<query.value(0).toInt();
                                            msg = "true";
                                        }
                                    
                                      Ruslan Polupan
                                      • 19 сентября 2019 г. 1:47
                                      • (ред.)

                                      Процедура не подойдет?

                                      SET TERM ^ ;
                                      CREATE OR ALTER PROCEDURE adduser (name VARCHAR(1024),  phone VARCHAR(1024), password VARCHAR(1024), rating float)
                                      return (user_id integer)
                                      as
                                      DECLARE VARIABLE user_id;
                                      begin
                                          user_id = GEN_ID(GEN_USERS_ID,1);
                                          insert into USERS (ID,PHONE,NAME, PASSWORD,RATING)
                                          values(:user_id, phone, name, password, rating);
                                      end^
                                      SET TERM ; ^
                                      

                                      возвращает id и добавляет запись в таблицу.

                                        Михаиллл
                                        • 19 сентября 2019 г. 2:03

                                        Скажите пожалуйста, что делать с это процедурой?
                                        Её нужно выполнить в базе данных и потом как то ее вызывать из Qt? Если да, то как потом вызывать процедуру?

                                          Ruslan Polupan
                                          • 19 сентября 2019 г. 2:24
                                          • (ред.)

                                          Выполнить скрипт на базе через редактор скриптов IBE , а вызывать через QSqlQuery как обычный запрос.
                                          только в доках глянь как получать возвращаемое заначение, я не помню.
                                          q.prepare("execute procedure addser(:name, :ph, :pass, :rat)");

                                            Михаиллл
                                            • 19 сентября 2019 г. 2:32

                                            Скажите пожалуйста, как добавить эту процедуру?
                                            Если просто вставляю в скрипт, то оно не работает (что ожидаемо).
                                            Похоже ее нужно добавлять непосредственно в нужную таблицу, но как?

                                              Ruslan Polupan
                                              • 19 сентября 2019 г. 2:39

                                              IBexpert Настройки редактор скриптов Ctrl+F12
                                              Не забыть поставить галочку Использовать текщее соединение

                                                AlexanderBardin
                                                • 19 сентября 2019 г. 2:40

                                                https://s.mail.ru/BkqS/KQBWcafHa

                                                  AlexanderBardin
                                                  • 19 сентября 2019 г. 2:41

                                                  только мне кажется в строке
                                                  3 - returns (user_id integer) нужно написать, а не return
                                                  5 - DECLARE VARIABLE user_id integer; тут по моему надо указать тип переменной integer

                                                    Ruslan Polupan
                                                    • 19 сентября 2019 г. 2:43

                                                    Согласен... не было примеров под рукой.

                                                      Михаиллл
                                                      • 19 сентября 2019 г. 2:43

                                                      Но у меня почему-то интерфейс отличается, нормально ли это? Или може

                                                        AlexanderBardin
                                                        • 19 сентября 2019 г. 2:47

                                                        да нормально, от версии зависит, и у меня все в одном окне опция стоит, у вас нет

                                                          Ruslan Polupan
                                                          • 19 сентября 2019 г. 2:49

                                                          Советы по IBE: ВЫМУЧАННЫЕ массой потерянного времени
                                                          1. Использовать последню версию. https://ru.wikipedia.org/wiki/IBExpert в разделе ссылки Бесплатная полнофункциональная версия — Ссылка для скачивания специальной лицензии для бывшего СССР.
                                                          2. НИКОГДА не использовать SDI интерфейс. Изменить можно Настройка Настроки среды.

                                                            Михаиллл
                                                            • 19 сентября 2019 г. 2:58

                                                            Получилась такая процедура

                                                            SET TERM ^ ;
                                                            CREATE OR ALTER PROCEDURE adduser (name VARCHAR(1024),  phone VARCHAR(1024), password VARCHAR(1024), rating float)
                                                            returns  (user_id integer)
                                                            as
                                                            DECLARE VARIABLE user_id integer; 
                                                            begin
                                                                user_id = GEN_ID(GEN_USERS_ID,1);
                                                                insert into USERS (ID,PHONE,NAME, PASSWORD,RATING)
                                                                values(:user_id, phone, name, password, rating);
                                                            end^
                                                            SET TERM ; ^
                                                            

                                                            Но при нажатии на выполнение получаю ошибку, говорящую что скрипт выполнен с ошибкой.

                                                              Ruslan Polupan
                                                              • 19 сентября 2019 г. 3:00

                                                              Текст или срин ошибки.

                                                                Михаиллл
                                                                • 19 сентября 2019 г. 3:04

                                                                Unsuccessful execution caused by system error that does not preclude successful execution of subsequent statements.
                                                                Dynamic SQL Error.
                                                                SQL error code = -901.
                                                                variable USER_ID conflicts with parameter in same procedure.

                                                                  Ruslan Polupan
                                                                  • 19 сентября 2019 г. 3:13

                                                                  А если так

                                                                  SET TERM ^ ;
                                                                  CREATE OR ALTER PROCEDURE adduser (name VARCHAR(1024),  phone VARCHAR(1024), password VARCHAR(1024), rating float)
                                                                  returns (out_user_id integer)
                                                                  as
                                                                  DECLARE VARIABLE user_id integer;
                                                                  begin
                                                                      user_id = GEN_ID(GEN_USERS_ID,1);
                                                                      out_user_id = :user_id;
                                                                      insert into USERS (ID,PHONE,NAME, PASSWORD,RATING)
                                                                      values(:user_id, phone, name, password, rating);
                                                                  end^
                                                                  SET TERM ; ^
                                                                  
                                                                    Михаиллл
                                                                    • 19 сентября 2019 г. 3:26
                                                                    • Ответ был помечен как решение.

                                                                    Подправил скрипт, так приняло:

                                                                    SET TERM ^ ;
                                                                    CREATE OR ALTER PROCEDURE adduser (name VARCHAR(1024),  phone VARCHAR(1024), password VARCHAR(1024), rating float)
                                                                    returns (out_user_id integer)
                                                                    as
                                                                    DECLARE VARIABLE user_id integer;
                                                                    begin
                                                                        user_id = GEN_ID(GEN_UESRS_ID,1);
                                                                        out_user_id = :user_id;
                                                                        insert into UESRS (ID,PHONE,NAME, PASSWORD,RATING)
                                                                        values(:user_id, :phone, :name, :password, :rating);
                                                                    end^
                                                                    SET TERM ; ^
                                                                    

                                                                    В Qt Сделал такой запрос и все заработало

                                                                            query.prepare("execute procedure adduser(:name, :phone, :password, :rating)");
                                                                        query.bindValue(":name", "UserNotRegistered");
                                                                        query.bindValue(":phone", "UserNotRegistered");
                                                                        query.bindValue(":password", "UserNotRegistered");
                                                                        query.bindValue(":rating", 0);
                                                                    
                                                                        if(!query.exec())
                                                                        {
                                                                            emit sig_error(query.lastError().text());
                                                                            qDebug()<<"не записалось";
                                                                            qDebug()<<"query.lastError().text() : "<<query.lastError().text();
                                                                            msg = "false";
                                                                        }
                                                                        else if(query.next()) {
                                                                            qDebug()<<"Ok";
                                                                            qDebug()<<"query.value(0):"<<query.value(0).toString();
                                                                            msg = "true";
                                                                        }
                                                                    

                                                                    Спасибо всем за помощь!

                                                                      Ruslan Polupan
                                                                      • 19 сентября 2019 г. 3:37

                                                                      Так а где ты используешь возвращаемый ID?

                                                                        Михаиллл
                                                                        • 19 сентября 2019 г. 3:41

                                                                        В клиентской части. Клиентская часть по id будет получать соответствующую информацию.

                                                                          Ruslan Polupan
                                                                          • 19 сентября 2019 г. 4:01

                                                                          если просто добавлять запись, то тогда процедра не нужна

                                                                          insert into USERS (ID,PHONE,NAME, PASSWORD,RATING)
                                                                          values(GEN_ID(GEN_USERS_ID,1), phone, name, password, rating);
                                                                          
                                                                            Михаиллл
                                                                            • 19 сентября 2019 г. 4:32

                                                                            Но мне же нужно еще получить этот id и вернуть его пользователю, а при таком запросе ничего не вернется.

                                                                              Комментарии

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

                                                                              C++ - Тест 002. Константы

                                                                              • Результат:16баллов,
                                                                              • Очки рейтинга-10
                                                                              B

                                                                              C++ - Тест 001. Первая программа и типы данных

                                                                              • Результат:46баллов,
                                                                              • Очки рейтинга-6
                                                                              FL

                                                                              C++ - Тест 006. Перечисления

                                                                              • Результат:80баллов,
                                                                              • Очки рейтинга4
                                                                              Последние комментарии
                                                                              k
                                                                              kmssr8 февраля 2024 г. 18:43
                                                                              Qt Linux - Урок 001. Автозапуск Qt приложения под Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
                                                                              АК
                                                                              Анатолий Кононенко5 февраля 2024 г. 1:50
                                                                              Qt WinAPI - Урок 007. Работаем с ICMP Ping в Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
                                                                              EVA
                                                                              EVA25 декабря 2023 г. 10:30
                                                                              Boost - статическая линковка в CMake проекте под Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
                                                                              J
                                                                              JonnyJo25 декабря 2023 г. 8:38
                                                                              Boost - статическая линковка в CMake проекте под Windows Сделал всё по-как у вас, но выдаёт ошибку [build] LINK : fatal error LNK1104: не удается открыть файл "libboost_locale-vc142-mt-gd-x64-1_74.lib" Хоть убей, не могу понять в чём дел…
                                                                              G
                                                                              Gvozdik18 декабря 2023 г. 21:01
                                                                              Qt/C++ - Урок 056. Подключение библиотеки Boost в Qt для компиляторов MinGW и MSVC Для решения твой проблемы добавь в файл .pro строчку "LIBS += -lws2_32" она решит проблему , лично мне помогло.
                                                                              Сейчас обсуждают на форуме
                                                                              P
                                                                              Pisych27 февраля 2023 г. 4:04
                                                                              Как получить в массив значения из связанной модели? Спасибо, разобрался:))
                                                                              AC
                                                                              Alexandru Codreanu19 января 2024 г. 11:57
                                                                              QML Обнулить значения SpinBox Доброго времени суток, не могу разобраться с обнулением значение SpinBox находящего в делегате. import QtQuickimport QtQuick.ControlsWindow { width: 640 height: 480 visible: tr…
                                                                              BlinCT
                                                                              BlinCT27 декабря 2023 г. 8:57
                                                                              Растягивать Image на парент по высоте Ну и само собою дял включения scrollbar надо чтобы был Flickable. Так что выходит как то так Flickable{ id: root anchors.fill: parent clip: true property url linkFile p…
                                                                              Дмитрий
                                                                              Дмитрий10 января 2024 г. 4:18
                                                                              Qt Creator загружает всю оперативную память Проблема решена. Удалось разобраться с помощью утилиты strace. Запустил ее: strace ./qtcreator Начал выводиться весь лог работы креатора. В один момент он начал считывать фай…
                                                                              Evgenii Legotckoi
                                                                              Evgenii Legotckoi12 декабря 2023 г. 6:48
                                                                              Побуквенное сравнение двух строк Добрый день. Там случайно не высылается этот сигнал textChanged ещё и при форматировани текста? Если решиать в лоб, то можно просто отключать сигнал/слотовое соединение внутри слота и …

                                                                              Следите за нами в социальных сетях