SQL - ignore where clause if null / no input - sql

I'm building a SSRS report and would like one of my parameters to be optional where data is entered or not.
Here is an example query for a better understanding:
SELECT
C1
,C2
,C3
FROM
db_Database..tb_Table
WHERE
tb_Table_DateTime between [THEN] and [NOW]
AND
tb_Table_Integer IN (#Integer)
I'm trying to work out if, in my query, I can ignore the whole:
AND tb_Table_Integer IN (#Integer)
line if user chooses not to input any number.
Bascially, I want all data returned unless specified otherwise via #integer.
If not possible in the query, can this be achieved in the Visual Studio?
Cheers.

This is typically handled by doing:
WHERE . . . AND
(#Integer IS NULL OR tb_Table_Integer = #Integer)
Do not use IN (#Integer). It sort of implies that you think that #Integer could be a list. That is not possible.

The most common way to do this is with coalesce or nullif. Like this:
WHERE coalesce(#integer,tb_Table_Integer) = tb_Table_Integer

Related

Querying full and sub-strings via multi-valued parameter using SQL

I am building a report with Microsoft SSRS (2012) having a multi-value parameter #parCode for the user to filter for certain codes. This works perfectly fine. Generally, my query looks like this:
SELECT ...
FROM ...
WHERE
TblCode.Code IN (#Code)
ORDER BY...
The codes are of following type (just an excerpt):
C73.0
C73.1
...
C79.0
C79.1
C79.2
Now, in additon to filtering for multiple of these codes I would like to als be able to filter for sub-strings of the codes. Meaning, when the user enters (Example 1)
C79
for #parCodes The output should be
C79.0
C79.1
C79.2
So eventually the user should be able to enter (Example 2)
C73.0
C79
for #parCodes and the output would be
C73.0
C79.0
C79.1
C79.2
I managed to implement both functionalities seperately, so either filtering for multiple "complete" codes or filterting for sub-string of code, but not both simultaneously.
I tried to do something like
...
WHERE
TblCode.Code IN (#parCode +'%')
ORDER BY...
but this screws up the Example 2. On the other hand, if I try to work with LIKE or = instead of IN statement, then I won't be able to make the parameter multi-valued.
Does anyone have an idea how to realize such functionality or whether IN statement pared with multi-valued parameters simply doesn't allow for it?
Thank you very much!
Assuming you are using SQL server
WHERE (
TblCode.Code IN (#parCode)
OR
CASE
WHEN CHARINDEX('.', Code)>0 THEN LEFT(TblCode.Code, CHARINDEX('.', TblCode.Code)-1)
ELSE TblCode.Code
END IN (#parCode)
)
The first clause makes exact match so for your example matches C73.0
The second clause matches characters before the dot character so it would get values C79.0, C79.1, C79.2 etc
Warning: Filtering using expressions would invalidate the use of an index on TblCode.Code

PyPika control order of with clauses

I am using PyPika (version 0.37.6) to create queries to be used in BigQuery. I am building up a query that has two WITH clauses, and one clause is dependent on the other. Due to the dynamic nature of my application, I do not have control over the order in which those WITH clauses are added to the query.
Here is example working code:
a_alias = AliasedQuery("a")
b_alias = AliasedQuery("b")
a_subq = Query.select(Term.wrap_constant("1").as_("z")).select(Term.wrap_constant("2").as_("y"))
b_subq = Query.from_(a_alias).select("z")
q = Query.with_(a_subq, "a").from_(a_alias).select(a_alias.y)
q = q.with_(b_subq, "b").from_(b_alias).select(b_alias.z)
sql = q.get_sql(quote_char=None)
That generates a working query:
WITH a AS (SELECT '1' z,'2' y) ,b AS (SELECT a.z FROM a) SELECT a.y,b.z FROM a,b
However, if I add the b WITH clause first, then since a is not yet defined, the resulting query:
WITH b AS (SELECT a.z FROM a), a AS (SELECT '1' z,'2' y) SELECT a.y,b.z FROM a,b
does not work. Since BigQuery does not support WITH RECURSIVE, that is not an option for me.
Is there any way to control the order of the WITH clauses? I see the _with list in the QueryBuilder (the type of variable q), but since that's a private variable, I don't want to rely on that, especially as new versions of PyPika may not operate the same way.
One way I tried to do this is to always insert the first WITH clause at the beginning of the _with list, like this:
q._with.insert(0, q._with.pop())
Although this works, I'd like to use a PyPika supported way to do that.
In a related question, is there a supported way within PyPika to see what has already been added to the select list or other parts of the query? I noticed the q.selects member variable, but selects is not part of the public documentation. Using q.selects did not actually work for me when using our project's Python version (3.6) even though it did work in Python 3.7. The code I was trying to use is:
if any(field.name == "date" for field in q.selects if isinstance(field, Field))
The error I got was as follows:
def __getitem__(self, item: slice) -> "BetweenCriterion":
if not isinstance(item, slice):
> raise TypeError("Field' object is not subscriptable")
Thank you in advance for your help.
I could not figure out how to control the order of the WITH clauses after calling query.with_() (except for the hack already noted). As a result, I restructured my application to get around this problem. I am now calling query.with_() before building up the rest of the query.
This also made my related question moot, because I no longer need to see what I've already added to the query.

Why am I getting a `Data type mismatch` error when I add "CF" to the end of my search string in a SQL statement in Access?

The following query (qryCurLotNewProducts) produces a data set that I want process further with another query (qryBNP_CFRecordset):
//qryCurLotNewProducts
SELECT tblNewProducts.*
FROM tblNewProducts INNER JOIN tblCurLot ON (tblCurLot.CatalogNum = tblNewProducts.CatalogNum) AND
(tblNewProducts.LotNum = tblCurLot.CurLot);
When I run this second query to list only the "CF" products found in the first query, I get the `Data type mismatch in criteria expression' error.
//qryBNP_CFRecordset
SELECT qryCurLotNewProducts.*, tblABCategory.UNSPSC, tblAmount.ProductSize
FROM tblAmount RIGHT JOIN (tblABCategory RIGHT JOIN qryCurLotNewProducts ON tblABCategory.ABCategory = qryCurLotNewProducts.ABCategory) ON tblAmount.Amount = qryCurLotNewProducts.Amount
WHERE (((qryCurLotNewProducts.CatalogNum) Like "A700-###CF") AND ((qryCurLotNewProducts.DateEntered) Between #1/1/2000# And #3/1/2020#))
ORDER BY qryCurLotNewProducts.CatalogNum, Abs(qryCurLotNewProducts.LotNum);
If I remove the CF from the search string (so "A700-###"), the query correctly outputs a list containing all items that contain that pattern:
If I use strings like "A700-####F" or "A700-###ZZ" or other combinations like that, I don't get an error but rather an empty results set.
Notably, "A700-001CF", "A700-002CF", etc all create the data type error. It seems there is something about the CF key combination that is causing trouble.
Has anybody else ever seen this issue? Do I need to use some kind of delimiter to tell SQL to not view CF as some kind of special switch?
Abs(qryCurLotNewProducts.LotNum) wont work with the values for Products ending in CF. Your LotNum-Column has a text-type.
Edit: Your LotNum-Column has a text-type as you can see in your first screenshot.

How can I write a WHERE statement that looks for a variable OR Null?

I am attempting to write a query for an Altiris report. This query is looking for machine information. The query works fine, however the problem I am running into is with my parameters. I have set up multiple parameters within Altiris to allow me to filter and search through the report for multiple fields. Then, in my query, I add those parameters into the WHERE statements.
All of the parameters were working fine, until I added Make and Model parameters. We have quite a few machines that do not have information populated into these fields. So when I add in the WHERE xxxx LIKE N'%Make%', I lose about 500 machines based on it now only looking for machines with something in that field. I tried to fix this by adding lines like the following:
Where ((xxxx LIKE N'%Make%' OR xxxx is null))
This kind of worked, in that now the report shows all machines... But if I enter "HP" into the Make parameter field and then rerun the report... it shows all HP machines like I want, but also all of the null machines as well.
How can I rewrite my where statements so that they do not exclude machines in the report, and allow me to filter by all HP machines, without showing null values as well?
Hope this made sense, and thank you
In this snip of code, the last two lines make me lose about 500 machines in my total machine count of the report. It is omitting all machines that have null values.
WHERE
(dbo.OS_Version.[OS Name] LIKE N'%OSName%') AND
(dbo.OS_Version.[OS Version] LIKE N'%Build%') AND
(dbo.OS_Version.Name LIKE N'%Name%') AND
(dbo.Inv_AeX_AC_Identification.[Hardware Serial Number] LIKE N'%Serial%') AND
(dbo.vHWComputerSystem.Manufacturer LIKE N'%Make%') AND
(dbo.vHWComputerSystem.Model LIKE N'%Model%')
This is how I tried to fix it, and now I get all 20,000 machines. But my make/model fields report on null fields as well.
WHERE
(dbo.OS_Version.[OS Name] LIKE N'%OSName%') AND
(dbo.OS_Version.[OS Version] LIKE N'%Build%') AND
(dbo.OS_Version.Name LIKE N'%Name%') AND
(dbo.Inv_AeX_AC_Identification.[Hardware Serial Number] LIKE N'%Serial%') AND
((dbo.vHWComputerSystem.Manufacturer LIKE N'%Make%') OR (dbo.vHWComputerSystem.Manufacturer is null)) AND
((dbo.vHWComputerSystem.Model LIKE N'%Model%') OR (dbo.vHWComputerSystem.Model is null))
I'm guess that if you don't enter a value for a parameter, it's coming through as an empty string, and of course, every varchar is LIKE '%%'.
I'm not sure what RDBMS this is, but if the ISNULL function is available, try this:
where ((ISNULL(xxxx,'') LIKE N'%Make%')
This replaces nulls with the empty string before doing the LIKE comparison.
I think you want something like this:
(cs.Manufacturer LIKE N'%#Make%' OR #Make = '') AND
(cs.Model LIKE N'%#Model%' OR #Model = '')
I am using = '' rather than IS NULL because you are clearly not passing in the parameters as NULL values (the LIKE wouldn't work).
This does not provide a method for filtering to get only the NULL values, because you are using the "special value" for the parameter to mean "don't apply a filter here".
Note that cs is intended as a table alias. I also strongly recommend that you use table aliases so your queries are easier to write and to read.
I think you're looking for something like WHERE ISNULL(Model, '') LIKE '%Model%'. However, you should replace '%Model%' with a variable. The above example would literally match the word 'Model'
DECLARE #Model NVARCHAR(100) = 'T-800'
...
WHERE ISNULL(Model, '') LIKE '%' + #Model + '%'
^ This would not include rows with NULL Model values

REGEXP Oracle SQL

I am having a clob field rq_dev_comments which should replace the username with "anonymous"
Update <TABLE>.req
Set rq_dev_comments = regexp_REPLACE(rq_dev_comments,
'\<[bB]\>.*gt;,', '<b>anonymous ')
where length(rq_dev_comments) > ...
Now my question is, if there is a way to check before wheather "anonymous" is already set or not and how to reduce the datasets?
Example:
rq_dev_comments = "<html><b>HendrikHeim</b>: I found an error....</html>"
Desired: "<html><b>Anonymous</b>: I found an error....</html>"
The following solution will not catch cases where "username" may appear more than once, and some but not all occurrences have already been replaced with "anonymous". So think twice before you use it. (The same would apply to ANY solutions along the lines of what you asked!)
Add the following to your WHERE clause:
... where length(...) ....
and dbms_lob.instr(rq_dev_comments, '<b>Anonymous') = 0
"= 0" means the search pattern wasn't found in the input string.
Another thing: In the example you show "anonymous" capitalized (with upper case A), but in your code you have it all lower case. Decide one way or another and be consistent. Good luck!