JDBC on SQL Server, executeQuery() cannot find the result with null - sql-server

I use jdbc to retrieve data from SQL Server, and ANSI_NULLS is off . So if I run
select * from cj_log where evt = null
I can get the result.
But when I put it in a statement like this
Statement st = DBConnection.getConnection().createStatement();
String sql = "select * from CJ_LOG where EVT=null";
ResultSet rs = st.executeQuery(sql);
The result set is empty. What is the problem here?

You need to say
where EVT is null
Nothing is ever equal to null, even null.
Think of it like this: Null means "don't know".
You are asking "is something I don't know equal to something I don't know"
The answer is "I don't know". So you don't get any rows.

Related

Why does Snowflake LAST_QUERY_ID returns NULL?

Given the following procedure
CREATE OR REPLACE PROCEDURE z()
RETURNS STRING NOT NULL
LANGUAGE JAVASCRIPT
AS
$$
const what = snowflake.execute( {sqlText: "select $1 as value from values (1), (2), (3);"} )
return 'Hi There';
$$
;
If I run the 2 statements below
CALL z();
select * from table(result_scan(-2));
I get an error "SQL Error [709] [02000]: Statement 01912a0c-01c1-0574-0000-4de50036137e not found"
If I run the 2 statements below
CALL z();
SELECT LAST_QUERY_ID(), LAST_QUERY_ID(-1), LAST_QUERY_ID(-2);
It shows me that LAST_QUERY_ID() and LAST_QUERY_ID(-1) are identical but also that LAST_QUERY_ID(-2) returns NULL...
Any idea why it returns NULL rather than something that would allow me to retrieve the result of my query "select $1 as value from values (1), (2), (3);"?
Thanks
It shows me that LAST_QUERY_ID() and LAST_QUERY_ID(-1) are identical but also that LAST_QUERY_ID(-2) returns NULL
It's expected to see the same query ID for LAST_QUERY_ID() and LAST_QUERY_ID(-1), because they are same (the default value for LAST_QUERY_ID is "-1").
On the other hand, the LAST_QUERY_ID(-2) should not returns NULL, and the "select * from table(result_scan(-2))" query should not fail.
If you define the function with CALLER rights, you can see that the LAST_QUERY_ID(-2) returns the query ID and the "select * from table(result_scan(-2))" query works:
CREATE OR REPLACE PROCEDURE z()
RETURNS STRING NOT NULL
LANGUAGE JAVASCRIPT
EXECUTE AS CALLER
AS
$$
const what = snowflake.execute( {sqlText: "select $1 as value from values (1), (2), (3);"} )
return 'Hi There';
$$
;
As a workaround, you can use the history window to check the latest queries. You should be able to see your query (01912a0c-01c1-0574-0000-4de50036137e) in the history tab. You will notice that these queries are executed by same user, and in the same session. Therefore, there shouldn't be a restriction on listing these queries.
I am able to reproduce the issue on my test environment, and I will report the issue to the development team. If you have access to Snowflake support, it could be better to submit a support case regarding to this issue, so you can easily follow the process.
For the record, here is the answer I got from Snowflake Support
This is an expected behavior because of security limitation placed on purpose (queries from inside a SP do not have access to queries outside and vice versa).
We put a blanket limitation that the world of inside and outside such SPs should be separated. From one the "result" of a query from another cannot be accessed.
Yes, If we declare the procedure with caller rights, everything (LAST_QUERY_ID and RESULT_SCAN) works fine in this case.
There is a discussion going on to implement this use-case when the owner and caller of an "owner's right" SP are the same, all this limitations should be lifted. But we cannot be sure about the timeline, I can link this case with that discussion so that we have this record.
Sounds good to me :-)

c++ builder: getting values via ADOQuery using SELECT

