SQLite3 with C++ retrieve ID and store to another table - c++

Good evening people,
I am building a database using SQLite3 and C++ and I want to insert into table "Subs" as a foreign key, the ID which is the primary key for table "Programs". The table Programs has two columns, Id and programCode. I have the programCode in a variable so my approach is to get the Id from the programCode, store it into a variable and then store this in the table Subs. My problem is that I don't know how to get the result from query and store it into a variable. This is my code:
sqlite3_stmt *sql;
rc = sqlite3_prepare_v2(db, "SELECT Id FROM Programs WHERE programCode=?", -1, &sql, 0);
sqlite3_bind_text(sql, 1, _program.c_str(), -1, SQLITE_TRANSIENT);
int step = sqlite3_step(sql);
if(step == SQLITE_ROW) {
printf("%d\n", sqlite3_column_int(sql, 0));
}
The _program variable holds the programCode value.
Printf prints nothing and I expected to see the result of the query so I can use this to store it into an integer.
Any help would be highly appreciated.

Thanks to #CL for giving me this piece of information. I checked my csv where I retrieve the information for the database and the programCode had a "space" before the text so that is why there was no matching row. Thanks #CL!

Related

Retrieve Data from Database by Passing an ID, c++

I am trying to fetch data from my database giving it only an ID number. My database has 2 columns, first is ID, and second is an image path.
so if i pass ID=3, it should return the path corresponding to that ID.
I have tried to do that, but I am stuck at query.
mysql_query (conn, "SELECT * FROM table" );
res = mysql_use_result(conn);
row = mysql_fetch_row(res)
ID = atoi(row[0]);
path = row[1];
printf("ID: %i", ID);
printf("Image Path: %s", path);
Please help:)
I think the question is not really clear. First case, for each row you want to display id/path:
mysql_query (conn, "SELECT * FROM table" );
res = mysql_use_result(conn);
while (row = mysql_fetch_row(res)) {
ID = atoi(row[0]);
path = row[1];
printf("ID: %i", ID);
printf("Image Path: %s", path);
}
Other possibility, you want only one row because you know the ID you are looking for. Then you can decide to retrieve only the missing column with something like:
mysql_query (conn, "SELECT path FROM table WHERE id=ID" );
In some more complicated cases, lets say even if with the WHERE you may have multiple rows, you can keep only the first one for example by adding the TOP condition in your query. In any cases you need to think on what will be returned for real.
I didn't test the code I wrote, just edited a bit what you posted (just to be fair ^^)
You seem to have a few problems with basic computer concepts. For instance, the concept of having one thing versus more things. You fetch one row, but your database table has multiple rows and your query returns all rows. (No WHERE clause).
The obvious solution is to either fetch all rows, or (better) restrict your query to just the row you want.

Firebird/IBPP: How to retrieve ID generated by a database autoincrement?

I configured my firebird database to autoincrement the primary key of the table.
CREATE GENERATOR GEN_CHANNEL_PARAMETER_SET_ID;
SET GENERATOR GEN_CHANNEL_PARAMETER_SET_ID TO 0;
CREATE TRIGGER CHANNEL_PARAMETER_SETS_BI FOR CHANNEL_PARAMETER_SETS
ACTIVE BEFORE INSERT POSITION 0
AS
BEGIN
if (NEW.CHANNEL_PARAMETER_SET_ID is NULL) then NEW.CHANNEL_PARAMETER_SET_ID = GEN_ID(GEN_CHANNEL_PARAMETER_SET_ID, 1);
END
Now, in my C++ program using IBPP I have the following problem:
When inserting a dataset into an new row of this table I know all values in my C++ program exept the new primary key because the database creates it. How can I retrieve this key form the database?
Maybe someone else inserted an entry too - just a moment after I inserted one. So retrieve the PK with the highest value could create an error. How can I handle this?
Adopting Amir Rahimi Farahani's answer I found the following solution for my problem:
I use a generator:
CREATE GENERATOR GEN_CHANNEL_PARAMETER_SET_ID;
SET GENERATOR GEN_CHANNEL_PARAMETER_SET_ID TO 0;
and the following C++/IBPP/SQL code:
// SQL statement
m_DbStatement->Execute(
"SELECT NEXT VALUE FOR gen_channel_parameter_set_id FROM rdb$database"
);
// Retrieve Data
IBPP::Row ibppRow;
int64_t channelParameterSetId;
m_DbStatement->Fetch(ibppRow);
ibppRow->Get (1, channelParameterSetId);
// SQL statement
m_DbStatement->Prepare(
"INSERT INTO channel_parameter_sets "
"(channel_parameter_set_id, ...) "
"VALUES (?, ...) "
);
// Set variables
m_DbStatement->Set (1, channelParameterSetId);
...
...
// Execute
m_DbStatement->Execute ();
m_DbTransaction->CommitRetain ();
It is possible to generate and use the new id before inserting the new record:
SELECT NEXT VALUE FOR GEN_CHANNEL_PARAMETER_SET_ID FROM rdb$database
You now know the value for new primary key.
Update:
IBPP supports RETURNING too:
// SQL statement
m_DbStatement->Prepare(
"INSERT INTO channel_parameter_sets "
"(...) VALUES (...) RETURNING channel_parameter_set_id"
);
// Execute
m_DbStatement->Execute ();
m_DbTransaction->CommitRetain ();
// Get the generated id
m_DbStatement->Get (1, channelParameterSetId);
...
To retrieve the value of the generated key (or any other column) you can use INSERT ... RETURNING ....
For example:
INSERT INTO myTable (x, y, z) VALUES (1, 2, 3) RETURNING ID
Also a lot of drivers provide extra features to support RETURNING, but I don't know IBPP.
Note that from the perspective of a driver the use of RETURNING will make the insert act like an executable stored procedure; some drivers might require you to execute it in a specific way.

