Aggregate Function Error on an Expression - sql-server

What could be wrong with this query:
SELECT
SUM(CASE
WHEN (SELECT TOP 1 ISNULL(StartDate,'01-01-1900')
FROM TestingTable
ORDER BY StartDate Asc) <> '01-01-1900' THEN 1 ELSE 0 END) AS Testingvalue.
The get the error:
Cannot perform an aggregate function on an expression containing an aggregate or a subquery.

As koppinjo stated what your current (broken) query is doing is checking if you have a NULL-value (or StartDate = '01-01-1900') in your table, return either a 1 or a 0 depending on which, and then attempting to SUM that single value.
There are 2 different logical things you want.
Either getting the amount of rows that has a StartDate or checking if any row is missing StartDate.
SELECT --Checking if there is a NULL-value in table
(
CASE WHEN
(SELECT TOP 1 ISNULL(StartDate,'01-01-1900')
FROM TestingTable
ORDER BY StartDate Asc) <> '01-01-1900' THEN 1
ELSE 0
END
) AS TestingValue
SELECT SUM(TestingValue) TestingValue --Give the count of how many non-NULLs there is
FROM
(
SELECT
CASE WHEN
ISNULL(StartDate,'01-01-1900') <> '01-01-1900' THEN 1
ELSE 0
END AS TestingValue
FROM TestingTable
) T
Here is a SQL Fiddle showing both outputs side by side.

Hard to say, but you probably want something like this:
SELECT
SUM(TestingValue)
FROM
(SELECT
CASE
WHEN ISNULL(StartDate,'01-01-1900') <> '01-01-1900'
THEN 1
ELSE 0
END AS TestingValue
FROM TestingTable) t
As your original query is written now, your subquery will return 1 value overall, so your sum would be 1 or 0 always, not to mention it is illegal. To get around that, this SQL will apply the case statement to every row in the TestingTable and insert the result into a derived table (t), then the 'outer' select will sum the results. Hope this helps!

Related

CAN THE COUNT FUNCTION IN SQL SERVER DB ACCEPT MULTIPLE VALUES

I am querying the very popular AdventureWorks DB in SSMS.
My objective to find the number of males and females under each job title from HumanResources.Employee.
For this my original query was,
SELECT JobTitle,
COUNT(CASE WHEN Gender='M' THEN 1
ELSE 0
END) AS MALE_COUNT,
COUNT(CASE WHEN Gender='F' THEN 1
ELSE 0
END) AS FEMALE_COUNT,Gender
FROM HumanResources.Employee
GROUP BY JobTitle,Gender
ORDER BY JobTitle
GO
However, I am getting incorrect answer with the above query.So by modifying it as below ,I am getting the desired result:
SELECT JobTitle,
COUNT(CASE WHEN Gender='M' THEN 1
END) AS MALE_COUNT,
COUNT(CASE WHEN Gender='F' THEN 1
END) AS FEMALE_COUNT,Gender
FROM HumanResources.Employee
GROUP BY JobTitle,Gender
ORDER BY JobTitle
GO
As can be easily seen, I am just removing the 'ELSE 0' condition for both the CASE statements, but am I unable to figure out as to how '0' is affecting the values returned in the result.
Can someone explain to me the difference between these two? Also I would like to know how the COUNT function is taking multiple values, when normally(say SELECT COUNT(3,3)) it doesn't work.
You want SUM(), not COUNT(): the latter takes in account every non-null value (this includes 0), so your current conditional expressions counts all rows - it is equivalent to COUNT(*)
Also, I suspect that gender should probably not appear in the SELECT and GROUP BY clauses, since that's precisely what you are trying to aggregate
I think that you want:
SELECT
JobTitle,
SUM(CASE WHEN Gender='M' THEN 1 ELSE 0 END) AS MALE_COUNT,
SUM(CASE WHEN Gender='F' THEN 1 ELSE 0 END) AS FEMALE_COUNT
FROM HumanResources.Employee
GROUP BY JobTitle
ORDER BY JobTitle
Documentations say:
COUNT(ALL expression) evaluates expression for each row in a group,
and returns the number of nonnull values.
Read more here: https://learn.microsoft.com/en-us/sql/t-sql/functions/count-transact-sql?view=sql-server-ver15
So we can rewrite your query as:
SELECT
JobTitle,
COUNT(CASE WHEN Gender='M' THEN 1 ELSE NULL END) AS MALE_COUNT,
COUNT(CASE WHEN Gender='F' THEN 1 ELSE NULL END) AS FEMALE_COUNT
FROM HumanResources.Employee
GROUP BY JobTitle
ORDER BY JobTitle
About your queries:
First query:
inside Count function you have a CASE expression which will change the 'M' to 1 and 'F' to 0. Then COUNT function will do the count operations over them. because neither 1 nor 0 are NULL so Count will return total number of records, regardless of 'M' or 'F'
This procedure is same for second CASE too.
Second query:
Inside Count function you have a CASE expression which will change 'M' to 1, but you did not mentioned what to do with other values, so NULL will be returned for non-M values. After that Count function will do the count operations on these records and will return the number of M's.(Second query is equal to the query I have posted, and they both will have the same output. However because of readability I prefer my query over yours :-) )
This procedure is same for second CASE too.
Documentations for CASE expression says:
ELSE else_result_expression Is the expression returned if no
comparison operation evaluates to TRUE. If this argument is omitted
and no comparison operation evaluates to TRUE, CASE returns NULL.
else_result_expression is any valid expression. The data types of
else_result_expression and any result_expression must be the same or
must be an implicit conversion.
Read more here: https://learn.microsoft.com/en-us/sql/t-sql/language-elements/case-transact-sql?view=sql-server-ver15
SELECT Count(3,3)
This is syntactically wrong and will give you an error like this, which is pretty self explanatory:
Msg 174, Level 15, State 1, Line 1 The Count function requires 1
argument(s)
The syntax for Count function based on the aforementioned documentations is like this:
-- Aggregation Function Syntax
COUNT ( { [ [ ALL | DISTINCT ] expression ] | * } )
-- Analytic Function Syntax
COUNT ( [ ALL ] { expression | * } ) OVER ( [ <partition_by_clause> ] )

