qt select not working with where statement - sql

I'm using qt 4.8 and psql driver to connect to a postgres 9.1 database.
I'm doing a generic library to connect and insert into the database; almost all methods are ready but in the last one, I need to do a select from a table to insert values into another. When I try the select statement it behaves different. According to the code in turn but no one of the tests I made have resulted in a correct solution.
Here's my code:
struct enfriadores enf;
enf.horaE=time(&enf.horaE);
enf.horaS=time(&enf.horaS)+1900;
//base1.insertaEvento(db,enf);
QString consulta = "Select id_evento from eventos where extract(epoch from horae)=:hora_bus";
QDateTime hora_bus(QDateTime::fromTime_t(enf.horaE));
//qDebug()<< enf.horaE;
QSqlQuery query(db);
query.prepare(consulta);
query.bindValue(":hora_bus",hora_bus);
query.exec();
query.first();
while(query.next())
{
int valor = query.value(0).toInt();
qDebug() << valor << endl;
}
The base1.insertaEvento is a call from a class I did to insert data on the table where afterwards I'll need to extract the id. The
qDebug() << enf.horaE;
I put it to know if the time was in the right form before I attached it to the query, which by the way, was correct.
horaE is taken from a struct I have declaed in the previously mentioned class.
When I run the query as it is with the while(query.next()) it runs good but returns no results and if I delete the while loop but still maintain the query.next() compiler returns
QSqlQuery::value: not positioned on a valid record
0
I tried using the query.first() method and the query.setForwardOnly(true) but with same results.
Also if I try the value of hora_bus with qDebug() and replace it directly in the psql console I get a positive match so the problem is not in the way data is inserted or formatted, it's in the way the query is retrieved I believe but do not know how to resolve this
Any ideas?
Thanks

The SQL expression extract(epoch from horae) produces a number of seconds since 1/1/1970 so so that's what should be passed to the parameter :hora_bus.
The QDateTime::fromTime_t(enf.horaE) indicates that enf.horaE has this value, however instead of passing ot to the query, it's passing a QDateTime object whose text representation is probably going to be a string with year,month,etc... that can't be compared to a number of seconds.
So try this instead:
query.bindValue(":hora_bus",enf.horaE);
Also the code shouldn't ignore the boolean return values of prepare() and exec(). You don't want to try looping within results when the execution of the query has failed.
EDIT1:
indeed when passing a QDateTime set to today to a prepared query similar to yours, QSqlQuery::exec() returns false with an SQL error invalid input syntax for type double precision.
EDIT2: it appears QVariant doesn't support being initialized with a long so an explicit cast to a different supported type is necessary. I've chosen qlonglong for a safe larger value:
query.bindValue(":hora_bus",(qlonglong)enf.horaE);
Tested, it worked for me.

http://qt-project.org/doc/qt-4.8/qsqlquery.html#details
At the very end of the documentation it mentions the following:
Warning: You must load the SQL driver and open the connection before a QSqlQuery is created. Also, the connection must remain open while the query exists; otherwise, the behavior of QSqlQuery is undefined.
If the connection to the database is timing out, or one of the variables you are using goes out of scope, you might disconnect early and get undefined results.
You can also check the return values on most of your function calls to see if they were successful or not.
Hope that helps.

Related

BigQuery : Returning timestamp from JS udf throwing "Failed to coerce output value to type TIMESTAMP"

I have a bigquery code.
CREATE TEMP FUNCTION to_struct_attributes(input STRING)
RETURNS STRUCT<status_code STRING, created_time TIMESTAMP>
LANGUAGE js AS """
let res = JSON.parse(input);
res['created_time'] = Date(res['created_time'])
return res;
""";
SELECT
5 AS ID,
to_struct_attributes(
TO_JSON_STRING(
STRUCT(
TIMESTAMP(PARSE_TIMESTAMP('%Y%m%d%H%M%S', '20220215175959','America/Los_Angeles')) AS created_time
)
)
) AS ATTRIBUTES;
When I execute this, I'm getting the following error:
Failed to coerce output value "2022-02-16 01:59:59+00" to type TIMESTAMP
I feel this is quite strange, since BigQuery should be able to interpret it correctly and I haven't had this issue with any other datatypes. Also, if I do:
SELECT TIMESTAMP("2022-02-16 01:59:59+00")
It returns:
2022-02-16 01:59:59 UTC
So BigQuery can indeed parse it correctly. I'm not sure why it doesn't happen for the UDF. On searching the internet, I found this question and as the answer suggests, if I change the return statement to:
return Date(res.created_time);
It resolves the issue. But for a project of mine, doing it for every timestamp is not feasible due to the high number of struct columns.
So, I wanted to know if someone has a better alternative to it?
PS : I have removed a lot of non-essential parts from the above example, so this might look a bit abstract. Also, the actual use-case is a bit different and complex that's why I need that JS udf.
The best way to do what you want is to implement the following code.
return Date(res.created_time);
This happens when you pass a TIMESTAMP to a UDF, it is represented as a DATE object, as stated in the documentation. This is like a return of a TIMESTAMP from a JavaScript UDF, where you need to construct and return a DATE object.