sql Column with multiple values (query implementation in a cpp file )

I am using this link.
I have connected my cpp file with Eclipse to my Database with 3 tables (two simple tables
Person and Item
and a third one PersonItem that connects them). In the third table I use one simple primary and then two foreign keys like that:
CREATE TABLE PersonsItems(PersonsItemsId int not null auto_increment primary key,
Person_Id int not null,
Item_id int not null,
constraint fk_Person_id foreign key (Person_Id) references Person(PersonId),
constraint fk_Item_id foreign key (Item_id) references Items(ItemId));
So, then with embedded sql in c I want a Person to have multiple items.
My code:
mysql_query(connection, \
"INSERT INTO PersonsItems(PersonsItemsId, Person_Id, Item_id) VALUES (1,1,5), (1,1,8);");
printf("%ld PersonsItems Row(s) Updated!\n", (long) mysql_affected_rows(connection));
//SELECT newly inserted record.
mysql_query(connection, \
"SELECT Order_id FROM PersonsItems");
//Resource struct with rows of returned data.
resource = mysql_use_result(connection);
// Fetch multiple results
while((result = mysql_fetch_row(resource))) {
printf("%s %s\n",result[0], result[1]);
}
My result is
-1 PersonsItems Row(s) Updated!
5
but with VALUES (1,1,5), (1,1,8);
I would like that to be
-1 PersonsItems Row(s) Updated!
5 8
Can somone tell me why is this not happening?
Kind regards.
I suspect this is because your first insert is failing with the following error:
Duplicate entry '1' for key 'PRIMARY'
Because you are trying to insert 1 twice into the PersonsItemsId which is the primary key so has to be unique (it is also auto_increment so there is no need to specify a value at all);
This is why rows affected is -1, and why in this line:
printf("%s %s\n",result[0], result[1]);
you are only seeing 5 because the first statement failed after the values (1,1,5) had already been inserted, so there is still one row of data in the table.
I think to get the behaviour you are expecting you need to use the ON DUPLICATE KEY UPDATE syntax:
INSERT INTO PersonsItems(PersonsItemsId, Person_Id, order_id)
VALUES (1,1,5), (1,1,8)
ON DUPLICATE KEY UPDATE Person_id = VALUES(person_Id), Order_ID = VALUES(Order_ID);
Example on SQL Fiddle
Or do not specify the value for personsItemsID and let auto_increment do its thing:
INSERT INTO PersonsItems( Person_Id, order_id)
VALUES (1,5), (1,8);
Example on SQL Fiddle
I think you have a typo or mistake in your two queries.
You are inserting "PersonsItemsId, Person_Id, Item_id"
INSERT INTO PersonsItems(PersonsItemsId, Person_Id, Item_id) VALUES (1,1,5), (1,1,8)
and then your select statement selects "Order_id".
SELECT Order_id FROM PersonsItems
In order to achieve 5, 8 as you request, your second query needs to be:
SELECT Item_id FROM PersonsItems
Edit to add:
Your primary key is autoincrement so you don't need to pass it to your insert statement (in fact it will error as you pass 1 twice).
You only need to insert your other columns:
INSERT INTO PersonsItems(Person_Id, Item_id) VALUES (1,5), (1,8)