Incorrect Syntax in sql server , can't figure out the reason

I'm trying to uodate a column in table , depending on combination of two columns.If the value was null , since beginning of time I set it to 0 otherwise I set it to max value until that date.I'm using SQL SERVER 2008.Thanks for the help in advance!
update Table1
set value = a.value
from
( SELECT product,
week ,
case when value is null then
(case when max(value) over(PARTITION BY product ORDER BY week ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) is null then 0
else (max(value) over (PARTITION BY product ORDER BY week ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)) end )
else value end as value
from table2 ) a
where a.product = table1.product
and a.week = table1.week
The ROWS keyword was added to the OVER clause in 2012. You won't be able to use it for 2008.
https://msdn.microsoft.com/en-us/library/ms189461(v=sql.110).aspx

Iff condition Access to SQL syntax

I have an access query that I have recreate in SQL.
Access:
SELECT Columns ,
IIf([Col1]="X",IIf([COL2]<>"XXXX",1,0)) AS NEWCOL1,
IIf([COL2] Not In ("HHH","GGG"),1,0) AS [NEWCOL2],
IIf(([NEWCOL1]=1) Or ([NEWCOL2]=1),1,0) AS NEWCOL3
FROM [TABLE]
WHERE ((([TABLE].COL2)<>"XXXX")) OR ((([TABLE].COL2)<>"HHH" And ([TABLE].COL2)<>"GGG"));
In SQL :
SELECT Columns ,
"NEWCOL1" =
CASE WHEN ([COL1]='X' AND COL2<> 'XXXX') THEN 1
ELSE 0
END,
"NEWCOL2" =
CASE WHEN COL2 NOT IN ('HHH','GGG') THEN 1
ELSE 0
END ,
IIf(([NEWCOL1]=1) Or ([NEWCOL2]=1),1,0) AS NEWCOL3
FROM [TABLE]
WHERE ((([TABLE].COL2)<>'XXXX')) OR ((([TABLE].COL2)<>'HHH' And ([TABLE].COL2)<>'GGG'));
IIf(([NEWCOL1]=1) Or ([NEWCOL2]=1),1,0) AS NEWCOL3
When I use the Newcol1 and newcol2 it throws an error invalid column how could use them maybe in a nested case or iif statement
If you're in SQL 2012, where IIF() is valid, then it looks like the problem is that you don't have an ELSE value for the first outer case:
IIf([Col1]='X',IIf([COL2]<>'XXXX',1,0){,NEED SOME ELSE VALUE HERE}) AS NEWCOL1,
I don't know why this would work in Access. I guess Access must be more "dummy proof" than SQL Server.
To replace your original first IIF with a CASE, you would do this:
CASE WHEN [Col1]='X' THEN
CASE WHEN [COL2]<>'XXXX' THEN 1 ELSE 0 END
END
By not supplying an ELSE for the first condition, if [Col1] does not equal 'X', the statement will return NULL without raising an error.
To handle your most recent request with a CTE, you could do as below:
WITH cte AS (
SELECT
Columns,
CASE WHEN ([COL1]='X' AND COL2<> 'XXXX') THEN 1 ELSE 0 END AS NEWCOL1,
CASE WHEN COL2 NOT IN ('HHH','GGG') THEN 1 ELSE 0 END AS NEWCOL2
FROM [TABLE]
WHERE ((([TABLE].COL2)<>'XXXX')) OR ((([TABLE].COL2)<>'HHH' And ([TABLE].COL2)<>'GGG'))
)
SELECT *, IIf(([NEWCOL1]=1) Or ([NEWCOL2]=1),1,0) AS NEWCOL3
FROM cte;

