sql select with argument which can be NULL - sql

What is the best way to have a select query which has an argument which can be NULL depending on some variable in the program?
I can think of two solutions (pseudocode):
bool valueIsNull;
int value;
query = "SELECT * FROM table WHERE field ";
if (valueIsNull)
{
query += "IS NULL";
}
else
{
query += "= ?";
}
statement st = sql.prepare(query);
if (!valueIsNull)
{
st.bind(0, value);
}
or
bool valueIsNull;
int value;
query = "SELECT * FROM table WHERE field = ? OR (? IS NULL AND field IS NULL)";
statement st = sql.prepare(query);
if (valueIsNull)
{
st.bindNull(0);
st.bindNull(1);
}
else
{
st.bind(0, value);
st.bind(1, value);
}
It is a lot of code for just a simple SELECT statement and I find it just ugly and unclear.
The cleanest way would be something like:
bool valueIsNull;
int value;
query = "SELECT * FROM table WHERE field = ?"; // <-- this does not work
statement st = sql.prepare(query);
st.bind(0, value, valueIsNull); // <-- this works
Obviously this does not work. But is there a clean way to handle this?
I do not think it matter much but I am using C++, cppdb and postgresql.

With Postgresql (but I believe not standard) you can use
SELECT * from some_table where field IS NOT DISTINCT FROM ?;
IS NOT DISTINCT FROM, unlike plain =, is true when both sides are NULL.

As you've noted, the main problem with this:
SELECT * FROM table WHERE field = ? OR (? IS NULL AND field IS NULL)
is that it is actually two parameters which need to be bound.
You can get around that with a (should be fairly portable) construct like:
SELECT *
FROM table
INNER JOIN (SELECT ? AS param1 /* FROM DUAL */) AS params
ON 1 = 1
WHERE field = param1
OR COALESCE(param1, field) IS NULL

Related

ActiveJDBC , How can i query some columns i interest with in a single table

when i query a single table , i do not want all columns , i just want some column that i interest in.
For example, when i use where method to query a table, it will query all columns in a table like
public class SubjectSpecimenType extends Model {
}
SubjectSpecimenType.where("SUBJECT_ID = ? AND SITE_ID = ?", subjectId, siteId);
i don't know if there has a method named select that i can use to query some column like
SubjectSpecimenType.select("SUBJECT_NAME", "SITE_NAME").where("SUBJECT_ID = ? AND SITE_ID = ?", subjectId, siteId);
there are the source code in LazyList.java
/**
* Use to see what SQL will be sent to the database.
*
* #param showParameters true to see parameter values, false not to.
* #return SQL in a dialect for current connection which will be used if you start querying this
* list.
*/
public String toSql(boolean showParameters) {
String sql;
if(forPaginator){
sql = metaModel.getDialect().formSelect(null, null, fullQuery, orderBys, limit, offset);
}else{
sql = fullQuery != null ? fullQuery
: metaModel.getDialect().formSelect(metaModel.getTableName(), null, subQuery, orderBys, limit, offset);
}
if (showParameters) {
StringBuilder sb = new StringBuilder(sql).append(", with parameters: ");
join(sb, params, ", ");
sql = sb.toString();
}
return sql;
}
when call formSelect method, the second param columns always be null
is there a unfinish TODO ?
When operating on Models, ActiveJDBC always selects all columns, because if you load a model and it has partial attributes loaded, then you have a deficient model. The columns are specified in some edge cases, as in the RawPaginator: https://github.com/javalite/javalite/blob/e91ebdd1e4958bc0965d7ee99e6b7debc59a7b85/activejdbc/src/main/java/org/javalite/activejdbc/RawPaginator.java#L141
There is nothing to finish here, the behavior is intentional.

Breaking up a static string sql command into the command portion and seperate parameters

I have a static string with parameters, being sent to an SQL Execute command.
The strings have the format of delete 'Name' from table where x = 1 and y = 2 or select * from table where x = 1 and y = 2.
My problem is that I need to break the string into parameters.
How do I break the strings so that I can pass the command with the parameters to a single functional with the least possible work?
I have only one function to fix and handle this problem.
From this:
protected object ExecuteScaler(string queryString)
{ OpenConnection(); }
DbCommand command = _provider.CreateCommand();
command.Connection = _connection; command.CommandText = queryString; command.CommandType = CommandType.Text; if (_useTransaction) {
command.Transaction = _transaction; }
try { returnValue = command.ExecuteScalar(); } ...
Can someone please give me an example?
When you build a sql-command like this:
// don't do this because of sql injection
sql = "SELECT * FROM MyTable WHERE Col2 = " + somevalue;
Where you "break out of" the string constant to place a value, that is the point where you want to use a parameter placeholder:
// safe from sql injection
sql = "SELECT * FROM MyTable WHERE Col2 = #somevalue";
And then you can supply the value for #somevalue using the Parameters collection.
When the query needs some fixed values, then it is probably OK to keep them in the string:
// the "type" never changes for this query:
sql = "SELECT * FROM MyTable WHERE type=1 and Col2 = #somevalue";

