Why does parameter count mismatch? - qt

From what I gather it's a mistake in your database/query and I've tried the following in DB Browser for Sqlite and it works:
UPDATE odgovori SET odgovor="1131" WHERE korisnik_ID="2" AND pitanje_ID="1";
INSERT INTO odgovori (korisnik_ID, pitanje_ID, odgovor) SELECT "2", "1", "1" WHERE (SELECT Changes()=0);
but, when I try this in QT:
Q_ASSERT(qry.driver()->hasFeature(QSqlDriver::NamedPlaceholders));
qry.prepare("UPDATE odgovori SET odgovor=:odgovor WHERE korisnik_ID=:korisnik_ID AND pitanje_ID=:pitanje_ID;"
"INSERT INTO odgovori (korisnik_ID, pitanje_ID, odgovor) SELECT :korisnik_ID, :pitanje_ID, :odgovor WHERE (SELECT Changes()=0);");
qry.bindValue(":odgovor", odgovor);
qry.bindValue(":korisnik_ID", id);
qry.bindValue(":pitanje_ID", QString::number(pitanjeid));
qry.exec();
qDebug()<<qry.lastError();
I get QSqlError("", "Parameter count mismatch", ""). I've tried with ? and qry.addBindValue and I get the same result. What am I missing?

As pointed out by #wthung in the comments, I tried manually inserting fixed numbers and the debugger throws QSqlError("21", "Unable to execute multiple statements at a time", "not an error")
So I broke the qry into two parts and it worked.
qry.prepare("UPDATE odgovori SET odgovor=:odgovor WHERE korisnik_ID=:korisnik_ID AND pitanje_ID=:pitanje_ID;");
qry.bindValue(":odgovor", odgovor);
qry.bindValue(":korisnik_ID", id);
qry.bindValue(":pitanje_ID", QString::number(pitanjeid));
qry.exec();
qry.prepare("INSERT INTO odgovori (korisnik_ID, pitanje_ID, odgovor) SELECT :korisnik_ID, :pitanje_ID, :odgovor WHERE (SELECT Changes()=0);");
qry.bindValue(":odgovor", odgovor);
qry.bindValue(":korisnik_ID", id);
qry.bindValue(":pitanje_ID", QString::number(pitanjeid));
qry.exec();

Related

In SQLite , How to SELECT a column only if it exists in the table

I am trying to write a query where the table will be generated dynamically for each job . And the columns will either exist or not based on input. In SQLite , i need to fetch the value of a column only if it exists otherwise null.
I tried with if & case statements using Pragma_table_info , but for negative scenario it is not working.
'''select
case when (select name from pragma_table_info('table_name') where name = col_name )is null
then error_message
else col_name'''
end
from table_name
This query is running if the mentioned col_name exists . But if not exists then it is throwing syntax error in else part.
Only in select query it should be done
Your code should work if the table's name, the column's name and the error message are properly quoted:
SELECT CASE
WHEN (SELECT name FROM pragma_table_info('table_name') WHERE name = 'col_name')
IS NULL THEN 'error_message'
ELSE 'col_name'
END
But you can do the same simpler with aggregation and COALESCE():
SELECT COALESCE(MAX(name), 'error_message')
FROM pragma_table_info('table_name')
WHERE name = 'col_name'
See the demo.

Can I use CASE WHEN outside of SELECT in SQLite/Conditional Structure in SQLite?

In SQL Server, I can use IF conditional structure to execute some statements if a condition is true. According to this and this, there seem to be no such structure in SQLite.
I want to check if a table exist, if it does, do nothing, if not, do a lot of things including creating tables, inserting and deleting data from other tables and updating as well:
CASE WHEN ((SELECT COUNT(*) FROM sqlite_master WHERE type = 'table' AND name = 'TraitsSwap') = 1) THEN
-- 50 lines of code, including CREATE, DROP, INSERT, DELETE and UPDATE statements, with random() in used
ELSE
-- Do nothing
END
Is there anyway I can achieve this? The code includes usage of random() and it requires consistent result (i.e, only random in the first time). I am sorry if this sounds unreasonable, but this is in context of game modding, so I cannot really change the backend code to run separated transaction code.
I think there may be an alternative if there is a function in SQLite that can execute a string/statement block and return a result. For that, I can transform the query into
SELECT CASE WHEN ((SELECT COUNT(*) FROM sqlite_master WHERE type = 'table' AND name = 'TraitsSwap') = 1) THEN
ExecuteCode("Code; RETURN 1;")
ELSE
0
END
I tried
SELECT CASE WHEN ((SELECT COUNT(*) FROM sqlite_master WHERE type = 'table' AND name = 'TraitsSwap') = 1) THEN
SELECT 1;
INSERT INTO Foo(Test) VALUES("");
SELECT "A";
ELSE
SELECT 1;
SELECT 2;
SELECT "A";
END
but it's unsuccessful, the error is
near "SELECT": syntax error: SELECT CASE WHEN ((SELECT COUNT(*) FROM
sqlite_master WHERE type = 'table' AND name = 'TraitsSwap') = 1) THEN
SELECT

Android SQLITE Insert into table with values coming from a subquery