If any clause when grouping

Doing a Sum() on a column adds up the values in that column based on group by. But lets say I want to sum these values only if all the values are not null or not 0, then I need a clause which checks if any of the values is 0 before it does the sum. How can I implement such a clause?
I'm using sql server 2005.
Thanks,
Barry
Let's supose your table schema is:
myTable( id, colA, value)
Then, one approach is:
Select colA, sum(value)
from myTable
group by colA
having count( id ) = count( nullif( value, 0 ))
Notice that nullif is a MSSQL server function. YOu should adapt code to your rdbms brand.
Explanation:
count aggregate function only count not null values. Here a counting null values test.
You say that 0+2+3=0 for this case. Assuming that NULL+2+3 should also be zero:
SELECT GroupField,
SUM(Value) * MIN(CASE WHEN COALESCE(Value, 0) = 0 THEN 0 ELSE 1 END)
FROM SumNonZero
GROUP BY GroupField
The above statement gives this result
GroupField (No column name)
case1 5
case2 0
case3 0
with this test data
CREATE TABLE SumNonZero (
GroupField CHAR(5) NOT NULL,
Value INT
)
INSERT INTO SumNonZero(GroupField, Value)
SELECT 'case1', 2
UNION ALL SELECT 'case1', 3
UNION ALL SELECT 'case2', 0
UNION ALL SELECT 'case2', 2
UNION ALL SELECT 'case2', 3
UNION ALL SELECT 'case3', NULL
UNION ALL SELECT 'case3', 3
UNION ALL SELECT 'case3', 4
It makes no sense to eliminate 0 from a SUM because it wont impact the sum.
But you may want to SUM based on another field:
select FIELD, sum(
case when(OTHER_FIELD>0) then FIELD
else 0
end)
from TABLE
group by TABLE

SQL Server result column in WHERE clause

SELECT
MyColumn = 'something'
FROM table
WHERE MyColumn == 'something'
Possible to use MyColumn in WHERE clause?
EDIT:
Here's full query:
select TOP 10
PremiumYTDCurrent=Sum(CASE WHEN
AASI.Inv_Acctcur>='201101'
and AASI.Inv_Acctcur<='201102'
THEN (AASI.Inv_Premium)*R.[Percent]
ELSE 0 END),
PremiumYTDPrevious=Sum(CASE WHEN
AASI.Inv_Acctcur>='201001'
and AASI.Inv_Acctcur<='201002'
THEN (AASI.Inv_Premium)*R.[Percent]
ELSE 0 END),
R.STAFF, L.Description, L.LINE_OF_BUSINESS
from AAS_Invoice AASI,Invoice I,Revenue_Tracking R, Policy P, Line_Of_Business L
where I.Invoice_No=convert(Char,Convert(int,AASI.Inv_Entry_Num))
and I.Invoice=R.Invoice
and I.POLICY=P.POLICY
and L.LINE_OF_BUSINESS=P.LINE_OF_BUSINESS
and R.Organization IN (SELECT ST.ORGANIZATION FROM Staff ST WHERE ST.STAFF=14407)
and R.Staff=14407
and R.Activity_type='Broker'
and R.[Percent]>0
and PremiumYTDCurrent != 0
group by R.STAFF, L.Description, L.LINE_OF_BUSINESS
order by PremiumYTDCurrent DESC, PremiumYTDPrevious DESC, average_policy DESC
You can not use the column in the where clause. Use the expression instead.
and Sum(CASE WHEN
AASI.Inv_Acctcur>='201101'
and AASI.Inv_Acctcur<='201102'
THEN (AASI.Inv_Premium)*R.[Percent]
ELSE 0 END) <> 0
Edit 1
Did not notice the SUM clause.
Try add it as a HAVING clause instead after order by.
having Sum(CASE WHEN
AASI.Inv_Acctcur>='201101'
and AASI.Inv_Acctcur<='201102'
THEN (AASI.Inv_Premium)*R.[Percent]
ELSE 0 END) != 0
You could wrap the SQL up in a nested statement, a horrendously simple example being, e.g.:
SELECT MyMadeUpColumnName, col2, AnotherMadeUpColumn FROM (
SELECT SUM(sillycolumn) AS 'MyMadeUpColumnName', col2 FROM table GROUP BY col2
) AS t
WHERE t.AnotherMadeUpColumn <> 0
Any column names that you (re)define in the derived table become the actual column names for the parent select.

Resources