SSRS and PostgreSQL: How do I pass an optional parameter? - postgresql

I'm using a PostgreSQL ODBC data source in an SSRS report.
From my previous knowledge with MS SQL Server data sources, to pass an optional parameter to a SSRS dataset query, you would do this:
SELECT *
FROM MyTable
WHERE SomeField = #Param1 OR #Param1 IS NULL
The key was using OR #Param1 IS NULL which basically bypasses the SomeField = #Param1 part and effectively acts as an "optional" filter. However, this doesn't seem to work when using a PostgreSQL ODBC data source (not sure if it's due to Postgres or ODBC or both). I get an error when clicking on Refresh Fields, or when executing/previewing the report.
This might be partly due to not being able to pass named parameters into the SQL, but instead having to use "?" like so:
SELECT *
FROM MyTable
WHERE SomeField = ?
...which makes it impossible to do OR ? IS NULL basically.
So, anybody know how I might be able to pass optional parameters to a PostgreSQL data set in SSRS?

Not a specific ODBC solution but a workaround. This will work if SomeField can not be null:
select *
from mytable
where somefield = coalesce(?, somefield)
If SomeField can be null and you want to return nulls:
where somefield is not distinct from coalesce(?, somefield)
Check is distinct from

Related

Pass parameters to psql function [duplicate]

I'm trying to use a query where the schema and table are passed as parameters into a prepared statement using pg_query_params like this:
$searchSchema = 'mySchema';
$searchTable = 'myTable';
$searchColumn = 'searchColumn';
$searchValue = 'some value';
$selQuery = "SELECT *
FROM $1.$2 --fails here
WHERE someColumn like $3;";
$rs = pg_query_params($db, $selQuery , array($searchSchema, $searchTable, $searchColumn, $searchValue));
The issue is with the schema and table which need to be set dynamically - as in the code above.
In a parameterized SQL statement (which is a prepared statement in PostgreSQL), parameters can only stand for constant values, not for table or column names.
This limitation is enforced by PostgreSQL, and there is no way around it, no matter what programming language or driver you use. This is also intentional and not a bug.
You will have to compose a string that contains the complete SQL statement with table and column names substituted and execute that. Beware of SQL injection – use functions like pg_escape_identifier to escape names.

Changing Jet SQL IsNull to to SQL IsNull Function

I have a query in MS Access that I am trying to change to SQL view
One of the select statement part is
IIf(IsNull([Book ID]),-1,[Book ID]) AS SubBookID
Unlike in Access T-SQL wants 2 parameters for the IsNull function.
What I need to do is something like
IIf(IsNull([Book ID],true),-1,[Book ID]) AS SubBookID
But we cannot use true like that cause T-SQL thinks that it is a column name
you are going to check if [Book ID] is null or not. If it is null then you are going to return -1 else you are going to return the [Book ID].
To achieve this you need to right it as:
ISNULL([Book ID],-1) AS SubBookID
As you see you do not need the IIF function anymore in this situation.
Read more about ISNULL in T-SQL: https://learn.microsoft.com/en-us/sql/t-sql/functions/isnull-transact-sql?view=sql-server-2017

PreparedStatement setNull in SELECT query