In my db-driven app I need to perform insert into queries in which the value for one or more field comes from a subquery.
The insert into statement may look like the following example:
INSERT INTO MyTable (field_1, field_2)
VALUES('value for field 1', (SELECT field_x FROM AnotherTable WHERE ...))
At present I am doing it manually building the query:
String MyQuery = "INSERT INTO mytable (field_1, field_2)
VALUES('value for field 1', (SELECT field_x FROM AnotherTable WHERE ...))"; // Of course my query is far more complex and is built in several steps but the concept is safe, I end up with a SQL String
SQLiteDatabase= db = getWritableDatabase();
db.execSQL(MyQuery); // And it works flawlessy as it was a Swiss Clock
What i would like to do instead is:
SQLiteDatabase db = getWritableDatabase();
ContentValues values = new ContentValues();
values.put("field_1", "value for field 1");
values.put("field_2", ThisIsAQuery("(SELECT field_x FROM AnotherTable WHERE ...)"));
db.insert("MyTable", null, values);
db.close();
Where the fake method ThisIsAQuery(...) is the missing part, something that should tell the query builder that "SELECT.." is not a value but a query that should be embedded in the insert statement.
Is there a way to achieve this?
The whole point of the ContentValues container is to be able to safely use strings without interpreting them as SQL commands.
It is not possible to use subqueries with insert(). The only way to get a value from another table is by executing a separate query; in this case, ThisIsAQuery() would be stringForQuery() or longForQuery().

Corona SQLIte : Checking if a value exists or not

I would like to check if a value can be returned or not by my SQL request:
Search_IDItem = "SELECT * FROM giftshop WHERE id ="..item_id..""
for row_2 in db:nrows(Search_IDItem) do (..)
CheckInventory = "SELECT * FROM inventory WHERE code ="..row_2.code..""
if CheckInventory ~= nil then
print(row_2.code)
updateItemsCode(row_2.code, "inventory", "qtyoninventory", row_2.qtyoninventory+1)
else
insertInventory(2,row_2.code, row_2.name, row_2.src, row_2.desc, "no",row_2.qtyoninventory,row_2.price,row_2.usetxt)
end
The error is:
near "=": syntax error
Basicly, I would like to know if the value exist, I'll only update the field "quantity", if not, I will create the new item.
Unfortunately, it doesn't work! Is there any advice or solution?
Syntax error is a result of misunderstanding of your query by the SQL.
One of the most often reasons is incorrect string insertion. So I suppose that row_xx.code is a string
To solve the problem you should "quote" row_xx.code by ' symbol like this:
CheckInventory = "SELECT * FROM inventory WHERE code ='"..row_2.code.."'"
Update
To solve the second part of the problem and figure out if value exists I suggest following
In old good plain Java when I get SQLite Cursor I may check if it has rows at all like this:
if(cursor.moveToFirst())
// it has at least one value
else
// it hasn't values at all
Sure there is similar thing for Corona
You also may use following approach to update record (creating if not exists):
// create record IF NOT EXISTS:
String createNonExistentRec = "Insert or ignore into "...// insert key/unique values
db.execSQL(createNonExistentRec, ...);
// update values:
String updateQuery = "..."
...
I found a solution :
for x in db:urows "select count(*) from inventory" do
if x>0 then -- The inventory is empty
for w in db:urows("SELECT count (*) FROM inventory WHERE code ='"..row_2.code.."'") do
--The item is already in the inventory
if w > 0 then
CheckInventory = "SELECT * FROM inventory WHERE code ='"..row_2.code.."'"
for row_4 in db:nrows(CheckInventory) do
updateItemsCode(row_4.code, "inventory", "qtyoninventory", row_4.qtyoninventory+1)
end
else
--The item is not in the inventory, so we add it!
for maxid in db:urows("SELECT MAX(id) FROM inventory") do
insertInventory(maxid+1,row_2.code, row_2.name, row_2.src, row_2.desc, "no",1,row_2.price,row_2.usetxt)
end
end
end
else
insertInventory(1,row_2.code, row_2.name, row_2.src, row_2.desc, "no",1,row_2.price,row_2.usetxt)
end
end

Strange result with

When i run this as my first commend i get an exception an error near "last_insert_rowid". This is referring to the last last_insert_rowid();. If i set the curser to the line command.CommandText = and run it again it is fine.
What gives? The last_insert_rowid seems to be working properly why doesnt the last_insert_rowid after the 2nd insert work.
I tried moving last_insert_rowid() to after the execute and i still get an error. What gives?
using (var trans = connection.BeginTransaction())
{
command.CommandText =
"INSERT INTO link_list(link, status, hash_type, hash_id) " +
"VALUES(#link, #status, #hash_type, #hash_id);" +
"INSERT INTO active_dl(linkId, orderNo) " +
"VALUES(last_insert_rowid(), (SELECT COUNT(*) FROM active_dl)); last_insert_rowid();";
command.Parameters.Add("#link", System.Data.DbType.String).Value = link;
command.Parameters.Add("#status", System.Data.DbType.Int32).Value = SiteBase.Status.none;
command.Parameters.Add("#hash_type", System.Data.DbType.Int32).Value = 0;
command.Parameters.Add("#hash_id", System.Data.DbType.Int32).Value = 0;
int rowid = command.ExecuteNonQuery();
trans.Commit();
}
Why is the last last_insert_rowid() there? After the second insert you call last_insert_rowid with no select or anything to identify what you want to do with it.
You would have to put a select in front of it to retrieve the value wouldn't you?
You're trying to execute 2 sql commands in the one statement. You'll need to split the 2 statements up into 2 calls and return the inserted id from the first statement.
An alternative suggestion is a stored procedure but I don't think sqlite supports these.

Resources