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

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

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

  1. QSqlQuery query(db);
  2. query.prepare("insert into UESRS (NAME) "
  3. "values (:NAME)");
  4. query.bindValue(":NAME", "UserNotRegistered");
  5.  
  6. if(!query.exec())
  7. {
  8. emit sig_error(query.lastError().text());
  9. qDebug()<<"не записалось";
  10. qDebug()<<"query.lastError().text() : "<<query.lastError().text();
  11. msg = "false";
  12. }
  13. else {
  14. qDebug()<<"Ok";
  15. msg = "true";
  16. }
4

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

38
AlexanderBardin
  • 18 сентября 2019 г. 18: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 г. 18:30
    • (ред.)

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

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

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

      1. CREATE GENERATOR GEN_UESRS_ID;
      2.  
      3. CREATE TABLE UESRS (
      4. ID INTEGER NOT NULL,
      5. PHONE CHAR(1024),
      6. NAME CHAR(1024),
      7. "PASSWORD" CHAR(1024),
      8. RATING FLOAT
      9. );
      10.  
      11.  
      12.  
      13.  
      14. /******************************************************************************/
      15. /*** Primary keys ***/
      16. /******************************************************************************/
      17.  
      18. ALTER TABLE UESRS ADD PRIMARY KEY (ID);

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

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

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

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

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

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

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

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

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

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

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

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

              1. CREATE GENERATOR GEN_USERS_ID;
              2.  
              3. CREATE TABLE USERS (
              4. ID DT_ID /* DT_ID = INTEGER NOT NULL */,
              5. NAME VARCHAR(500),
              6. LOGIN VARCHAR(50),
              7. PWD VARCHAR(50),
              8. PROF VARCHAR(50),
              9.  
              10. );
              11.  
              12.  
              13. /******************************************************************************/
              14. /*** Primary keys ***/
              15. /******************************************************************************/
              16.  
              17. ALTER TABLE USERS ADD CONSTRAINT PK_USERS PRIMARY KEY (ID);
              18.  
              19.  
              20. /******************************************************************************/
              21. /*** Indices ***/
              22. /******************************************************************************/
              23.  
              24. CREATE INDEX USERS_ID ON USERS (ID);
              25. CREATE INDEX USERS_NAME ON USERS (NAME);
              26.  
              27.  
              28. /******************************************************************************/
              29. /*** Triggers ***/
              30. /******************************************************************************/
              31.  
              32.  
              33.  
              34. SET TERM ^ ;
              35.  
              36.  
              37.  
              38. /******************************************************************************/
              39. /*** Triggers for tables ***/
              40. /******************************************************************************/
              41.  
              42.  
              43.  
              44. /* Trigger: USERS_BI */
              45. CREATE OR ALTER TRIGGER USERS_BI FOR USERS
              46. ACTIVE BEFORE INSERT POSITION 0
              47. as
              48. begin
              49. if (new.id is null) then
              50. new.id = gen_id(gen_users_id,1);
              51. end
              52. ^
                Ruslan Polupan
                • 18 сентября 2019 г. 20:40

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

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

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

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

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

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

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

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

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

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

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

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

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

                            1. SELECT GEN_ID(GEN_UESRS_ID , 1) FROM UESRS

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

                            1. value: not positioned on a valid record

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

                            1. /******************************************************************************/
                            2. /*** Generated by IBExpert 18.09.2019 18:59:25 ***/
                            3. /******************************************************************************/
                            4.  
                            5. /******************************************************************************/
                            6. /*** Following SET SQL DIALECT is just for the Database Comparer ***/
                            7. /******************************************************************************/
                            8. SET SQL DIALECT 3;
                            9.  
                            10.  
                            11.  
                            12. /******************************************************************************/
                            13. /*** Tables ***/
                            14. /******************************************************************************/
                            15.  
                            16.  
                            17. CREATE GENERATOR GEN_UESRS_ID;
                            18.  
                            19. CREATE TABLE UESRS (
                            20. ID INTEGER NOT NULL,
                            21. PHONE CHAR(1024),
                            22. NAME CHAR(1024),
                            23. "PASSWORD" CHAR(1024),
                            24. RATING FLOAT
                            25. );
                            26.  
                            27.  
                            28.  
                            29.  
                            30. /******************************************************************************/
                            31. /*** Primary keys ***/
                            32. /******************************************************************************/
                            33.  
                            34. ALTER TABLE UESRS ADD PRIMARY KEY (ID);
                            35.  
                            36.  
                            37. /******************************************************************************/
                            38. /*** Triggers ***/
                            39. /******************************************************************************/
                            40.  
                            41.  
                            42.  
                            43. SET TERM ^ ;
                            44.  
                            45.  
                            46.  
                            47. /******************************************************************************/
                            48. /*** Triggers for tables ***/
                            49. /******************************************************************************/
                            50.  
                            51.  
                            52.  
                            53. /* Trigger: UESRS_BI */
                            54. CREATE OR ALTER TRIGGER UESRS_BI FOR UESRS
                            55. ACTIVE BEFORE INSERT POSITION 0
                            56. as
                            57. begin
                            58. if (new.id is null) then
                            59. new.id = gen_id(gen_uesrs_id,1);
                            60. end
                            61. ^
                            62.  
                            63. SET TERM ; ^
                            64.  
                            65.  
                            66.  
                            67. /******************************************************************************/
                            68. /*** Privileges ***/
                            69. /******************************************************************************/
                            70.  
                              Михаиллл
                              • 18 сентября 2019 г. 22:49

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

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

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

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

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

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

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

                                    1. SELECT GEN_ID(GEN_UESRS_ID , 1) FROM RDB$DATABASE

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

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

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

                                      1. SET TERM ^ ;
                                      2. CREATE OR ALTER PROCEDURE adduser (name VARCHAR(1024), phone VARCHAR(1024), password VARCHAR(1024), rating float)
                                      3. return (user_id integer)
                                      4. as
                                      5. DECLARE VARIABLE user_id;
                                      6. begin
                                      7. user_id = GEN_ID(GEN_USERS_ID,1);
                                      8. insert into USERS (ID,PHONE,NAME, PASSWORD,RATING)
                                      9. values(:user_id, phone, name, password, rating);
                                      10. end^
                                      11. SET TERM ; ^

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

                                                            1. SET TERM ^ ;
                                                            2. CREATE OR ALTER PROCEDURE adduser (name VARCHAR(1024), phone VARCHAR(1024), password VARCHAR(1024), rating float)
                                                            3. returns (user_id integer)
                                                            4. as
                                                            5. DECLARE VARIABLE user_id integer;
                                                            6. begin
                                                            7. user_id = GEN_ID(GEN_USERS_ID,1);
                                                            8. insert into USERS (ID,PHONE,NAME, PASSWORD,RATING)
                                                            9. values(:user_id, phone, name, password, rating);
                                                            10. end^
                                                            11. SET TERM ; ^

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

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

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

                                                                Михаиллл
                                                                • 19 сентября 2019 г. 14: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 г. 14:13

                                                                  А если так

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

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

                                                                    1. SET TERM ^ ;
                                                                    2. CREATE OR ALTER PROCEDURE adduser (name VARCHAR(1024), phone VARCHAR(1024), password VARCHAR(1024), rating float)
                                                                    3. returns (out_user_id integer)
                                                                    4. as
                                                                    5. DECLARE VARIABLE user_id integer;
                                                                    6. begin
                                                                    7. user_id = GEN_ID(GEN_UESRS_ID,1);
                                                                    8. out_user_id = :user_id;
                                                                    9. insert into UESRS (ID,PHONE,NAME, PASSWORD,RATING)
                                                                    10. values(:user_id, :phone, :name, :password, :rating);
                                                                    11. end^
                                                                    12. SET TERM ; ^

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

                                                                    1. query.prepare("execute procedure adduser(:name, :phone, :password, :rating)");
                                                                    2. query.bindValue(":name", "UserNotRegistered");
                                                                    3. query.bindValue(":phone", "UserNotRegistered");
                                                                    4. query.bindValue(":password", "UserNotRegistered");
                                                                    5. query.bindValue(":rating", 0);
                                                                    6.  
                                                                    7. if(!query.exec())
                                                                    8. {
                                                                    9. emit sig_error(query.lastError().text());
                                                                    10. qDebug()<<"не записалось";
                                                                    11. qDebug()<<"query.lastError().text() : "<<query.lastError().text();
                                                                    12. msg = "false";
                                                                    13. }
                                                                    14. else if(query.next()) {
                                                                    15. qDebug()<<"Ok";
                                                                    16. qDebug()<<"query.value(0):"<<query.value(0).toString();
                                                                    17. msg = "true";
                                                                    18. }

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

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

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

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

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

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

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

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

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

                                                                              Комментарии

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