libpqxx prepared statements nonnull checks for pointer types

I'm a newbie to SQL overall and libpqxx as well.I'm trying to build a basic application where I just need to use prepared statements to execute very simple jobs.
I have started with libpxx 4.0 version and I implemented codes like this:
pqxx::work txn( *conn );
auto result = txn.prepared( "my_insert" )( x->getId( ), x->isIdSet( ) )( x->getUser( ), x->isUserSet( ) )(x->getCreatedAt( ), x->isCreatedAtSet( ) ).exec( );
txn.commit();
Now I had to change to version 6.4 and realized the prepared function is deprecated and I should use the exec_prepared function. Okay. BUT I'm really missing the "nonnull" condition. For certain reasons I'm working with a lot of pointers and I need a convenient way to pass on these values to the database API. I could write something like:
auto result = txn.exec_prepared( "my_insert", (x->isIdSet() ? std::to_string(x-getId()) : "null"), ....);
This could work in some cases but when I try to insert "null" as string into a smallint field I get an sql error (what is reasonable though).
As types differ I can't use the ?: operator to return string/int/etc... on true branch and nullptr on false branch.
I couldn't find a proper documentation about the library. They have a doc here but if you want to find out more about a certain function there's literally nothing there.
Honestly even the deprecated .prepared(...) function doesn't work properly with 6.4 for me. I tried txn.prepared("whatever")(y->z->getA(), y->z != nullptr).exec() form and I got segmentation fault when y was a valid non-null pointer type and z was null-pointer. I expected the function wouldn't touch the value before checking on the condition but apparently it's not the case.
I have a prepared statement with 8 parameters 6 of them being a pointer type (shared_ptr) and it would be extremely messy if I have to come up with a ridiculous solution to check all the parameters one-by-one and having to write 200 lines just to be able to call this function properly.
Anyone out there having a proper solution? As I mentioned I'm a newbie so I might miss an important part there. Help me out please ^^
I know this question is old. But here's what you do:
const auto& id{ x->isIdSet()
? std::optional<std::string>{x-getId()} : std::nullopt };
auto result{ txn.exec_prepared("my_insert", id, ....) };

ERROR: function regexp_matches(jsonb, unknown) does not exist in Tableau but works elsewhere