How to use where when variable not null

I want use where when input variable is not null.
For example, when #custid is not null create this query:
Select *
from customers
where custid = #custid
and when #custid is null, then use this query instead:
Select *
from customers
How can I do this?
I searched on google, but haven't found any similar answer. Thanks
You can use the following query:
Select *
from customers
where #custid IS NULL OR custid=#custid
In this case if your variable is null only the condition #custid IS NULL will be evaluated and you get query identical to Select * from customers
If your variable is not null then condition #custid IS NULL is false and your query is identical to Select * from customers where custid=#custid
I use a SqlBuilder class and provide filters that attach the WHERE clauses programmatically.
So the SqlBuilder class would look like this:
public class Program
{
public static void Main()
{
Console.WriteLine(SqlBuilder.GetSql(null));
Console.WriteLine(SqlBuilder.GetSql("CUSTOMER_ID"));
}
public class SqlBuilder{
private static string _baseSql = "select * from customers";
public static string GetSql(string customerId){
var final = _baseSql;
if(customerId != null)
final += " WHERE custId=#custId";
return final;
}
}
}
This can also be made generic through the use of parameters and enums.

Is there any advantage to PreparedStatement#setInt vs inline SQL?

I've read Give me Parameterized SQL or give me death numerous times.
The advantage of Parameterized SQL for Strings, Dates, and floating-point numbers is very obvious and indisputable.
My question is: what about ints?
I ask because, oftentimes, if I'm writing a query or update and the only parameter is an int, I'll just write an inline sql and append the int as a shortcut ("select * from table where id = " + id).
My question: Are there any advantages to using Parameterized SQL for ints alone?
To illustrate with Java:
Are there any advantage to this:
Connection conn;
int id;
String sql = "select * from table where id = ?";
try (PreparedStatement p_stmt = conn.prepareStatement(sql)) {
p_stmt.setInt(1, id);
ResultSet results = p_stmt.executeQuery();
// ...
} catch (SQLException e) {
// ...
}
over this:
Connection conn;
int id;
String sql = "select * from table where id = " + id;
try (Statement stmt = conn.createStatement()) {
ResultSet results = stmt.executeQuery(sql);
// ...
} catch (SQLException e) {
// ...
}
I would say the biggest advantage would be consistency. If you decide that all SQL built by string concatenation is "wrong", it's easier to verify that your code is "right", compared to a rule like "All SQL built by string concatenation is wrong, except that which deals with ints as parameters".
Another case, say: down the line, you want to introduce sorting or grouping to the query, suddenly, your line turns into something like this:
String sql = "select * from table where id = " + id + " order by somecolumn";
And hopefully you remembered the space before order. And that everyone after you does also.
There is much to be said for doing things only one way, especially when that one way is the right thing most of the time.

Parameterized LIKE clause in SQL statement using Dapper

I want to perform the following query using Dapper, which currently doesn't return expected results (I think it must be treating the #pName param as literal text within the single quotes?):
var q = "SELECT * FROM Users WHERE Name LIKE '#pName%'";
#pName is the param I assign a value to upon executing the query.
Things work if I just build the SQL like:
var q = "SELECT * FROM Users WHERE Name LIKE '" + name + "%'";
.. but I would prefer to use a param if possible.
I am executing the query using the following code:
o = _cn.Query<User>(q, new { pName = new DbString { Value = name, IsFixedLength = false, Length = 25, IsAnsi = true } }).ToList();
How do I got about this using Dapper?
SELECT * FROM Users WHERE Name LIKE #pName + '%'
I would like to add here another possible solution:
var results = cn.Query("SELECT * FROM Table WHERE Column LIKE #value", new { value = value + "%" });
The wildcard is inside the string var itself, and then we reference that var in the SQL. Applies to any wildcard pattern you want.