SQLite INSERT command return error "column number is not unique"

I have a text file with rows (lines). Each row is a record in database table. I read this file and fill database.
Tables creating command:
CREATE TABLE gosts(number TEXT PRIMARY KEY, userNumber TEXT, status TEXT, date TEXT, title TEXT, engTitle TEXT, description TEXT, mainCategory INTEGER, category INTEGER, subCategory INTEGER);
Inserting query:
INSERT INTO gosts VALUES ("30331.8-95", "ÃÎÑÒ 30331.8-95", "Äåéñòâóþùèé", "01.07.1996", "Ýëåêòðîóñòàíîâêè çäàíèé. ×àñòü 4. Òðåáîâàíèÿ ïî îáåñïå÷åíèþ áåçîïàñíîñòè. Îáùèå òðåáîâàíèÿ ïî ïðèìåíåíèþ ìåð çàùèòû äëÿ îáåñïå÷åíèÿ áåçîïàñíîñòè. Òðåáîâàíèÿ ïî ïðèìåíåíèþ ìåð çàùèòû îò ïîðàæåíèÿ ýëåêòðè÷åñêèì òîêîì", "Electrical installations of buildings. Part 4. Protection for safety. Applisation of protective measues for safety. Measures of protection against electric shock", "Íàñòîÿùèé ñòàíäàðò óñòàíàâëèâàåò îáùèå òðåáîâàíèÿ ïî ïðèìåíåíèþ ìåð çàùèòû äëÿ îáåñïå÷åíèÿ áåçîïàñíîñòè è òðåáîâàíèÿ ïî ïðèìåíåíèþ ìåð çàùèòû îò ïîðàæåíèÿ ýëåêòðè÷åñêèì òîêîì ïðè ýêñïëóàòàöèè ýëåêòðîóñòàíîâîê çäàíèé", 37, 333, 628);
Please ignore encoding problems. Source file has cp1251 encoding, but inserting sample is taken from console. I tried to use utf-8 but had the same problem.
SQLite using code above:
if(sqlite3_prepare_v2(database, query, -1, &statement, 0) == SQLITE_OK) {
...
}
Function calling doesn't return SQLITE_OK. And I gea error message by:
string error = sqlite3_errmsg(database);
if(error != "not an error") cout << query << " " << error << endl;
Strangely, some records are inserted without error and I can't find differences between good and bad records.
I can provide more information if needed.
I would bet that the difference between the good and bad rows were whether or not the value associated with the 'number' column was already in the table.
This is one of the reasons that table designs usually do not use TEXT valued columns for PRIMARY KEYs.
If it is possible to re-create your table, I would create an ID field responsible for being the PRIMARY KEY for your table. Further enable the IDENTITY property for auto increment of your primary key value.
This should prevent insertion failure due to having duplicate values in the 'number' column.
Now if values in 'number' column must be unique then you should add a UNIQUE constraint on that column.
NOTE: The UNIQUE will yield the same error you are currently receiving as it appears you are trying to add multiple rows with the same value for column'number'
Review the SQLite CREATE TABLE documentation for more details.

Get column names in sqlite3

I would like to print my sql table contents and for that reason, I would like to retrieve the column name from the table. One solution I came across was :
SELECT sql FROM sqlite_master WHERE tbl_name = 'table_name' AND type = 'table'
But looks like I will have to parse the results.
Another suggestion was to use:
PRAGMA table_info(table_name);
but the below sqlite page suggests not to use this :
http://www.sqlite.org/pragma.html#pragma_full_column_names
Does there exists any way to achieve this. Also what would be the syntax to use
PRAGMA table_info(table_name);
Above solutions have been taken from here
Since your question is tagged c I assume you have access to the SQLite C API. If you create a prepared statement with one of the prepare_v2 functions that selects from the table you want you can use sqlite3_column_name to get the name of each column.
You can safely use PRAGMA table_info(table-name); since it's not deprecated in any way (yours post links to another pragma).
int sqlite3_get_table(
sqlite3 *db, /* An open database */
const char *zSql, /* SQL to be evaluated */
char ***pazResult, /* Results of the query */
int *pnRow, /* Number of result rows written here */
int *pnColumn, /* Number of result columns written here */
char **pzErrmsg /* Error msg written here */
);
If you are using c/c++, you can use the function sqlite3_get_table(db, query, result, nrow, ncol, errmsg);
Make the query as select * from table;
And the first few results result[0], result[1]...... will have the column names.
This setting will toggle showing column names as part of the return for select statements:
.headers on