I am using Postgresql together with HikariCP and my query is something like
SELECT * FROM my_table WHERE int_val = ? ...
Now, I would like to set NULL value to my variables - I have tried
ps.setNull(1, Types.INTEGER); // ps is instance of PreparedStatement
try (ResultSet rs = ps.executeQuery()) {
... // get result from resultset
}
Although I have rows matching the conditions ( NULL in column 'int_val'), I have not received any records..
The problem is (I think) in query produced by the Statement, looks like:
System.out.println(ps.toString());
// --> SELECT * FROM my_table WHERE int_val = NULL ...
But the query should look like:
"SELECT * FROM my_table WHERE int_val IS NULL ..." - this query works
I need to use dynamically create PreparedStatements which will contain NULL values, so I cannot somehow easily bypass this.
I have tried creating connection without the HikariCP with the same result, so I thing the problem is in the postgresql driver? Or am I doing something wrong?
UPDATE:
Based on answer from #Vao Tsun I have set transform_null_equals = on in postgresql.conf , which started changing val = null --> val is null in 'simple' Statements, but NOT in PreparedStatements..
To summarize:
try (ResultSet rs = st.executeQuery(SELECT * FROM my_table WHERE int_val = NULL)){
// query is replaced to '.. int_val IS NULL ..' and gets correct result
}
ps.setNull(1, Types.INTEGER);
try (ResultSet rs = ps.executeQuery()) {
// Does not get replaced and does not get any result
}
I am using JVM version 1.8.0_121, the latest postgres driver (42.1.4), but I have also tried older driver (9.4.1212). Database version -- PostgreSQL 9.6.2, compiled by Visual C++ build 1800, 64-bit.
It is meant behaviour that comparison x = null is equal to null (no matter what x is equal to). Basically for SQL NULL is unknown, not the actual value... To bypass it you can set transform_null_equals to on or true. Please checkout docs:
https://www.postgresql.org/docs/current/static/functions-comparison.html
Some applications might expect that expression = NULL returns true if
expression evaluates to the null value. It is highly recommended that
these applications be modified to comply with the SQL standard.
However, if that cannot be done the transform_null_equals
configuration variable is available. If it is enabled, PostgreSQL will
convert x = NULL clauses to x IS NULL.
I have just found a solution, which works the same for "values" and "NULLs" by using IS NOT DISTINCT FROM instead of =.
More on postgresql wiki
It is important to recognize that null is not a value with SQL. It is encoding the logical notion of "unknown". This is why null = var results in false always, even for cases where var has a value of null. So even if if you are replacing the value of your variable (aka ? in your case) with a value of null, the result be definition must not be what you do expect as long as SQL standard is complied with.
Now there are some databases around that try to outsmart SQL standard by assuming a column value of null should be taken as a programming language null (nil, undef or whatever is used for that purpose).
This creates some convenience for the unwary programmer, but in the long run causes grieve as soon as you need a true distinction between a SQL null and a programming language null.
Nevertheless, for ease of porting from such databases to PostgresQL (or simple for ease of lazy programming) you may resort to setting transform_null_equals.
BUT, you are using prepared statements. As such, prepared statements are converted to query plan once and such query plan needs to be valid for all potential values of the variables used in the prepared statement query. Now, a VAR is null is fundamentally different from a VAR = ?. So there is no chance for the query parser, query optimizer or even query execution engine to dynamically rewrite the (already prepared) query based on the actual parameter values passed in.
From this, you should take the recommendation serious that is given with the documentation of transform_null_equals and change your code to use VAR is null when a null value is to be searched for and a VAR = ? for other cases.

Multiple SQL queries in a report

The requirement is to generate a single report connecting to a single DB:
Query1 is a group by query and has a bar chart and pie chart based on it.
Query2 is a simple query on which a table gets created.
Both these queries need results based on a WHERE clause, which is supplied dynamically.
Can somebody point me to some examples on how to achieve this?
Thank you.
You can tell JasperReports to use a parameter to define part of the query using the $P!{PARAMETER_NAME} syntax. This tells JasperReports to use the literal value of PARAMETER_NAME as part of the query. You can then do:
Create a parameter named WHERE_CLAUSE in the report.
Give WHERE_CLAUSE a default value of 1=1.
Consider the following SQL statement:
SELECT * FROM table WHERE $P!{WHERE_CLAUSE}
The $P! expression changes the literal SQL statement to:
SELECT * FROM table WHERE 1=1
That is a valid query. Note the difference between $P{} and $P!{} -- the exclamation mark (!) is important.
You can then supply the SQL conditions dynamically.

make a column in sybase default to the current date/time of row insertion

I have a sybase 15 DB and for one of my tables, I want to make a column default to the current date/time of the row insert. Is this possible?
In a sybase text, the following is said:
ALTER TABLE sales_order
MODIFY order_date DEFAULT CURRENT DATE
On my DB this doesn't do anything, as CURRENT DATE is not recognized.
using getDate() is a valid solution, you must have had a syntax error. Try it like this:
create table test_tbl (
date_data DATETIME default getDate() NOT NULL
)
Try using getDate() instead
... DEFAULT GETDATE() is correct. the case is irrelevant; mixed case may indicate a Java method, but it is a straight TSQL Function. Please post the exact error msg if you want further assistance.
Also, the ALTER TABLE method sets the Default for future INSERTS; if you want the existing data changed, you need to UPDATE (good for small tables) or unload/reload the table (demanded for the large).
Watch the NULL/NOT NULL: you do not want to change that without understanding. Again, the existing/future issue needs address. NOT NULL prevents NULL being explicitly passed as an INSERT VALUE.
CURRENT_DATE is a SQL standard that isn't universally adopted.
As noted elsewhere the getdate() T-SQL function should be used instead.