Get row from table based on parameter - sql

I want to get row from based on parameter value. Either it could be value 'ABC' or NULL. Below is the source table and expected result, which I'm trying to achieve.
SourceTable
column1 column2
--------------------------
value1 NULL
value2 ABC
Tried with query, but it is getting two rows which are with value1 and value2.
Declare #Param1 varchar(20) = 'ABC'
Select *
from SourceTable
where column2 = #Param1 Or column2 is NULL
If value is 'ABC' then Result -
column1 column2
--------------------------
value2 ABC
If value is NULL then Result -
column1 column2
--------------------------
value1 NULL

Perhaps this would work for you?
select *
from SourceTable
where column2 = #Param1 or (#Param1 is null and column2 is null)

You can try something like: Only problem you might encounter with this is if your column2 has blanks.
SELECT *
FROM SourceTable
WHERE ISNULL(column2, '') = ISNULL(#Param1, '')

Perhaps you want union all and a check for existence:
Select *
from SourceTable
where column2 = #Param1
union all
Select *
from SourceTable
where column2 is null and not exists (select 1 from sourcetable st2 where st2.column2 = #Param1);
An alternative uses order by -- if you want only one row:
select top 1 st.*
from sourcetable st
where column2 = #param1 or column2 is null
order by (case when column2 is not null then 1 else 2 end);

Related

Find which where clause is the most troublesome

Problem background
I am trying to pin down to what condition(s) are causing no records / rows the most, so to allow me to find the root cause of what data in the database might need scrubbing.
So for example from the following query I would like to know whether it was the first condition which fails most of the time or second condition is the most offending one and so on.
SELECT TOP 1
FROM table
WHERE column1 = #param1 -- (cndtn 1)This condition works without anding with other conditions
AND column2 = #param2
AND column3 = #param3 -- (cndtn 3) This with 1 works 10% of the time
AND column4 = #param4
One of the ideas I thought was to break the procedure to use one condition at a time.
DECLARE #retVal int
SELECT #retVal = COUNT(*)
FROM table
WHERE column1 = #param1
IF (#retVal > 0)
--Do Something like above but by using #param2, #param3 and so on
Issues
If first check itself fails I wouldn't have a way forward to investigate into other combinations.
This doesn't seem very efficient either as this stored procedure is called hundreds of times.
Other SO Post I also find this great post (Find which one of the WHERE clauses succeeded) but this isn't very helping when no records are returned.
If this is just for debugging, what about detecting when the ##ROWCOUNT = 0 and storing those parameters in a separate debugging table?
SELECT TOP 1 *
FROM SomeTable
WHERE column1 = #param1
AND column2 = #param2
AND column3 = #param3
AND column4 = #param4
-- order by ....
;
-- one or more parameters "failed"
IF ##ROWCOUNT = 0
BEGIN
INSERT INTO SomeTable_Debug( createdDate, column1, column2, column3, column4, column5)
VALUES (getDate(), #param1, #param2, #param3, #param4, #param5)
END
You can then use the debugging table later on, in a separate query script, without having to worry about it's impact on a frequently invoked procedure. For example, this query returns 1 when a condition "fails", otherwise it returns null. It's not optimized for efficiency, but should be fine for occasional debugging use:
SELECT *
, (SELECT 1 WHERE NOT EXISTS (SELECT NULL FROM SomeTable st WHERE st.column1 = d.column1)) AS Matches_Column1
, (SELECT 1 WHERE NOT EXISTS (SELECT NULL FROM SomeTable st WHERE st.column2 = d.column2)) AS Matches_Column2
, (SELECT 1 WHERE NOT EXISTS (SELECT NULL FROM SomeTable st WHERE st.column3 = d.column3)) AS Matches_Column3
, (SELECT 1 WHERE NOT EXISTS (SELECT NULL FROM SomeTable st WHERE st.column4 = d.column4)) AS Matches_Column4
, (SELECT 1 WHERE NOT EXISTS (SELECT NULL FROM SomeTable st WHERE st.column5 = d.column5)) AS Matches_Column5
FROM SomeTable_Debug d
Sample Results:
id
createdDate
column1
column2
column3
column4
column5
Matches_Column1
Matches_Column2
Matches_Column3
Matches_Column4
Matches_Column5
1
2022-04-18 16:51:11.487
1
22
3
4
5
null
1
null
null
null
2
2022-04-18 16:51:11.500
1
22
3
4
56
null
1
null
null
1
db<>fiddle here

IF ELSE in where block of sql query

I have the below stored procedure
CREATE PROCEDURE sp1
(
#param1 bit,
#parma2 bit
)
AS
BEGIN
SELECT * from Table1 where
if #param1 = 1 then column1 is null
else if #parma2 = 1 then column1 is not null
END
Obviously the If else part in the where clause is not correct . Could anyone suggest how to tackle it ?
Something like this:
SELECT * from Table1 where
case
when #param1 = 1 then [column 1] is null
when #param2 = 1 then [column 1] is not null
end
But you don't need two parameters for this procedure, only one should suffice.
Try the following:
SELECT
Case WHEN #param1 = 1 THEN Null
Case WHEN #param2 = 1 THEN column1 Else '' End as column1 ,
* FROM Table1
The above statement will set column1 to null if param1 = 1, it will get the value of column1 if param2 = 1 otherwise it will set it to empty string.
Seems to me like the simplest option would be to use AND and OR:
SELECT *
FROM Table1
WHERE (#param1 = 1 AND column1 is null)
OR (#parma2 = 1 AND column1 is not null)
Use this:
CASE WHEN condition THEN value ELSE value END

Select default if no rows return

SELECT Column1
FROM Table1
WHERE PKColumn = SomeValue
I am selecting just one column, my query will return only 0 or 1 row for sure. I want to select some default values like Some Default if no row returned otherwise the returned value.
I tried something like
SELECT CASE WHEN COUNT(1) = 1 THEN Column1 ELSE 'Some Default' END AS Column1
FROM Table1
WHERE PKColumn = SomeValue
GROUP BY Column1
But it doesn't work.
Is there any way to do it in single SQL statement?
I think you can use a query like this:
SELECT TOP(1)
CASE WHEN EXISTS(SELECT 1 FROM t WHERE PKColumn = SomeValue) THEN Column1
ELSE 'Some Default' END AS Column1
FROM t;
Or using EXISTS with UNION:
SELECT 'Some Default' As Column1
WHERE NOT EXISTS(SELECT 1 FROM t WHERE PKColumn = SomeValue)
UNION ALL
SELECT Column1
FROM t
WHERE PKColumn = SomeValue;
You can use COALESCE
Evaluates the arguments in order and returns the current value of the
first expression that initially does not evaluate to NULL.
SELECT COALESCE((SELECT TOP 1 Column1 FROM Table1 WHERE PK = SomeValue), 'DefaultValue')
or like this:
DECLARE #ReturnValue INT = 3 -- Default value
SELECT TOP 1 #ReturnValue = Column1 FROM Table1 WHERE PK = SomeValue
SELECT #ReturnValue
SELECT
[Column1] = ISNULL([t2].[Column1], 'Some Default')
FROM
[Table1] AS [t1]
OUTER APPLY
(
SELECT
[Column1]
FROM
[Table1]
WHERE
[PKColumn] = [t1].[PKColumn]
) AS [t2]
WHERE
[t1].[PKColumn] = 'SomeValue';
Perhaps can try using LEN instead of COUNT to check if Column1 has value?
SELECT CASE WHEN LEN(Column1) > 0 THEN Column1 ELSE 'Some Default' END AS Column1
FROM Table1
WHERE PKColumn = SomeValue
GROUP BY Column1

How do I create a conditional WHERE clause?

I need to have a conditional where clause that operates as so:
Select *
From Table
If (#booleanResult)
Begin
Where Column1 = 'value1'
End
Else
Begin
Where column1 = 'value1' and column2 = 'value2'
End
Any help would be appreciated.
Could you just do the following?
SELECT
*
FROM
Table
WHERE
(#booleanResult = 1
AND Column1 = 'value1')
OR
(#booleanResult = 0
AND Column1 = 'value1'
AND Column2 = 'value2')
You can group conditions easily in a WHERE clause:
WHERE
(#BooleanResult=1 AND Column1 = 'value1')
OR
(#BooleanResult=0 AND Column1 = 'value1' AND column2 = 'value2')
Based on the script in question, it seems that you need the condition for Column1 irrespective of whether the variable #booleanResult is set to true or false. So, I have added that condition to the WHERE clause and in the remaining condition checks whether the variable is set to 1 (true) or if it is set to 0 (false) then it will also check for the condition on Column2.
This is just one more way of achieving this.
Create and insert script:
CREATE TABLE MyTable
(
Column1 VARCHAR(20) NOT NULL
, Column2 VARCHAR(20) NOT NULL
);
INSERT INTO MyTable (Column1, Column2) VALUES
('value1', ''),
('', 'value2'),
('value1', 'value2');
Script when bit variable is set to 1 (true):
DECLARE #booleanResult BIT
SET #booleanResult = 1
SELECT *
FROM MyTable
WHERE Column1 = 'value1'
AND ( #booleanResult = 1
OR (#booleanResult = 0 AND Column2 = 'value2')
);
Output:
COLUMN1 COLUMN2
------- -------
value1
value1 value2
Script when bit variable is set to 0 (false):
DECLARE #booleanResult BIT
SET #booleanResult = 0
SELECT *
FROM MyTable
WHERE Column1 = 'value1'
AND ( #booleanResult = 1
OR (#booleanResult = 0 AND Column2 = 'value2')
);
Output:
COLUMN1 COLUMN2
------- -------
value1 value2
Demo:
Click here to view the demo in SQL Fiddle.
To provide a shorter answer:
Select *
From Table
Where Column1 = 'value1' and
coalesce(column2, '') = (case when #BooleanResults = 0
then 'value1'
else coalesce( column2, '')
end)
Query 1: if the #CompanyID is set to -1 then all records are selected
Query 2: if the #CompanyID is set to 10 or 11 or 12, only those records are selected where the companyid=#CompanyID
Declare #CompanyID int
Set #CompanyID = -1
select * from sales
where 1=IIF(#CompanyID =-1, 1, IIF(CompanyID =#CompanyID,1,0))
Set #CompanyID = 10
select * from sales
where 1=IIF(#CompanyID =-1, 1, IIF(CompanyID =#CompanyID,1,0))

IF statement error

I have the following columns in TableA
TableA
Column1 varchar
Column2 int
Column3 bit
I am using this statement
IF Column3 = 0
SELECT Column1, Column2 FROM
TableA WHERE
Column2 > 200
ELSE
SELECT Column1, Column2 FROM
TableA WHERE
Column2 < 200
But the statment does not compile. It says Invalid Column Name 'Column3'
Column3 is not being referenced anywhere outside of the IF and ELSE blocks. If you wish to reference this value you will need to declare a new variable and use that;
DECLARE #btColumn3 BIT
SELECT #btColumn3 = Column3 FROM #tblTableA
IF #btColumn3 = 0
SELECT Column1, Column2 FROM
#tblTableA WHERE
Column2 > 200
ELSE
SELECT Column1, Column2 FROM
#tblTableA WHERE
Column2 < 200
Or do the following;
IF (SELECT Column3 FROM #tblTableA) = 0
SELECT Column1, Column2 FROM
#tblTableA WHERE
Column2 > 200
ELSE
SELECT Column1, Column2 FROM
#tblTableA WHERE
Column2 < 200
Either way you will have to ensure that the query used to retrieve Column3 returns a single result either by limiting your query so that it can only return a single value or using MIN(), MAX() etc depending on your requirements.
Also, if you need to execute more than one query within the IF and ELSE blocks you will need to wrap the contents in BEGIN and END as follows:
IF #btColumn3 = 0
BEGIN
// Do a query
// Do another
END
ELSE
BEGIN
// Do a query
// Do another
END
If you want to do this you need to first store the value of Column3 in a variable.
Declare #temp money
Select #Temp = Column3
From TableA
IF #Temp = 0
begin
SELECT Column1, Column2 FROM
TableA WHERE
Column2 > 200
end
ELSE
begin
SELECT Column1, Column2 FROM
TableA WHERE
Column2 < 200
end
Obviously, this assumes that there will only be one value returned for Column3.
EDIT:
This is a different approach which I think should work for you:
declare #CutOffValue money
declare #MaxValue money
Set #CutOffValue = 200
Set #MaxValue = 9999999999
Select Column1, Column2
From TableA
Where Column2 > Case When Column3 = 0 Then #CutOffValue Else 0 End
And Column2 < Case When Column3 = 0 Then #MaxValue Else #CutOffValue End
You are mixing 2 different levels:
IF is at the TSQL (procedure) level and cannot depend on the row values
SELECT is the query itself where the row values can be used to filter the result set
The following would work
IF Condition /* independent of the different values of TableA. can be an aggregate though */
BEGIN
SELECT Column1, Column2 FROM
TableA WHERE
Column2 > 200
END
ELSE
BEGIN
SELECT Column1, Column2 FROM
TableA WHERE
Column2 < 200
END
You will need the syntax as follows
IF <CONDITION>
BEGIN
<Your Statement>
END
ELSE
<Your Statement>
Hope this is helpful!!
Assuming you have posted the complete query, then the problem with your IF clause is that you are assuming that it can use the columns from the SELECT statement following it. It cannot and does not. This is why it will not compile.
You need your test condition to be separate from the statements following the IF clause. See on MSDN.
DECLARE #test BIT
SELECT #test = 0
IF #test = 0
BEGIN
SELECT Column1, Column2 FROM
TableA WHERE
Column2 > 200
END
ELSE
BEGIN
SELECT Column1, Column2 FROM
TableA WHERE
Column2 < 200
END
Why not just do
select Column1, Column2 from TableA where
Column2 > 200 and Column3 = 0 or Column2 < 200 and Column3 = 1
or, abusing arithmetics,
select Column1, Column2 from TableA where (Column2 - 200) * (2 * Column3 - 1) < 0
Since the answer to your problem varies largely on exactly what logic has to be implemented, analyzing present scenario all I can give you is a small and compact query which can meet your requirements (I hope so…)
SELECT Column1,column2 FROM TableA WHERE
(CASE WHEN Column3=0 then Column2 else 2)>(CASE WHEN Column3=0 then 200 ELSE 1)
AND (CASE WHEN Column3<>0 then Column2 else 1)<(CASE WHEN Column3<>0 then Column2 else 2)