Case statement in sql using other selected columns in the same statement - sql-server

I would like to know if the following is possible in SQL server 2005. Column A and B are calculated using other case statements in my actual stored proc. I don't want to repeat the same for another field unnecessarily. If this is not syntactically possible, any other ideas?
SELECT A, B, CASE WHEN column1='1' THEN A ELSE B END Col1.
Modified version of actual query provided as requested. CTE kind of seems to be tough in this model. WANNABE is the column I want to accomplish in the sub select statement.
SELECT 1 AS Region, 'Test',
CAST(Work AS NUMERIC(18,2)) Work,
Work + 2 AS Work2,
WANNABE
FROM
(
SELECT
ROW_NUMBER() OVER(PARTITION BY G.Value, C.C, FR.Mod1 ORDER BY FR.Date DESC, FG.Date DESC, FC.Date DESC) ROW,
CASE WHEN COALESCE(FR.Mod1, '') = '' THEN '' ELSE FR.Mod1 END Mod1,
CASE WHEN #var1=1 AND #var2 = 1 THEN FR.Col1 * G.Value
WHEN #var1=1 AND #var2 = 0 THEN FP.Col1 * G.Value END Work,
CASE WHEN 1=1 THEN Work ELSE 1 END WANNABE,
(
SELECT Col3
FROM Table2
WHERE c = FR.Value
) AS Custom
FROM MainTable FR
JOIN #C C ON FR.Col2 = C.Col2
LEFT JOIN Function1(#VersionDate) cv ON cv.Code = C.Code
LEFT JOIN Function2(#VersionDate) hv ON hv.Code = C.Code
LEFT JOIN #G G ON 1 = 1
LEFT JOIN SubTable1 FG ON FG.Number = G.Value, 2 AND FG.Date = #VersionDate
LEFT JOIN SubTable2 FO ON FO.Number = G.Value
AND FO.Date = #VersionDate AND FO.Code = FR.Code AND FR.Mod1 = FO.Mod1
LEFT JOIN SubTable3 FP ON FP.Code = FR.Code AND FP.VersionDate = #Versiondate
AND CASE WHEN DATALENGTH(FR.Mod1) = 0 THEN '00' ELSE FR.Mod1 END = CASE WHEN DATALENGTH(FP.Mod1) = 0 THEN '00' ELSE FP.Mod1 END
LEFT JOIN SubTable4 FC ON FC.Date = #VersionDate
WHERE FR.Date = #VersionDate
) x
WHERE x.Row = 1
AND RTRIM(LTRIM(x.Col1)) IN ('', '2')

You can define the A,B column aliases in a CTE then reference them in an outer select.
;WITH CTE AS
(
SELECT CASE ... END AS A,
CASE ... END AS B,
column1
FROM your_table
)
SELECT A,
B,
CASE WHEN column1='1' THEN A ELSE B END Col1
FROM CTE
Similarly you can also define them in a CROSS APPLY that is sometimes a bit less verbose.
A silly example just to show the syntax is
SELECT A,
B,
CASE WHEN type='P' THEN A ELSE B END Col1
FROM master..spt_values
CROSS APPLY (SELECT CASE WHEN number %2 = 1 THEN 1 END,
CASE WHEN number %2 = 0 THEN 0 END) T(A,B)
Following your update you can replace the derived table with a CTE and nest CTEs as follows
;WITH x as
(
SELECT
ROW_NUMBER() OVER(PARTITION BY G.Value, C.Code, FR.Mod1 ORDER BY FR.Date DESC, FG.Date DESC, FC.Date DESC) ROW,
...<snip>
WHERE FR.Date = #VersionDate
),
x2 As
(
SELECT *,
CASE WHEN 1=1 THEN Work ELSE 1 END WANNABE
FROM x
)
SELECT 1 AS Region, 'Test',
CAST(Work AS NUMERIC(18,2)) Work,
Work + 2 AS Work2,
WANNABE
FROM x2
WHERE x2.Row = 1
AND RTRIM(LTRIM(x2.Col1)) IN ('', '2')

Yeah it is posible, but how is all your sql statement? You can use the case statement in the select statement as you are using it.
Something like this
SELECT SUM((CASE WHEN column1='1' THEN 10 ELSE 0 END)) AS A, SUM((CASE WHEN column1='2' THEN 10 ELSE 0 END)) AS B
FROM YourTable

Related

SqlQuery to display the value which is not bull from two rows with same ID

Here I Have one ID having different Codes, I have to display if the Id has a Code value then need to display the code value row else null value row.
ID
Code
Name
12
null
Three
12
2345
Three
13
null
four
14
1543
rewq
Essentially we want to lookup up and pick out the entire "first" row giving precedence to a non-null. (The logic would be easy to reverse in all of the options below.) These all then go with the assumption that a maximum of two rows can be present and that one of them must have a null Code in that case.
with data as (select *, count(*) over (partition by ID) as cnt from T)
select ID, Code, Value from data
where cnt = 1 or Code is not null;
or
select distinct t1.ID,
coalesce(t2.Code, t1.Code) as Code, coalesce(t2.Value, t1.Value) as Value
from T t1 left outer join T t2 on t2.ID = t1.ID and t2.Code is not null;
or
--SQL Server
select ID, Code, Value
from T t1 cross apply (
select 1 as Keep from T t2
where t2.ID = t1.ID
having case when t1.Code is null then 0 else 1 end =
case when max(t2.Code) is null then 0 else 1 end) v;
or
with data as (select *, max(Code) over (partition by ID) as maxCode from T)
select ID, Code, Value from data
where coalesce(Code, '!##') = coalesce(maxCode, '!##');
or
with data as (
select *,
row_number() over (
partition by ID
order by case when Code is not null then 0 else 1 end) as rn
from T
) select ID, Code, Value from data where rn = 1;
or
with data as (
select distinct ID,
max(Code) over (partition by ID) as Code,
first_value(Value) over (
partition by ID
order by case when Code is not null then 0 else 1 end) as Value
from T
) select * from data;
or
select * from T t1
where Code is not null or not exists
(select 1 from T t2 where t2.ID = t1.ID and t2.Code is not null);
or
select ID, max(Code) as Code,
/* works better with character values */
substring(max(left(coalesce(Code, '') + ' ', 10) + Value), 10, 50)
from T group by ID;
https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=2c08e5bd0b67118d39cf9f6404218b09
Well this worked for me
SELECT * FROM tablename

TSQL aggregation function in CASE/WHEN condition

I have this query:
SELECT
CASE
WHEN COUNT(DISTINCT Q.FIELD_1) > 1 AND MAX(Q.FIELD_1) <> 'N/A' THEN 'VALUE_010' ELSE 'VALUE_011' END AS FIELD_1,
CASE
WHEN COUNT(DISTINCT Q.FIELD_2) = 10 AND MAX(Q.FIELD_2) <> 'N/A' THEN 'VALUE_020'
WHEN COUNT(DISTINCT Q.FIELD_2) = 100 AND MAX(Q.FIELD_2) <> 'N/A' THEN 'VALUE_021'
ELSE 'VALUE_022' END AS FIELD_2
FROM (
SELECT
A.FIELD_1,
B.FIELD_2
FROM TABLE_A a
JOIN TABLE_B b
ON a.FIELD_X = b.FIELD_Y
GROUP BY
A.FIELD_1,
B.FIELD_2
) Q
What I want is to use aggregation functions like COUNT or MAX combined in the CASE/WHEN conditions of the select. Actually I got error: "Incorrect syntax near >".
Is it possible or I should try different approaches?
I think it is because you have a comma after FIELD_2 in your code
ELSE 'VALUE_022' END AS FIELD_2,
In your query you have a trailing comma in ELSE 'VALUE_022' END AS FIELD_2,
Otherwise try
SELECT
CASE
WHEN Q.F1 > 1 THEN 'VALUE_010' ELSE 'VALUE_011' END AS FIELD_1,
CASE
WHEN Q.F2 = 10 THEN 'VALUE_020'
WHEN Q.F2 = 100 THEN 'VALUE_021'
ELSE 'VALUE_022' END AS FIELD_2
FROM (
SELECT
COUNT DISTINCT(A.FIELD_1) AS F1,
COUNT DISTINCT(B.FIELD_2 AS F2
FROM TABLE_A a
JOIN TABLE_B b
ON a.FIELD_X = b.FIELD_Y
GROUP BY
A.FIELD_1,
B.FIELD_2
) Q
try this
SELECT
CASE WHEN COUNT(DISTINCT a.FIELD_1) > 1 THEN 'VALUE_010' ELSE 'VALUE_011' END AS FIELD_1
,CASE
WHEN COUNT(DISTINCT b.FIELD_2) = 10 THEN 'VALUE_020'
WHEN COUNT(DISTINCT b.FIELD_2) = 100 THEN 'VALUE_021'
ELSE 'VALUE_022' END AS FIELD_2
FROM TABLE_A a
JOIN TABLE_B b
ON a.FIELD_X = b.FIELD_Y
GROUP BY A.FIELD_1, B.FIELD_2

Use IF in SELECT part of query

I need to create something like this
SELECT x.id
, x.name
, x.type
,(
IF x.type = 1
(SELECT SUM(Col1) FROM TableA WHERE ... etc)
ELSE IF x.type = 2
(SELECT SUM(Col2) FROM TableB WHERE ... etc)
) AS Total
FROM TableX as x
So I am trying to select a different sub query according to the value of x.type
Wing
Try to use LEFT JOIN and COALESCE. Use your conditions of x.type to join the tables.
COALESCE (Transact-SQL): Evaluates the arguments in order and returns the current value of the first expression that initially does not evaluate to NULL.
https://msdn.microsoft.com/en-us/library/ms190349.aspx
SELECT x.id
, x.name
, x.type
, COALESCE(SUM(TableA.Column), SUM(TableB.Column)) as column_xyz
FROM TableX as x
LEFT JOIN TableA ON x.type = 1 AND ...
LEFT JOIN TableB ON x.type = 2 AND ...
You can also use CASE WHEN ... THEN ... instead of COALESCE to define which column to use.
Use CASE statement
SELECT x.id,
x.name,
x.type,
CASE
WHEN x.type = 1 THEN (SELECT Sum(Col1)
FROM TableA Where...)
WHEN x.type = 2 THEN (SELECT Sum(Col2)
FROM TableB Where .. )
END AS Total
FROM TableX AS x
You can use CASE WHEN as the below:
SELECT
x.id,
x.name,
x.type,
CASE
WHEN x.type = 1 THEN (SELECT SUM(A.Col1) FROM TableA A WHERE 1 = 1)
WHEN x.type = 2 THEN (SELECT SUM(B.Col2) FROM TableB B WHERE 1 = 1)
ELSE NULL END AS Total
FROM
TableX as x
You can use case expression:
select t.* ,
Case when t.type = 1 then (select sum(col1) ... TableA)
when t.type = 2 then (select sum(col2) ... TableB)
End as Total
From tableX t
By using variable -
DECLARE #SumA INT = SELECT SUM(Col1) FROM TableA WHERE ... etc
DECLARE #SumB INT = SELECT SUM(Col2) FROM TableB WHERE ... etc
SELECT x.id
, x.name
, x.type
,( CASE x.type
WHEN 1 THEN #SumA
WHEN 2 THEN #SumB
END
) AS Total
FROM TableX as x
Choose the datatype for Sum variable accordingly (if Decimal).

Add a WHERE clause in a complex SQL query

I want to pass a ShowRoomId value to the query below. The Employees table has a ShowRoomId column.
How can I do it?
My SQL query is as following:
SELECT *
FROM Employees A
OUTER APPLY (SELECT TOP 1 *
FROM EmployeeBasics B
WHERE (A.EmployeeID = B.EmployeeID)
ORDER BY B.BasicUpdateDate DESC) AS B
OUTER APPLY (
SELECT C.EmployeeId , count(*) AS TotalAbsent
FROM EmployeeAbsents C
WHERE C.AbsentDate BETWEEN '2016-05-01' AND '2016-05-30' AND A.EmployeeID = C.EmployeeID
GROUP BY C.EmployeeId
) AS C
OUTER APPLY (
SELECT EmployeeId,
SUM(CASE WHEN TransctionTypeId = 1 THEN Amount ELSE 0 END) AS Payment,
SUM(CASE WHEN TransctionTypeId = 2 THEN Amount ELSE 0 END) AS RecoverSalary,
SUM(CASE WHEN TransctionTypeId = 3 THEN Amount ELSE 0 END) AS RecoverCash
FROM dbo.EmployeeAdvances D
WHERE A.EmployeeID = D.EmployeeID
GROUP BY EmployeeId
) AS D
Simply use a WHERE clause at the end as following:
... YOUR SELECT ...
WHERE Col = ...YourCondition...
OR
Use WITH keyword to keep your current SELECT-statement in a cte. Then do your query on it.
WITH cte AS
(
... YOUR SELECT ...
)
SELECT *
FROM cte
WHERE Col = ...YourCondition...
OR
You can add your SELECT-statement in to parentheses and name it with an allias name. So you can do query on it too.
SELECT *
FROM
(
... YOUR SELECT ...
) t
WHERE t.Col = ...YourCondition...
As per Giorgi Nakeuri's advice, I added the WHERE clause at the end of the statement.
And it works for me. Revised code is here:
SELECT *
FROM Employees A
OUTER APPLY (SELECT TOP 1 *
FROM EmployeeBasics B
WHERE (A.EmployeeID = B.EmployeeID)
ORDER BY B.BasicUpdateDate DESC) AS B
OUTER APPLY (
SELECT C.EmployeeId , count(*) AS TotalAbsent
FROM EmployeeAbsents C
WHERE C.AbsentDate BETWEEN '2016-05-01' AND '2016-05-30' AND A.EmployeeID = C.EmployeeID
GROUP BY C.EmployeeId
) AS C
OUTER APPLY (
SELECT EmployeeId,
SUM(CASE WHEN TransctionTypeId = 1 THEN Amount ELSE 0 END) AS Payment,
SUM(CASE WHEN TransctionTypeId = 2 THEN Amount ELSE 0 END) AS RecoverSalary,
SUM(CASE WHEN TransctionTypeId = 3 THEN Amount ELSE 0 END) AS RecoverCash
FROM dbo.EmployeeAdvances D
WHERE A.EmployeeID = D.EmployeeID
GROUP BY EmployeeId
) AS D
WHERE A.ShowRoomId = 2

CASE Statement with a JOIN and GROUP BY

I'm trying to select the winners of a race from an event by the specific competition they entered, for example.
The competition table
competition_ID, eventss_ID, competitor_ID, stageName, roundNo, startTime, finisheTime, judges_ID
The eventss table
eventss_ID, eventsName, noOfStages, eventsDate, entryFee, venue_ID, judges_ID
The results I want are;
Event RoundNo competitior_ID Competiton Winner
swimming 1 COM101 1st Place
swimming 1 COM213 2nd Place
swimming 2 COM101 1st Place
swimming 2 COM234 2nd Place
golf 1 COM654 1st Place
golf 1 COM874 2nd Place
Query I tried:
SELECT *
,CASE
WHEN finshTime = (SELECT MIN(finshTime) FROM competition) THEN '1st Place'
WHEN finshTime = (SELECT MAX(finshTime) FROM competition) THEN '2nd Place'
ELSE 'Draw'
END [Competition Winner]
FROM competition
JOIN eventss on eventss.eventss_ID = competition.eventss_ID
GROUP BY competition.roundNo
This would probably work to produce the desired output but it's hard to tell without proper sample data.
; WITH CTE AS (
SELECT *
, ROW_NUMBER() OVER (PARTITION BY eventss_ID, roundNo ORDER BY finishTime) RN
FROM competition)
, CTE2 AS (
SELECT *
, CASE (SELECT finishTime FROM CTE WHERE RN = 1 AND eventss_ID = c.eventss_ID AND roundNo = c.roundNO) - (SELECT finishTime FROM CTE WHERE RN = 2 AND eventss_ID = c.eventss_ID AND roundNo = c.roundNO)
WHEN 0 THEN 'Draw'
ELSE CASE RN
WHEN 1 THEN '1st Place'
ELSE '2nd Place' END END Drawn
FROM CTE c
WHERE RN IN (1, 2))
SELECT e.eventsName [Event], CTE2.RoundNo, CTE2.competitor_ID, CTE2.Drawn [Competition Winner]
FROM eventss e
JOIN CTE2 ON CTE2.eventss_ID = e.eventss_ID
ORDER BY e.eventsName, CTE2.roundNo, CTE2.Drawn
Note: I'm making the assumption that "finishtime" is stored as TIME or DATETIME. If it's stored as something else, this won't work.
EDIT: In the case of more than two people tied for first place, or in the case of a tie for second place, this query should work...
; WITH CTE AS (
SELECT *
, ROW_NUMBER() OVER (PARTITION BY eventss_ID, roundNo ORDER BY finishTime) RN
FROM competition)
, tiesforfirst AS (
SELECT *
, '1st Place' Drawn
FROM CTE T
WHERE finishTime = (SELECT finishTime FROM CTE WHERE RN = 1 AND eventss_ID = T.eventss_ID AND roundNo = T.roundNo))
, tiesforsecond AS (
SELECT *
, '2nd Place' Drawn
FROM CTE T
WHERE finishTime = (SELECT finishTime FROM CTE WHERE RN = 2 AND eventss_ID = T.eventss_ID AND roundNo = T.roundNo)
AND (SELECT COUNT(*) FROM tiesforfirst WHERE eventss_ID = T.eventss_ID AND roundNo = T.roundNo) = 1)
SELECT e.eventsName [Event], tf.RoundNo, tf.competitor_ID
, CASE (SELECT COUNT(*) FROM tiesforfirst WHERE eventss_ID = tf.eventss_ID AND roundNo = tf.roundNo) WHEN 1 THEN tf.Drawn ELSE 'Drawn 1st' END [Competition Winner]
FROM eventss e
JOIN tiesforfirst tf ON tf.eventss_ID = e.eventss_ID
UNION
SELECT e.eventsName [Event], tf.RoundNo, tf.competitor_ID
, CASE (SELECT COUNT(*) FROM tiesforsecond WHERE eventss_ID = tf.eventss_ID AND roundNo = tf.roundNo) WHEN 1 THEN tf.Drawn ELSE 'Drawn 2nd' END [Competition Winner]
FROM eventss e
JOIN tiesforsecond tf ON tf.eventss_ID = e.eventss_ID
ORDER BY e.eventsName, roundNo

Resources