SQL Server stored procedure: if vairable = X, case where statement - sql

I was able to craft this and it works, though I'm not sure why or if there is a cleaner way.
Basically I have an ASP.NET C# server side that's going to be passing a parameter. If the parameter = 0, I want the select to return everything
If the select is anything but zero, I want to just return the specific row.
DECLARE #OrgId INT = 0
;WITH cte AS
(
SELECT
o.ID_PK OrgId, ISNULL(o.Parent_ID_FK, 1) ParentId,
o.Organization_Name
FROM
DYN_Organization o
WHERE
o.Is_Active = 1
AND #OrgId LIKE CASE #OrgId
WHEN '0' THEN '0'
ELSE o.ID_PK
END
)
SELECT *
FROM cte
Again this works like I want it to, I just don't know why. I thought I would have to put % but it didn't like that. I was just testing my query when I realized it worked.

You could emulate this behavior with the logical or operator, or better yet, with in which is a shorthand over a series of ored equal checks:
;WITH cte AS
(
SELECCT o.ID_PK OrgId, ISNULL(o.Parent_ID_FK, 1) ParentId, o.Organization_Name
FROM DYN_Organization o
WHERE o.Is_Active = 1 AND
#OrgId IN ('0', o.ID_PK)
)
SELECT * FROM cte

Related

Conditional statements in "WHERE" in SQL Server

What I want to achieve is to have a switch case in the where clause. I want to test if this statement returns something, if it returns null, use this instead.
Sample:
SELECT [THIS_COLUMN]
FROM [THIS_TABLE]
WHERE (IF THIS [ID] RETURNS NULL THEN DO THIS SUBQUERY)
What I mean is that it will do this query first.
SELECT [THIS_COLUMN]
FROM [THIS_TABLE]
WHERE [ID] = 'SOMETHING'
If this returns NULL, do this query instead:
SELECT [THIS_COLUMN]
FROM [THIS_TABLE]
WHERE ID = (SELECT [SOMETHING] FROM [OTHER_TABLE]
WHERE [SOMETHING_SPECIFIC] = 'SOMETHING SPECIFIC')
Note that the expected results from the intended query varies from 30 rows up to 15k rows. Hope it helps.
Adding more information:
The results for this query will be used for another query but will just focus on this query.
Providing a real case scenario:
[THIS_COLUMN] is expected to have a list of VALUES.
[THIS_TABLE] contains the latest data only(let's say 1 year's worth of data) while the [OTHER_TABLE] contains the historical data.
What I want to achieve is when I query for a data that is not with in the 1 year's worth of data, IE 'SOMETHING' is not with in the 1 year scope(or in my case it returns NULL), I will use the other query where I query the 'SOMETHING_SPECIFIC'(Or may be 'SOMETHING' from the first statement makes more sense) from the historical table.
If I as reading through the lines correctly, this might work:
SELECT THIS_COLUMN
FROM dbo.THIS_TABLE TT
WHERE TT.ID = 'SOMETHING'
OR TT.ID = (SELECT OT.SOMETHING
FROM dbo.OTHER_TABLE OT
WHERE OT.SOMETHING_SPECIFIC = 'SOMETHING SPECIFIC'
AND NOT EXISTS (SELECT 1
FROM dbo.THIS_TABLE sq
WHERE sq.ID = 'SOMETHING'
AND THIS_COLUMN IS NOT NULL))
Note, however, that this could easily not be particularly performant.
You an use union all and not exists:
select this_column
from this_table
where id = 'something'
union all
select this_column
from this_table
where
not exists (select this_column from this_table where id = 'something')
and id = (select something from other_table where something_specific = 'something specific')
The first union member attempts to find rows that match the first condition, while the other one uses the subquery - the not exists prevents the second member to return something if the first member found a match.
90% of the time you can use a query-batch (i.e. a sequence of T-SQL statements) in a single SqlCommand object or SQL Server client session, so with that in-mind you could do this:
DECLARE #foo nvarchar(50) = (
SELECT
[THIS_COLUMN]
FROM
[THIS_TABLE]
WHERE
[ID] = 'SOMETHING'
);
IF #foo IS NULL
BEGIN
SELECT
[THIS_COLUMN]
FROM
[THIS_TABLE]
WHERE
[ID] = (
SELECT
[SOMETHING]
FROM
[OTHER_TABLE]
WHERE
[SOMETHING_SPECIFIC] = 'SOMETHING SPECIFIC'
)
END
ELSE
BEGIN
SELECT #foo AS [THIS_COLUMN];
END
That said, SELECT ... FROM ... WHERE x IN ( SELECT y FROM ... ) is a code-smell in a query - you probably need to rethink your solution entirely.

SQL Table Valued Function - Return certain data from 'WITH' based on parameter value

