SQL If parameter is null search all - sql

I have a JSF page where users can search by five options, and can choose how many of those options they search by (0-5). The database has no NULL values.
Currently I have a horrendous piece of code that builds that SQL statement, but I would like to just have one parameterized statement.
SELECT *
FROM table1
WHERE col1 = 'dave'
AND col2 = 'Smith'
AND col3 = '3/2/2014'
AND col4 = '12345'
AND col5 = '67890'
ORDER BY col5 DESC
Is there a way to detect an empty/null value in the search criteria e.g col5=''
And just return all results for that column?
So that if the search criteria was just col1='dave' then the statment would act as if the input was
SELECT *
FROM table1
WHERE col1 = 'dave'
ORDER BY col5 DESC

You can do this in SQL:
SELECT *
FROM table1
WHERE (col1 = #col1 or #col1 is null) and
(col2 = #col2 or #col2 is null) and
. . .
ORDER BY col5 DESC;
But, you may not want to. If you are using indexes to speed your searches, then the use of or can impede the use of the indexes in many databases (but apparently not in Oracle). This is also true of coalesce(), which could be used as:
WHERE col1 = coalesce(#col1, col1) and
col2 = coalesce(#col2, col2) and
. . .
If you are constructing the query anyway, then do it in the statement. The logic is like:
if #col1 is not null then
#where = concat(#where, " and col1 = '", #col1, "'")
end if;
if #col2 is not null then
#where = concat(#where, " and col2 = '", #col2, "'")
end if;
This will construct the correct where clause that can use available indexes.
There is one downside to this approach. You cannot pre-compile the statement for all parameter values. The statement would need to be recreated every time new values are input (this would normally be an acceptable amount of overhead because you are dealing with user input).

Try to use trim to change empty value '' to null and then use coalesce to replace null with value from col5 as below
SELECT *
FROM table1
WHERE col1 = 'dave'
AND col2 = 'Smith'
AND col3 = '3/2/2014'
AND col4 = '12345'
AND col5 = coalesce(trim('67890'),col5)
ORDER BY col5 DESC

SELECT *
FROM table1
WHERE (col1 = :col1 OR :col1 IS NULL)
AND (col2 = :col2 OR :col2 IS NULL)
AND (col3 = :col3 OR :col3 IS NULL)
AND (col4 = :col4 OR :col4 IS NULL)
AND (col5 = :col5 OR :col5 IS NULL)
ORDER BY col5 DESC
It is more convenient to use named parameter instead of "?" in JAVA

Related

SQL If-Else in the WHERE clause with conditions based on column values

How would you rewrite the WHERE clause in this pseudo-SQL?
SELECT *
FROM MyTable
WHERE IF ( Col1 <> '' ) Col1 = #Val1
ELSEIF ( Col2 <> '' ) Col2 = #Val2
The correct equivalent for your pseudo code is:
WHERE (Col1 <> '' AND Col1 = #Val1) OR
(Col1 = '' AND Col2 <> '' AND Col2 = #Val2)
This matches in priority order, first on Col1 and then on Col2. It only moves on to Col2 when Col1 is an empty string.
Note: This version assumes that Col1 is not NULL. That can easily be incorporated into the logic, if you need to support NULL values -- especially with a little guidance on how they should be handled.
Well, it is possible to do something like this using the CASE function:
SELECT *
FROM MyTable
WHERE 1 = CASE WHEN Col1 <> '' THEN CASE WHEN Col1 = #Val1 THEN 1 END
WHEN Col2 <> '' THEN CASE WHEN Col2 = #Val2 THEN 1 END
END
A case function returns a value. So, when 1 = 1, the condition is met. Since the ELSE parts of the case are left out, NULL is returned by the case when the condition is not met. Since 1 = null can never be true, the WHERE condition will not be met.
Sometimes the extra complexity added by code like this is not warranted - it would be up to your exact situation after checking for performance etc.
EDIT: added ELSE parts. These are not needed, but might make it clearer for some.
SELECT *
FROM MyTable
WHERE 1 = (CASE WHEN Col1 <> '' THEN (CASE WHEN Col1 = #Val1 THEN 1 ELSE 0 END)
WHEN Col2 <> '' THEN (CASE WHEN Col2 = #Val2 THEN 1 ELSE 0 END)
ELSE 0
END)
Assuming that I understood your logic correctly.
You want to match on either col1 = #val1 or col1 is a blank string
OR col2 = #val2 or col2 is a blank string.
SELECT *
FROM MyTable
WHERE (Col1 = #Val1 OR Col1 = '' )
OR (Col2 = #Val2 OR Col2 = '')

How to condense multiple update statement - SQL

I have an update statement for 10 columns which is replacing values in each of the column with a where condition to that specific column.
Here's the code:
UPDATE Table1
SET Col1 = REPLACE(Col1, '#DIV/0', NULL)
WHERE Col1 = '#DIV/0';
UPDATE Table1
SET Col2 = REPLACE(Col2, '#DIV/0', NULL)
WHERE Col2 = '#DIV/0';
UPDATE Table1
SET Col3 = REPLACE(Col3, '#DIV/0', NULL)
WHERE Col3 = '#DIV/0';
Like this I have it for 10 columns, it does the work but it doesn't look clear or professional.
I wanted to condense this code and make it look like a professional code.
Any suggestions is much appreciated.
Thanks!
I suggest you leave it as it is, with one change because statements such as REPLACE(Col1, '#DIV/0', NULL) do not make sense: calling REPLACE in sql server where any parameter is NULL always produces NULL, regardless if the text is found or not.
So best is this:
UPDATE Table1 SET Col1 = NULL WHERE Col1 = '#DIV/0';
UPDATE Table1 SET Col2 = NULL WHERE Col2 = '#DIV/0';
UPDATE Table1 SET Col3 = NULL WHERE Col3 = '#DIV/0';
Use case expressions keep the old value if it's not equal to '#DIV/0', the default else null will replace the '#DIV/0' values with NULL.
UPDATE Table1
SET
Col1 = case when Col1 <> '#DIV/0' then Col1 end,
Col2 = case when Col2 <> '#DIV/0' then Col2 end,
...
Note that all rows will be updated, i.e. one huge transaction. If that's a problem, either go back to your original solution with several updates, or add this at the end:
where '#DIV/0' in (Col1, Col2, ...)
If this is a good or bad idea depends on the data, how many percent of the rows/columns need to be updated. Indexes etc.
Assuming its T-SQL, why not just use NULLIF function
DECLARE ValToNull AS VARCHAR(10) = '#DIV/0'
UPDATE Table1
SET Col1 = NULLIF(Col1, ValToNull),
Col2 = NULLIF(Col2, ValToNull),
Col3 = NULLIF(Col3, ValToNull)

Select where in list or else select all most elegantly

For a select statement I set a part of the where condition externally in a configuration file as parameter, like this (COL2 is filled with string values):
SELECT COL1
,COL2
FROM TABLE1
WHERE COL2 = $external_parameter
Now I have a more complex case, where I need the external parameter to be a list. Whenever a value of COL2 is in the list, it should select, however if no list is provided or some kind of "empty" tag, every value should be selected again. I came up with an idea, but it does not work that way:
SELECT COL1
,COL2
FROM TABLE1
WHERE $external_list = ('') or COL2 IN $external_list
Like this, the statement would be true for all elements of COL2 when an empty list is provided, and true for every element in the list that matches with the list if a filled list is provided.
However, if I provide a filled list it will not work on the comparison in the first half of the where statement:
('entry_a', 'entry_b') = ('')
Is there any query that would make it work - best in a one line where statement?
Try something like this,
SELECT COL1
,COL2
FROM TABLE1
WHERE COL2 IN ($EXTERNAL_PARAMETER)
OR 1 = (
CASE
WHEN $EXTERNAL_PARAMETER = ''
THEN 1
ELSE 0
END
)
Try this way
SELECT COL1
,COL2
FROM TABLE1
WHERE COL2 IN (
CASE
WHEN $EXTERNAL_PARAMETER = ''
THEN COL2
ELSE $EXTERNAL_PARAMETER
END)
Try this
IF $EXTERNAL_PARAMETER = ''
SET $EXTERNAL_PARAMETER = NULL
SELECT COL1
,COL2
FROM TABLE1
WHERE COL2 = ISNULL($EXTERNAL_PARAMETER, COL2 )

remove first comma in string using sql

my string like that :
1 ,QCIM1J25836, QCIM1J27637
2 ,QCIM1J25836, QCIM1J27637, QCIM1J27638
I want to remove first comma only it means my output will be for
1 QCIM1J25836, QCIM1J27637
2 QCIM1J25836, QCIM1J27637, QCIM1J27638
may be in other will not be comma...so please tell me how can I update all data like that...
The following query should work:
It will update all the records in the column.
UPDATE table
SET col2 = CASE WHEN LEFT(col2 ,1) =',' THEN RIGHT(col2,LEN(col2)-1)
ELSE col2 END
UPDATE table
SET col2 = case when charindex(',',col2,0) =1 then right(col2, len(col2)-1) else col2 end
In SQL-Server you can do It in multiple ways.
You use STUFF in following:
SELECT col1,
STUFF(col2,1,1,'') as [Col Without First Comma]
FROM tbl
WHERE col2 LIKE ',%'
or you can use RIGHT
SELECT col1,
RIGHT(col2,LEN(col2)-1) as [Col Without First Comma]
FROM tbl
WHERE col2 LIKE ',%';
or you can use SUBSTRING
SELECT col1,
SUBSTRING(col2, 2, 255) as [Col Without First Comma]
FROM tbl
WHERE col2 LIKE ',%';
UPDATE
As per your comment you can update in the same ways too:
Using SUBSTRING
UPDATE tbl
SET col2 = SUBSTRING(col2, 2, 255)
WHERE col2 LIKE ',%';
Or using RIGHT
UPDATE tbl
SET col2 = RIGHT(col2,LEN(col2)-1)
WHERE col2 LIKE ',%';
Or using STUFF
UPDATE tbl
SET col2 = STUFF(col2,1,1,'')
WHERE col2 LIKE ',%';
USE [LIB]
CREATE FUNCTION [dbo].[trimChar]
(
#p_string varchar(max),
#p_char varchar(1)
)
RETURNS varchar(max)
AS
BEGIN
declare #l_string varchar(max) = #p_string
-- lets do the front
while SUBSTRING(#l_string,1,1) = #p_char
begin
set #l_string = substring(#l_string,2,len(#l_string))
end
-- lets do the back
set #l_string = reverse(#l_string)
while SUBSTRING(#l_string,1,1) = #p_char
begin
set #l_string = substring(#l_string,2,len(#l_string))
end
set #l_string = reverse(#l_string)
return #l_string
END
GO

How Can I optimize this query (OR inside AND validation)?

I'm having problems with this query:
SELECT col1, col2,col3,...,coln FROM MyTable
WHERE col1 = #value1
AND
(
ISNULL(col2,'c') = ISNULL(#value2,ISNULL(col2,'c'))
OR
ISNULL(col3,'c') = ISNULL(#value2,ISNULL(col3,'c'))
)
AND coln = 'valueN'
I have to stop the execution, it's so slow. But editing:
SELECT col1, col2,col3,...,coln FROM MyTable
WHERE col1 = #value1
AND
(
ISNULL(col2,'c') = ISNULL(#value2,ISNULL(col2,'c'))
)
AND coln = 'valueN'
This query is faster. Can someone help me? How can I replace the or statement or replace the query but validating col1 and col2?.
Thanks.
UPDATE:
Thank you very much guys. Really my query does not use '=' but use 'Like', sorry about that. However I use your suggestions to build my query and it works fine:
SELECT col1, col2,col3,...,coln FROM MyTable
WHERE col1 like '%' + #value1 + '%'
AND
(
(#value2 IS NULL)
OR
(col2 IS NOT NULL AND col2 LIKE '%' + #value2 + '%')
OR
(col3 IS NOT NULL AND col3 LIKE '%' + #value2 + '%')
)
AND coln = 'valueN'
I use this query with a page where I have many fields to filter a search and I need that a col2 textbox apply to col3 in database too, I want to mean, only one textbox for name1 and name2 in database.
Sorry about my wrong question and thanks for your suggestions.
ISNULL(col2,'c') = ISNULL('value2',ISNULL(col2,'c'))
is the same as
col2 = 'value2' or (col2 is null and 'value2' is null)
Replace the occurrences and you will most likely have a better performance.
Update
There's one fundamental difference between this solution and the one proposed by #onedaywhen: when the value provided in 'value2' (which I suppose is just a parameter assembled into a SQL string) is NULL, OP only wants to bring back only records where col2 is NULL. Take a closer look into OP's logic, you will see that there. OP's logic always filters: when the parameter is NULL, OP wants records where col2 is NULL.
#onedaywhen's solution brings every record when the parameter is NULL. Although this is a very common query, it's not what OP is looking for.
ISNULL(col2,'c') = ISNULL(#value2,ISNULL(col2,'c'))
is the same as
( ( col2 = #value2 ) OR ( #value2 IS NULL ) )
I'm not sure if this will improve performance, though: I've read that, at least for SQL Server 2005 and earlier, to get an efficient, scalable and performant solution either use IF ELSE control of flow blocks (one per parameter combination) or use dynamic SQL.
UPDATE: ...and here's the proof:
Query 1: When the parameter is a value that is not null:
DECLARE #value2 VARCHAR(10);
SET #value2 = 'Apples';
WITH T
AS
(
SELECT *
FROM (
VALUES (1, 'When col2 is null', NULL),
(2, 'When col2 is the same value as #value2', 'Apples'),
(3, 'When col2 is not the same value as #value2', 'Oranges')
) AS T (ID, narrative, col2)
)
SELECT *,
CASE WHEN ISNULL(col2,'c') = ISNULL(#value2,ISNULL(col2,'c')) THEN 'T' END AS OP,
CASE WHEN ( ( col2 = #value2 ) OR ( #value2 IS NULL ) ) THEN 'T' END AS OneDayWhen,
CASE WHEN col2 = #value2 or (col2 is null and #value2 is null) THEN 'T' END AS Adrian
FROM T;
Output 1:
ID narrative col2 OP OneDayWhen Adrian
----------- ------------------------------------------ ------- ---- ---------- ------
1 When col2 is null NULL NULL NULL NULL
2 When col2 is the same value as #value2 Apples T T T
3 When col2 is not the same value as #value2 Oranges NULL NULL NULL
Note all agree for all rows :)
Query 2: When the parameter is a null:
DECLARE #value2 VARCHAR(10);
SET #value2 = NULL;
WITH T
AS
(
SELECT *
FROM (
VALUES (1, 'When col2 is null', NULL),
(2, 'When col2 is the same value as #value2', 'Apples'),
(3, 'When col2 is not the same value as #value2', 'Oranges')
) AS T (ID, narrative, col2)
)
SELECT *,
CASE WHEN ISNULL(col2,'c') = ISNULL(#value2,ISNULL(col2,'c')) THEN 'T' END AS OP,
CASE WHEN ( ( col2 = #value2 ) OR ( #value2 IS NULL ) ) THEN 'T' END AS OneDayWhen,
CASE WHEN col2 = #value2 or (col2 is null and #value2 is null) THEN 'T' END AS Adrian
FROM T;
Output 2:
ID narrative col2 OP OneDayWhen Adrian
----------- ------------------------------------------ ------- ---- ---------- ------
1 When col2 is null NULL T T T
2 When col2 is the same value as #value2 Apples T T NULL
3 When col2 is not the same value as #value2 Oranges T T NULL
Note OP and OneDayWhen match for all rows, Adrian only matches for row ID = 1.