TSQL aggregation function in CASE/WHEN condition - sql-server

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

Related

SUM IFS across multiple tables

I have two queries in SQL:
Query A:
SELECT column_1, column_2, column_3 FROM a
Query B
SELECT column_1, column_2, column_3 FROM b
I want to add another column in a such that the column represent the SUM of all values from b.column_3 where b.column_1 = a.column_1
How can this be done in SQL Server?
This will give you all rows you needed:
SELECT *
FROM a
LEFT JOIN b -- left join because for some of the rows in "a" there will be not row in "b"
ON a.column_1 = b.column_1 -- your first condition
OR a.column_2 = b.column_2 -- your second condations
Then we just need to perform the sum:
SELECT a.column_1
,a.column_2
,a.column_3
,SUM(CASE WHEN b.column_1 IS NOT NULL AND a.column_1 = b.column_1 THEN b.column_3 ELSE 0 END)
,SUM(CASE WHEN b.column_1 IS NOT NULL AND a.column_2 = b.column_2 THEN b.column_3 ELSE 0 END)
FROM a
LEFT JOIN b
ON a.column_1 = b.column_1
OR a.column_2 = b.column_2
GROUP BY a.column_1
,a.column_2
,a.column_3
A join with aggregation should work here:
SELECT
a.column_1,
a.column_2,
a.column_3,
b.b_sum
FROM a
LEFT JOIN
(
SELECT column_1, SUM(column_3) AS b_sum
FROM b
GROUP BY column_1
) b
ON a.column_1 = b.column_1;

SQL - conditional ISNULL statement in a query

I am using the following query to gather some information about each ProductId - note that a ProductId can contain several records in the dbo.Sales table:
SELECT
c.ProductId,
COUNT(*) as NumberOfRecords,
(SELECT
(ISNULL(NULLIF(c.Text, ''), 'FALSE'))) as TextFieldHasData
FROM dbo.Sales c
JOIN dbo.Sources s
ON c.ProductId = s.ProductId
AND s.SourceStatusId in (1,2)
GROUP BY c.ProductId, c.Status, s.SourceStatusId, c.Text
ORDER BY c.ProductId
I need to tweak the ISNULL part of the query, and I'm having trouble with the syntax; what I actually need to do is first check the NumberofRecordscount - if the the NumberofRecords count for a given result record is greater than 1, then the TextFieldHadData field for that record should just say 'N/A'. But, if the NumberofRecordscount for a given result record = 1, then it should check whether the c.Text field is NULL or blank. If it is NULL or Blank, the TextFieldHasData field would say 'FALSE.' If it is not NULL or blank, the TextFieldHasData field would say 'TRUE.'
Looking at your code, perhaps you are looking for something like the following (where you would be grouping up to ProductId level):
SELECT
c.ProductId
, COUNT(*) as NumberOfRecords
,
CASE
WHEN COUNT(*) > 1
THEN 'N/A'
ELSE
CASE
WHEN SUM(CASE WHEN ISNULL(c.Text, '') = '' THEN 0 ELSE 1 END) > 0
THEN 'TRUE'
ELSE 'FALSE'
END
END TextFieldHasData
FROM
dbo.Sales c
JOIN dbo.Sources s ON
c.ProductId = s.ProductId
AND s.SourceStatusId in (1, 2)
GROUP BY c.ProductId
ORDER BY c.ProductId
You can use the query:
I can not validate it as I don't have these tables, but it should work, unless you find a minor syntax error.
The idea is to use "case when ..." sql function
select v.productid,v.NumberOfRecords,
case
when v.NumberOfRecords>1 then 'N/A'
when v.NumberOfRecords=1 and isnull(v.TextFieldHasData,'') ='' then 'FALSE'
else 'TRUE' end [textfieldhasdata]
from(
SELECT
c.ProductId,
COUNT(*) as NumberOfRecords,
(SELECT
(ISNULL(NULLIF(c.Text, ''), 'FALSE'))) as TextFieldHasData
FROM dbo.Sales c
JOIN dbo.Sources s
ON c.ProductId = s.ProductId
AND s.SourceStatusId in (1,2)
GROUP BY c.ProductId, c.Status, s.SourceStatusId, c.Text) v
ORDER BY ProductId

How to Have Multiple Case When Statements that Update the same column SQL Server

I want to write a query with multiple CASE WHEN statements that updates the same single column called 'Assert_True'. Basically I want the query to assert that the values in a.col_1 are the same in b.col_1 for all columns. The expected results is a temptable that I can then filter down on the Assert_True column to find which pair of columns do not have the same values. I have written the following code so far:
SELECT
CASE WHEN a.col_1 = b.col_1 THEN 0 ELSE 1 END AS Assert_True,
a.col_1, b.col_1,
CASE WHEN a.col_2 = b.col_2 THEN 0 ELSE 1 END AS Assert_True,
a.col_2, b.col_2,
CASE WHEN a.col_3 = b.col_3 THEN 0 ELSE 1 END AS Assert_True,
a.col_3, b.col_3
INSERT INTO #TempTable
FROM
database.schema.table1 a
JOIN
database.schema.table2 b ON a.ID = b.ID
Just one case statement will do using an OR for the multiple tests:
SELECT
CASE WHEN a.col_1 <> b.col_1 OR a.col_2 <> b.col_2 OR a.col_3 <> b.col_3 THEN 0 ELSE 1 END AS Assert_True,
a.col_1, b.col_1,
a.col_2, b.col_2,
a.col_3, b.col_3
INSERT INTO #TempTable
FROM
database.schema.table1 a
JOIN
database.schema.table2 b ON a.ID = b.ID
Alternatively, for your needs:
SELECT
CASE WHEN a.col_1 <> b.col_1 THEN 'col_1'
WHEN a.col_2 <> b.col_2 THEN 'col_2'
WHEN a.col_3 <> b.col_3 THEN 'col_3'
ELSE 'all matched'
END AS Assert_True,
a.col_1, b.col_1,
a.col_2, b.col_2,
a.col_3, b.col_3
INSERT INTO #TempTable
FROM
database.schema.table1 a
JOIN
database.schema.table2 b ON a.ID = b.ID

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).

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

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

Resources