I am trying to do a "with" to loop through some data (which its doing fine). But after that with, I want to return data dependent on a bit parameter. Its important that this is inside a function. Below is basically what my code is doing.
WITH StuffChain
AS (
//initial
union all
//more
)
After this, I am trying to do something like
CASE WHEN #MyParamVal = 1 THEN
SELECT TOP (1) * FROM StuffChain
ELSE
SELECT * FROM StuffChain
END
RETURN
SQL is not my strength and I am still learning sorry. I am also unsure whether or not to use inline or multi statement function
EDIT: When I am giving the case, I am using it to explain what I am after to return, not necessarily what I will use. I use it to just describe what I need using what little I know if that makes sense.
First of all, using TOP without ORDER BY is somewhat meaningless, because it provides no order against which to select the first few rows. In this case, we can try using ROW_NUMBER to control the ordering:
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (ORDER BY some_col) rn
FROM StuffChain
)
SELECT *
FROM cte
WHERE
(rn = #MyParamVal) OR (#MyParamVal <> 1);
You can do as follows. This is just one of the solution. you can do with many other ways also.
WITH StuffChain
AS (
//initial
union all
//more
)
After creation of CTE, try with following
SELECT TOP (CASE WHEN #MyParamVal = 1 THEN 1 ELSE
(SELECT COUNT(1) FROM StuffChain) END *
FROM StuffChain
order by <column> <ASC/DESC>;
We can use a Table Variable e.g. Declare #TEMP Table (intcol int,...) inside a function.
Declare #TEMP Table (intcol int,...)
WITH StuffChain
AS (
//initial
union all
//more
)
SELECT * INTO #TEMP FROM StuffChain;
--do what ever you want with temp table

Return 1 if value is 0 without CASE statement

I'm trying to find a tidier way of doing the below query so that I'm not duplicating my code.
SELECT CASE WHEN <COMPLICATED CODE THAT RETURNS A SINGLE INT> = 0
THEN 1
ELSE <COMPLICATED CODE THAT RETURNS A SINGLE INT> END
Ideally, I would like something like this using an existing function rather than creating my own:
SELECT ISVALUE(COMPLICATED CODE THAT RETURNS A SINGLE INT,0,1)
You can use apply:
SELECT (CASE WHEN v.val = 0 THEN 1 ELSE v.val END)
FROM . . . CROSS APPLY
(VALUES (<COMPLICATED CODE THAT RETURNS A SINGLE INT>)) v(val);
You could also do a series of functions:
select coalesce(nullif(<COMPLICATED CODE THAT RETURNS A SINGLE INT>, 0), 1)
However, I think apply is clearer. In addition the above will turn NULL values into 1 as well as 0.
You can use a CTE (or a subquery) as
WITH CTE AS
(
SELECT <COMPLICATED CODE THAT RETURNS A SINGLE INT> AS Value
FROM ...
)
SELECT CASE WHEN Value = 0 THEN 1 ELSE Value END
FROM CTE
This way you write the complicated code just once, and then use just the Value column.
You can use IIF:
SELECT IIF(1 = 1, 'true', 'false')
https://learn.microsoft.com/en-us/sql/t-sql/functions/logical-functions-iif-transact-sql
use a sub query, then you can figure out a mathematical formula that acts to give the values you desire, that way you can eliminate actual boolean logic and replace with mathematical functions
an example is
SELECT *,(1 - ceiling(cos(atan(abs(cast(x as float)))) -
floor(cos(atan(abs(cast(x as float))))))) +
x * ceiling(cos(atan(abs(cast(x as float)))) -
floor(cos(atan(abs(cast(x as float)))))) as Computed
FROM
( select 0 as x union SELECT 1 X UNION SELECT -.123 UNION SELECT 9.1 UNION SELECT 67000 union select -1) OQ

Accessing aliased fields in T-SQL

In a query I create lots of fields using the CASE expression.
I need to reference these fields later on in the query but it seems I can't access the field using its alias - I have to repeat the CASE expression every time I want to reference its value.
Is there a simple way to access these fields?
You can use CTEs (assuming SQL Server 2005+), like this very basic example:
DECLARE #Val INT
SET #Val = 1
;WITH CTEExample AS
(
SELECT CASE #Val WHEN 1 THEN 'A' ELSE 'B' END AS MyCaseField1
)
SELECT * FROM CTEExample WHERE MyCaseField1 = 'A'
why not simply make a subquery
eg
SELECT foo.column
FROM (
SELECT
CASE WHEN yourcase THEN 'a'
ELSE 'b'
END AS 'column'
FROM yourtable) AS foo
but this can be done with CTEs either (look at this answer)
You can also use CROSS APPLY for this as in this tip by Itzik Ben Gan.
SELECT SalesOrderID, OrderDate, Week_Day
FROM Sales.SalesOrderHeader
CROSS APPLY
(SELECT DATEPART(weekday, DATEADD(day, ##DATEFIRST - 7, OrderDate)) AS Week_Day) AS A
WHERE Week_Day NOT IN (1, 7);
You should be aware that reusing aliases in a where clause will render the predicate unsargable however so should be used with caution (this applies regardless of whether you use APPLY or a CTE)

Problem with sql select query

I'm having a little problem with [PortfelID] column. I need it's ID to be able to use it in function which will return me name about Type of Strategy per client. However by doing this i need to put [PortfelID] in GroupBy which complicates the results a lot.
I'm looking for a way to find Type of Strategy and Sum of Money this strategy has. However if i use Group By [PortfelID] I'm getting multiple entries per each strategy. Actually over 700 rows (because there are 700 [PortfelID] values). And all I want is just 1 strategy and Sum of [WycenaWartosc] for this strategy. So in total i would get 15 rows or so
Is there a way to use that function without having to add [PortfelID] in Group By?
DECLARE #data DateTime
SET #data = '20100930'
SELECT [dbo].[ufn_TypStrategiiDlaPortfelaDlaDaty] ([PortfelID], #data)
,SUM([WycenaWartosc]) AS 'Wycena'
FROM[dbo].[Wycena]
LEFT JOIN [KlienciPortfeleKonta]
ON [Wycena].[KlienciPortfeleKontaID] = [KlienciPortfeleKonta].[KlienciPortfeleKontaID]
WHERE [WycenaData] = #data
GROUP BY [PortfelID]
Where [dbo].[ufn_TypStrategiiDlaPortfelaDlaDaty] is defined like this:
ALTER FUNCTION [dbo].[ufn_TypStrategiiDlaPortfelaDlaDaty]
(
#portfelID INT,
#data DATETIME
)
RETURNS NVARCHAR(MAX)
AS BEGIN
RETURN ( SELECT TOP 1
[TypyStrategiiNazwa]
FROM [dbo].[KlienciPortfeleUmowy]
INNER JOIN [dbo].[TypyStrategii]
ON dbo.KlienciPortfeleUmowy.TypyStrategiiID = dbo.TypyStrategii.TypyStrategiiID
WHERE [PortfelID] = #portfelID
AND ( [KlienciUmowyDataPoczatkowa] <= #data
AND ([KlienciUmowyDataKoncowa] >= #data
OR KlienciUmowyDataKoncowa IS NULL)
)
ORDER BY [KlienciUmowyID] ASC
)
end
EDIT:
As per suggestion (Roopesh Majeti) I've made something like this:
SELECT SUM(CASE WHEN [dbo].[ufn_TypStrategiiDlaPortfelaDlaDaty] ([PortfelID], #data) = 'portfel energetyka' THEN [WycenaWartosc] ELSE 0 END) AS 'Strategy 1'
,SUM(CASE WHEN [dbo].[ufn_TypStrategiiDlaPortfelaDlaDaty] ([PortfelID], #data) = 'banków niepublicznych' THEN [WycenaWartosc] ELSE 0 END) AS 'Strategy 2'
FROM [dbo].[Wycena]
LEFT JOIN [KlienciPortfeleKonta]
ON [Wycena].[KlienciPortfeleKontaID] = [KlienciPortfeleKonta].[KlienciPortfeleKontaID]
WHERE [WycenaData] = #data
But this seems like a bit overkill and a bit too much of hand job is required. AlexS solution seems to do exactly what I need :-)
Here's an idea of how you can do this.
DECLARE #data DateTime
SET #data = '20100930'
SELECT
TypID,
SUM([WycenaWartosc]) AS 'Wycena'
FROM
(
SELECT [dbo].[ufn_TypStrategiiDlaPortfelaDlaDaty] ([PortfelID], #data) as TypID
,[WycenaWartosc]
FROM[dbo].[Wycena]
LEFT JOIN [KlienciPortfeleKonta]
ON [Wycena].[KlienciPortfeleKontaID] = [KlienciPortfeleKonta].[KlienciPortfeleKontaID]
WHERE [WycenaData] = #data
) as Q
GROUP BY [TypID]
So basically there's no need to group by PortfelID (as soon as you need to group by output of [dbo].[ufn_TypStrategiiDlaPortfelaDlaDaty]).
This query is not optimal, though. Join can be pushed to the outer query in case PortfelID and WycenaData are not in [KlienciPortfeleKonta] table.
UPDATE: fixed select list and aggregation function application
How about using the "Case" statement in sql ?
Check the below link for example :
http://www.1keydata.com/sql/sql-case.html
Hope this helps.