I have a column called "Bakery Activity" whose values are all JSONs that look like this:
{"flavors": [
{"d4js95-1cc5-4asn-asb48-1a781aa83": "chocolate"},
{"dc45n-jnsa9i-83ysg-81d4d7fae": "peanutButter"}],
"degreesToCook": 375,
"ingredients": {
"d4js95-1cc5-4asn-asb48-1a781aa83": [
"1nemw49-b9s88e-4750-bty0-bei8smr1eb",
"98h9nd8-3mo3-baef-2fe682n48d29"]
},
"numOfPiesBaked": 1,
"numberOfSlicesCreated": 6
}
I'm trying to extract the number of pies baked with a regex function in Tableau. Specifically, this one:
REGEXP_EXTRACT([Bakery Activity], '"numOfPiesBaked":"?([^\n,}]*)')
However, when I try to throw this calculated field into my text table, I get an error saying:
ERROR: function regexp_matches(jsonb, unknown) does not exist;
Error while executing the query
Worth noting is that my data source is PostgreSQL, which Tableau regex functions support; not all of my entries have numOfPiesBaked in them; when I run this in a simulator I get the correct extraction (actually, I get "numOfPiesBaked": 1" but removing the field name is a problem for another time).
What might be causing this error?
In short: Wrong data type, wrong function, wrong approach.
REGEXP_EXTRACT is obviously an abstraction layer of your client (Tableau), which is translated to regexp_matches() for Postgres. But that function expects text input. Since there is no assignment cast for jsonb -> text (for good reasons) you have to add an explicit cast to make it work, like:
SELECT regexp_matches("Bakery Activity"::text, '"numOfPiesBaked":"?([^\n,}]*)')
(The second argument can be an untyped string literal, Postgres function type resolution can defer the suitable data type text.)
Modern versions of Postgres also have regexp_match() returning a single row (unlike regexp_matches), which would seem like the better translation.
But regular expressions are the wrong approach to begin with.
Use the simple json/jsonb operator ->>:
SELECT "Bakery Activity"->>'numOfPiesBaked';
Returns '1' in your example.
If you know the value to be a valid integer, you can cast it right away:
SELECT ("Bakery Activity"->>'numOfPiesBaked')::int;
I found an easier way to handle JSONB data in Tableau.
Firstly, make a calculated field from the JSONB field and convert the field to a string by using str([FIELD_name]) command.
Then, on the calculated field, make another calculated field and use function:
REGEXP_EXTRACT([String_Field_Name], '"Key_to_be_extracted":"?([^\n,}]*)')
The required key-value pair will form the second caluculated field.

How to execute SQL Script which may or may not return data?

This is an extension of an old question of mine where the answer wasn't quite what I was asking. What I'm doing is executing SQL Script on an MS SQL Server database. This script may or may not return any recordsets. The problem is that the way that ADO components work, at least to my knowledge, I can only explicitly request one or the other.
If I know a query will return data, I use TADOQuery.Open
If I know a query will not return data, I use TADOConnection.Execute
If I don't know whether query will return data or not... ???
How can I execute any query and read the response to determine whether it has any recordsets or not so I can read that recordset?
What I've tried:
Calling TADOQuery.Open, but raises exception if there's no recordset
Calling TADOQuery.ExecSql, but never returns any data
Calling TADOConnection.Execute, but never returns any data
Using Option 3 and reverting to Option 1 on exceptions, but this is double the work (script files over 38,000 lines) and kinda nasty.
Using TADOCommand.Execute, but keeps raising "Parameter object is improperly defined. Inconsistent or incomplete information was provided" on creating some stored procedures (which otherwise don't happen when using TADOConnection.Execute).
Calling TADOConnection.Execute overload which returns _Recordset, but then the TADOConnection.Errors returns empty (and I depend on this).
Just as some background, the purpose is to implement something like the SQL Query tool in the SQL Server Management Studio. It allows you to execute any SQL script, and if it returns any recordsets, it displays them, otherwise it just displays output messages. The tool I'm working on automatically breaks SQL Script at GO statements, and executes each individual block separately. Some of those blocks might return data, and others might not. It's already obvious that I cannot make this determination prior to execution, so I'm looking for a way to go ahead with the execution and observe the result. TADOConnection.Execute provides some useful information, including the Errors (or output messages).
As of now, the only option I have is to supply an option in the user interface to allow the user to choose which type of execution to use - but this is what I'm trying to eliminate.
EDIT
The TADOCommand.Execute method is the closest to what I want. However, it fails on some bits of script which otherwise work perfectly fine using TADOConnection.Execute. See #5 above in "What I've tried". I almost wrote that as my answer, until I found this error happens on almost everything.
EDIT
After posting my answer below, I then came to learn that the Errors property no longer returns anything when I use this other overload of Execute. See #6 above in "What I've tried".
Calling...
ADOConnection1.Execute('select * from something', cmdText, []);
...does not return anything in ADOConnection1.Errors, whereas...
var
R: Integer;
begin
ADOConnection1.Execute('select * from something', R);
...does return messages in ADOConnection1.Errors, which is what I need, but yet, doesn't return any recordsets.
EDIT: Not the right solution
I discovered my solution finally after digging even deeper. The answer is to use the TADOConnection.Execute() overload which supports returning the recordset:
function TADOConnection.Execute(const CommandText: WideString;
const CommandType: TCommandType = cmdText;
const ExecuteOptions: TExecuteOptions = []): _Recordset;
Then, just assign the resulting _Recordset to the Recordset property of supported dataset components.
var
RS: _Recordset;
begin
RS := ADOConnection1.Execute('select * from something', cmdText, []);
if Assigned(RS) then begin
ADODataset1.Recordset:= RS;
...
end;
end;
The downside is that you cannot use the other overload which supports returning the RowsAffected. Also, nothing is returned in the Errors property of the TADOConnection when using this overload version of Execute, whereas the other one does. But that other doesn't return a recordset.

Convert String Variable to Datetime Returns Incorrect Value in SSIS

Following my question in https://stackoverflow.com/questions/7387418/where-clause-using-date-taken-from-string-variable-sent-out-incorrect-return-in-s, this is the simplified version of the question:
The query used for the OLE DB Source is this, with a string type variable inside:
select
*
from
A
where
A.A_IN_DATETIME < CONVERT(DATETIME,?,105) and
(A.A_OUT_DATETIME is NULL or A.A_OUT_DATETIME >= CONVERT(DATETIME,?,105))
The query above works inside a Foreach Variable Enumerator, with the variable used is an array of string variable consisting of this: 13-09-2011,12-09-2011,11-09-2011,10-09-2011,09-09-2011,08-09-2011,07-09-2011,06-09-2011,05-09-2011,04-09-2011,03-09-2011,02-09-2011,01-09-2011
The condition for the problem is this: For example, there is a record in A with A_IN_DATETIME = 2011-09-12 (YYYY-MM-DD format) and A_OUT_DATETIME = NULL.
The correct result for the query above that it should have been only returning values for 13-09-2011 and the rest return 0 records, but in the execution, there was a result for 12-09-2011 to 10-09-2011 also. I don't know if the SSIS somehow mistaken the 12-09-2011, 11-09-2011, 10-09-2011 to 09-12-2011,09-11-2011,09-10-2011 (FYI, I've checked the parsing result and also the loop enumerator by printing it out in a message box generated from the script task, and it is still in its correct form).
Is there any solution for this problem?
Run Sql Profiler and see what query comes through to SQL Server. This will allow you to re-run the exact query in SSMS and see the results right there.
I don't believe conversion to DATETIME accepts a format, i.e. 105.Try this instead:
CONVERT(DATETIME, '9/13/2011 15:37:00')
Result is DATETIME - 2011-09-13 15:37:00.000