The question is as for delphi coders as for c++ builder coders, cuz I'm using the same components.
I'm trying to fill labels on the form by the data from database. I do a SELECT query via TADOQuery. But when I try to get a result, I always get an error like "ADOQuery1: Field 'count' not found".
'id' passed to the function is an autoincrement field value, which is EXACTLY exists in database (it was got via DBLookupComboBox). Also, executing the query manually to show result in DBGrid is successfull.
Querying without parameters and writing 'id' value to query string fails too.
What's the problem? Here's the code.
void TSellForm::LoadData(int id) {
TADOQuery* q = DataModule1->ADOQuery1;
q->Active = false;
try
{
q->SQL->Text = "select * from drugs where(id=:id)";
q->Parameters->ParamByName("id")->Value = IntToStr(id);
q->ExecSQL();
this->LabelAvail->Caption = q->FieldByName("count")->Value;
}
catch (Exception* e) {
MessageBox(NULL, PChar(WideString(e->Message)),
L"Exception", MB_OK|MB_ICONWARNING);
}
q->SQL->Clear();
}
ExecSQL is only used for SQL statements that don't return a recordset, and to determine the results you use RowsAffected.
For SELECT statements (which return a recordset), you use Open or set Active to true.
Also, count is a reserved word in most SQL dialects (as in SELECT Count(*) FROM ..., so if you have a column with that name you're going to need to escape it, typically by using either [] or double-quotes around it or by aliasing it in the SELECT itself.
ADOQuery1->Close();
ADOQuery1->SQL->Text= "SELECT * FROM reportTble WHERE (firstName =:firstName) " ;
ADOQuery1->Parameters->ParamByName("firstName")->Value = textBox->Text ;
ADOQuery1->Open();
This is how you can use ADOQuery

How to pass a string literal parameter to a peewee fn call

I've got a issue passing a string literal parameter to a SQL function using peewee's fn construct. I've got an object defined as:
class User(BaseModel):
computingID = CharField()
firstName = CharField()
lastName = CharField()
role = ForeignKeyField(Role)
lastLogin = DateTimeField()
class Meta:
database = database
I'm attempting to use the mySQL timestampdiff function in a select to get the number of days since the last login. The query should look something like this:
SELECT t1.`id`, t1.`computingID`, t1.`firstName`, t1.`lastName`, t1.`role_id`, t1.`lastLogin`, timestampdiff(day, t1.`lastLogin`, now()) AS daysSinceLastLogin FROM `user` AS t1
Here's the python peewee code I'm trying to use:
bob = User.select(User, fn.timestampdiff('day', User.lastLogin, fn.now()).alias('daysSinceLastLogin'))
result = bob[0].daysSinceLastLogin
But when I execute this code, I get an error:
ProgrammingError: (1064, u"You have an error in your SQL syntax; check
the manual that corresponds to your MySQL server version for the right
syntax to use near ''day', t1.lastLogin, now()) AS
daysSinceLastLogin FROM user AS t1' at line 1")
Judging from this message, it looks like the quote marks around the 'day' parameter are being retained in the SQL that peewee is generating. And mySQL doesn't like quotes around the parameter. I obviously can't leave off the quotes in the python code, so can someone tell me what I'm doing wrong please?
Update: I have my query working as intended by using the SQL() peewee command to add the DAY parameter, sans quote marks:
User.select(User, fn.timestampdiff(SQL('day'), User.lastLogin, fn.now()).alias('daysSinceLastLogin'))
But I'm not sure why I had to use SQL() in this situation. Am I missing anything, or is this the right answer?
Is there a reason you need to use an SQL function to do this?
In part because I'm not very comfortable with SQL functions, I would probably do something like this:
import datetime as dt
bob = user.get(User = "Bob") #or however you want to get the User instance
daysSinceLastLogin = (dt.datetime.now() - bob.lastLogin).days

How to retrieve the value of uniqueidentifier generated while insert in Delphi ADO?

Suppose I generate the PK for my SQL Server DB table with the help of newid() function. In Java I can do something like this:
...
String query = "DECLARE #newGuid uniqueidentifier "+
"SET #newGuid = newid() "+
"INSERT INTO myTable(id, stringval) "+
"VALUES (#newGuid, "Hello") "+
"SELECT uid FROM #newGuid";
PreparedStatement ps = conn.prepareStatement(query);
ResultSet rs = ps.executeQuery();
String uid = rs.getString("uid");
But when I try to make that with Delphi+ADO I get stuck cause ADO can either get data from DB (Open method of AdoQuery) or put data to DB (ExecSQL method). So I can't insert new value to the table and get the parameter value afterwards.
You could solve this problem atleast in two ways.
You can put both of your SQL queries into one string (just like you have in your example) and call TADOQuery.Open or TADOQuery.Active := True. it doesn't matter that you have INSERT statement there as long as query returns something.
You can define parameter's direction as pdOutput in ADOQuery.Parameters collection and read value of that parameter after executing the query.
You are treating #newGuid as if it was a table. Your last row in the query should be:
SELECT #newGuid as uid

SqlCommand, passing something that could be null

I have a SQL command that I've been asked to modify, and I'm having some troubles with the fact that what I'm passing to the SQL can now be null. If I'm passing a value, I can rely on the columnName = #parameterName in the SQL, but with NULL, I can't pass null or DBNull and have it correctly resolve.
Here's the SQL pseudocode:
SELECT
Columns
FROM
ClientSetup
WHERE
Client_Code = #ClientCode AND
Package_Code = #PackageCode AND
Report_Code = #ReportCode
The problem is that now #ReportCode can validly be NULL. In my C# code where I set up the SqlCommand, I can put in:
cmd.Parameters.Add("#ReportCode", SqlDBType.VarChar, 5).Value = reportType;
//reportType is a string, which can be null
But, if reportType is null, I need to use Report_Code IS NULL in the SQL, rather than Report_Code = #reportCode.
The solution I've found is to change the last where clause to the following:
((#ReportCode IS NULL AND Report_Code IS NULL) OR Report_Code = #ReportCode)
and the parameter phrase to
cmd.Parameters.Add("#ReportCode", SqlDBType.VarChar, 5).Value = string.IsNullOrEmpty(reportType) ? System.DBNull : reportType;
What this does works, but I was wondering if anyone knew of a cleaner or better way to handle nullable parameters when passing things to SQL from .NET code.
The short answer is that no, the SqlClient API requires you to pass in a DbNull.Value for NULL parameter values.
But I have some doubts about how you treat NULLs. For one you use string.IsNullOrEmpty which means that you treat the emtpy string as a NULL. This is questionable, there may be legitimate empty string values in the database.
My second concern is the logic of matching NULLs in the database. More often than not passing in a NULL parameter means that the request is interested in any value, not specifically in NULL values. I'm not saying your logic of matching NULL parameters to NULL values is flawed, I just want to make sure you know what you're doing.
Much of a muchness, in the past I've built the query
test reportcode for null if is its replace ReportCode = #ReportCode with "ReportCode is Null"
add the reportcode parameter if it isn't.
Generally though ReportCode of null signalled I wanted to select based on the other parameters and didn't care what the null one was.
It's a bit naughty
but Where IsNull(ReportCode,'') = IsNull(#ReportCode,'')
would give you what you want, given you are using IsNullOrEmpty.
Well, is correct the way how you fix it
only is (#ReportCode IS NULL AND Report_Code IS NULL) not is neccesary. because it is not c# o c++.
Some how that should be finally result
SELECT
Columns
FROM
ClientSetup
WHERE
Client_Code = #ClientCode
AND Package_Code = #PackageCode
AND (Report_Code = #ReportCode or #ReportCode is null)

Resources