Conditional Statements Inside A Where Clause - sql

I have a sproc that runs on many different servers. In the sproc I have a select statement that looks like the following.
select *
from my_table
where id = #my_id
and status in (1,3)
However, for one of the databases I need the second part of that where clause to only be for statuses equal to 1. So essentially...
select *
from my_table
where id = #my_id
and status in (1)
I really don't want to us an if db_name() = 'mydb' statement because the actual select statements are much longer and the code starts to look really inelegant at that point. Is there some way to make the second part of the where clause conditional on the db_name?
Thanks for your help.

You can use a case statement
select *
from my_table
where id = #my_id
and status = CASE
WHEN db_name() = 'mydb'
THEN 1
WHEN db_name() = 'other'
THEN 3
ELSE -1
END

It will be inelegant, really, because it's conditional.
So, if status IN (1, 3) means status = 1 or status = 3...
where id = #my_id
and
(
status = 1
or
(db_name() <> 'mydb' and status = 3)
)

Create a new table.
select my_table.*
from my_table
inner join my_valid_statuses on my_table.status = my_valid_statuses.status
where my_table.id = #my_id
Then make sure that my_valid_statuses is populated appropriately in each database.

Try this: (I think I got your logic right...)
Cause you want it if the status is 1 for any database, but only want the status 3s for the databases that are not that single specified one...
Select ...
Where id = #my_id
And (status = 1 Or
(Db_Name() <> #DbName And status = 3))

How about something like this
select *
from dbo.MyTable
where 1=1
and
(DB_NAME() = 'FirstDatabase' and Status in (1))
OR
(DB_NAME() = 'SecondDatabase' and Status in (1, 3))

A little complex, but it'll do, if DB_NAME() works.
SELECT *
FROM my_table
WHERE id = #my_id and (status in (1) or (DB_NAME() <> 'mydb' AND status = 3))

Related

WHERE from CASE result

I have a statement - simplified
SELECT UserID,
CASE WHEN UserName = 'xxx' THEN 1 ELSE 0 AS Deleted
FROM User
WHERE Deleted = 0;
but this doesn't work because Deleted can't be used.
Is there a workaround? I can't solve it this way WHERE UserName <> 'xxx' , because in my real statement it's a huge sub select.
Wrap your original query up in a derived table. (Since column aliases aren't available in the same query's where clause.)
select *
from
(
SELECT UserID,
CASE WHEN UserName = 'xxx' THEN 1 ELSE 0 END AS Deleted
FROM User
) dt
WHERE dt.Deleted = 0;
We can use like below without sub queries.
SELECT *
FROM [User]
WHERE (CASE WHEN UserName = 'xxx' THEN 1 ELSE 0 END)=0

SQL - Select statements within case

How do I achieve this using SQL case statement?
select count(*) x from t_table where file_id = 310012;
if x<>0 : select distinct status from t_table where file_id = 310012
else : return x
See the code below:
SELECT CASE COUNT(*)
WHEN COUNT(*) > 0 THEN
(SELECT status FROM t_table WHERE file_id = 310012)
ELSE null END AS x
FROM t_table WHERE file_id = 310012;
You can do what you want with a union all:
select distinct status
from t_table
where file_id = 310012
union all
select 0
from dual
where not exists (select 1 from t_table where tile_id = 320023);
However, returning a single row with 0 seems like a bad idea, because it could be confused with a value status.
Note: You should use '0' if status is a string.
You don't need to count records. Just do only one query:
select distinct status from t_table where file_id = 310012
When the query return some rows, then x must be <> 0
If the query returns an empty resultset, then x must be equal to 0, and you get the second part of if x <> 0 then ..... else return x
As a bonus you get a higher processing speed, because you run only one query against the table, not two.

SQL if select statement returns no rows then perform alternative select statement

Basically, what syntex would allow me to achieve the title statement?
If (select statement 1) returns 0 rows THEN (select statement 2) else (select statement 3)
So that the sql returns results from either statement 2 or 3
I've looked for a way to do this but nothing I've found so far seems to exactly address the if requirements.
IF EXISTS (SELECT field FROM table)
BEGIN
SELECT field FROM table2
END
ELSE
BEGIN
SELECT field FROM table3
END
Here you go...
IF ((select count(*) from table1)= 0)
BEGIN
Select * from table2
END
ELSE
BEGIN
SELECT * from table3
END
Sorry for the lack of feedback. Someone else in the office took an interest and came up with this:
select * from (
select *
, (SELECT Count(*)
FROM users
WHERE version_replace = 59 AND moderated = 1) AS Counter
FROM users WHERE version_replace = 59 AND moderated in (0,1)
) AS y
where Counter = 0 and Moderated = 0
or Counter > 0 and Moderated = 1
ORDER By ID DESC
Which does what I need.

Replacing In clause with exists

HI Gurus,
I'm looking to replace an IN clause with exists, but despite reading other similar cases on here I've not been able to apply them to my dataset.
I am looking to add in a column to my main query which tells me if a fund is found within a separate list, and if it does then label it 'emergency' and if not then 'non-emergency'
The list is defined like so:
select
f.id
FROM _audit a
INNER JOIN _fund f ON a.article_id = f.id
WHERE a.entity_name = 'Fund'
AND a.Changes LIKE
'%finance_code2%OldValue>3%'
)
UNION
(
select
id AS fund_reference
FROM _fund
WHERE (finance_code2 LIKE '3%'
OR finance_code2 LIKE '9%')
AND finance_code2 IS NOT NULL
And so what I am looking for is essentially something like:
SELECT
...Main query here...
,CASE WHEN fund_id IN (list_details) THEN 'emergency' else 'non-emergency' end
I know that it would be more efficient to do something like
SELECT
...Main query here...
,SELECT CASE WHEN EXISTS
(SELECT fund_id FROM list_details WHERE fund_id IS NOT NULL) THEN 'emergency' else 'non-emergency' END
But every time I try it keeps returning false values (saying that funds are contained within the list when they are not)
In case it helps I'm using sql server 2005 and the main query is listed below, where the list_details result (id) is joined onto donation_fund_allocation on list_details.id = donation_fund_allocation.fund_id
As always any clue would be massively appreciated :)
Thanks!
Main query
SELECT
don.supporter_id AS contact_id
,don.id AS gift_id
,YEAR(don.date_received) AS calendar_year
,YEAR(don.date_received) - CASE WHEN MONTH(don.date_received) < 4 THEN 1 ELSE 0 END AS financial_year
,don.date_received AS date_received
,don.event_id AS event_id
,SUM(CASE WHEN don.gift_aid_status <> 4 THEN don.value_gross * ((dfa.percentage) / 100)
WHEN don.gift_aid_status = 4 AND don.value_net > don.value_gross
AND don.value_net <> 0 THEN don.value_net * ((dfa.percentage) / 100)
ELSE don.value_gross * ((dfa.percentage) / 100)
END
) AS donation_value
--**List details query to go in here**
FROM donation don WITH (nolock)
INNER JOIN donation_fund_allocation dfa WITH (nolock) ON dfa.donation_id = don.id
WHERE don.supporter_id IS NOT NULL
AND don.status = 4
AND don.value_gross <> 0
GROUP BY don.supporter_id
,don.id
,don.date_received
,don.event_id
You need to correlate the exists call with the outer query. As written you are just asking if there exist any rows in list_details where fund_id isn't null
So, what you actually want is
SELECT
...Main query here...
,SELECT CASE WHEN EXISTS
(SELECT 1 FROM list_details WHERE fund_id = outer.fund_id) THEN 'emergency' else 'non-emergency' END
Where outer is the table alias for where fund_id can be found in your main select
You could write a function which takes the fund_id and returns an appropriate string value of "emergency" or "non-emergency".

SQL Server query - loop question

I'm trying to create a query that would generate a cross-check table with about 40 custom columns that show Y or N. Right now I have
SELECT DISTINCT [Company],
[Option1],
[Option2],
[Option3],
CASE
WHEN [Table1].[ID1] IN (SELECT ID2 FROM Table2 WHERE Variable = 1 AND Bit = 1) THEN
'Y'
ELSE 'N'
END AS 'CustomColumn1:',
CASE
WHEN [Table1].[ID1] IN (SELECT ID2 FROM Table2 WHERE Variable = 2 AND Bit = 1) THEN
'Y'
ELSE 'N'
END AS 'CustomColumn1:',
CASE
WHEN [Table1].[ID1] IN (SELECT ID2 FROM Table2 WHERE Variable = 3 AND Bit = 1) THEN
'Y'
ELSE 'N'
END AS 'CustomColumn1:',
.............
-- REPEAT ANOTHER 40 times
FROM [Table1]
WHERE [Table1].[OtherCondition] = 'True'
ORDER BY [Company]
So my question is, how do I create a loop (while? for?) that will loop on variable and assign Y or N to the row based on the condition, rather than creating 40+ Case statements?
You couldn't use a loop, but you could create a stored procedure/function to perform the sub-select and case expression and call that 40 times.
Also, you could improve performance of the sub-select by changing it to
SELECT 1 FROM Table2 WHERE EXISTS [Table2].[ID2] = [Table1.ID1] AND Variable = 3 AND Bit = 1
A loop (that is, iterating through a cursor) works on rows, not columns. You will still have to have 40 expressions, one for each column, and the performance will be terrible.
Let SQL Server do its job. And do your bit by telling exactly what you need and creating proper indices. That is, replace
CASE WHEN [Table1].[ID1] IN (SELECT ID2 FROM Table2 WHERE Variable = 2 AND Bit = 1)
with
CASE WHEN EXISTS (SELECT 0 FROM Table2 WHERE ID2 = [Table1].[ID1] AND Variable = 2 AND Bit = 1)
If the output is so vastly different than the schema, there is a question as to whether the schema properly models the business requirements. That said, I would recommend just writing the SQL. You can simplify the SQL like so:
Select Company
, Option1, Option2, Option3
, Case When T2.Variable = 1 Then 'Y' Else 'N' End As CustomCol1
, Case When T2.Variable = 2 Then 'Y' Else 'N' End As CustomCol2
, Case When T2.Variable = 3 Then 'Y' Else 'N' End As CustomCol3
, Case When T2.Variable = 4 Then 'Y' Else 'N' End As CustomCol4
...
From Table1 As T1
Left Join Table2 As T2
On T2.ID2 = T1.ID
And T2.Bit = 1
Where T1.OtherCondition = 'True'
Group By T1.Company
Order By T1.Company
If you want to write something that can help you auto-gen those Case statements (and you are using SQL Server 2005+), you could do something like:
With Numbers As
(
Select 0 As Value
Union All
Select Value + 1
From Numbers
Where Value < 41
)
Select ', Case When T2.Variable = ' + Cast(N.Value As varchar(10)) + ' Then ''Y'' Else ''N'' End As CustomCol' + Cast(N.Value As varchar(10))
From Numbers As N
You would run the query and copy and paste the results into your procedure or code.
One way could have been to use Pivot statement, which is in MS SQL 2005+. But even in that you have to put 1 ... 40 hardcoded columns in pivot statement.
Other way i can think of is to create dynamic SQL, but it is not so much recommended, So what we can do is we can create a dynamic sql query by running a while loop on table and can create the big sql and then we can execute it by using sp_execute. So steps would be.
int #loopVar
SET #loopVar = 0
int #rowCount
varchar #SQL
SET #SQl = ''
Select #rowcount = Count(ID2) from Table2
WHILE(#loopVar <= #rowCount)
BEGIN
// create ur SQL here
END
sp_execute(#SQL)