Aggregate function calls may not be nested ERROR - sql

I am trying to run this query in postgresql but getting this error: "ERROR: Aggregate function calls may not be nested". I am not sure what the problem or a solution for this.
Here is my query:
select a.KEY_NBR, a.MAIN_ID
,
case
when a.KEY_NBR = a.MAIN_ID
then 'Don''t Use'
when a.count = MAX(a.count) over(partition by a.KEY_NBR)
then 'Good'
else 'Bad'
end [flag]
from MYTABLE a

Your query looks ok and should work. Perhaps the version you use has some limitations. Try this variation:
WITH a AS
( SELECT key_nbr, main_id, count,
MAX(count) OVER (PARTITION BY key_nbr) AS max_count
FROM mytable
)
SELECT a.key_nbr, a.main_id,
CASE WHEN a.key_nbr = a.main_id
THEN 'Don''t Use'
WHEN a.count = max_count
THEN 'Good'
ELSE 'Bad'
END AS flag
FROM a ;

Related

find duplicate row in the same table and mark them in sql

I have table 'workadress' and it contain 6 columns:
work_ref,work_street ,work_zip,workTN,...
I want to find duplicate rows in the same table depending on:
If (work_street, work_zip) are duplicate together, then you should look at workTN. If it is the same then put value ' ok ', but if workTN is not the same, put 'not ok'. How can I do it with SQL?
Result like:
You can use window functions:
select t.*,
(case when min(workTn) over (partition by work_street, work_zip) =
max(workTn) over (partition by work_street, work_zip)
then 'ok' else 'not ok'
end) as result
from t;
I think just a simple group by and count should be enough to do the job like so:
select
t.*,
case when dups.dups = 1 then 'OK' else 'not OK' end
from my_table t
join (
select work_street, work_zip, count(distinct workTN) dups
from my_table
group by work_street, work_zip
) dups on dups.work_street = t.work_street amd dups.work_zip = t.work_zip

SQL Server : "invalid column name" error after GROUP BY on subquery

I am trying to perform the following query on a SQL Server database table with a GROUP BY on a column which results from a CASE statement done on a subquery:
SELECT
AVG(sales) as avg_sales,
COUNT(*) as total_sales,
CASE
WHEN (pay_method='cc') AND (user_type='subscriber') THEN 'cc-subscribed'
WHEN (pay_method='cash') AND (user_type='subscriber') THEN 'cash-subscribed'
ELSE 'standard'
END as user_payment_type
FROM
(SELECT
column1, column2,
UserType as user_type,
CASE
WHEN column1='something' AND column2='something_else' THEN 'cc'
WHEN column1='something_else' AND column2='something' THEN 'cash'
END as pay_method
FROM MyTable) b
GROUP BY
user_payment_type
The error I am getting is
MSSQLDatabaseException: (207, b"Invalid column name 'user_payment_type'.DB-Lib error message 20018, severity 16:\nGeneral SQL Server error: Check messages from the SQL Server\n")
Note that the column name user_payment_type is unique and does not already exist in MyTable.
SQL Server does not allow the use of this aliased column in the group by clause (others like MySql do allow it) because the group by clause is executed before select.
You have to use that case statement:
group by CASE
WHEN (pay_method='cc') AND (user_type='subscriber') THEN 'cc-subscribed'
WHEN (pay_method='cash') AND (user_type='subscriber') THEN 'cash-subscribed'
ELSE 'standard'
END
Your SELECT and GROUP BY should match. You could avoid duplicating code by using CROSS APPLY:
WITH cte AS (
SELECT column1,
column2,
UserType as user_type,
CASE
WHEN column1='something' AND column2='something_else' THEN 'cc'
WHEN column1='something_else' AND column2='something' THEN 'cash'
END as pay_method
FROM MyTable
)
SELECT AVG(c.sales) as avg_sales,
COUNT(*) as total_sales,
s.user_payment_type
FROM cte c
CROSS APPLY (SELECT CASE
WHEN (pay_method='cc') AND (user_type='subscriber') THEN 'cc-subscribed'
WHEN (pay_method='cash') AND (user_type='subscriber') THEN 'cash-subscribed'
ELSE 'standard' END) s(user_payment_type)
GROUP BY s.user_payment_type
As others have noted, you can't reference column aliases in the group by clause, but should reference the same expression there too.
Note, however, that you're performing two calculations on the same data. You could perform both calculations in the same subquery to make the query shorter and easier to maintain:
SELECT
AVG(sales) as avg_sales,
COUNT(*) as total_sales,
user_payment_type
FROM (
SELECT sales,
CASE
WHEN column1 = 'something' AND
column2 = 'something_else' AND /* These are the conditions for cc */
user_type = 'subscriber'
THEN 'cc-subscribed'
WHEN column1 = 'something_else' AND
column2 = 'something' AND /* conditions for cash */
user_type = 'subscriber'
THEN 'cash-subscribed'
ELSE 'standard'
END as user_payment_type
FROM MyTable
) b
GROUP BY
user_payment_type
A simple way to do this without nested subqueries uses apply:
SELECT v1.user_payment_type,
AVG(t.sales) as avg_sales,
COUNT(*) as total_sales
FROM MyTable t CROSS APPLY
(VALUES (CASE WHEN t.column1 = 'something' AND t.column2 = 'something_else' THEN 'cc'
WHEN t.column1 = 'something_else' AND t.column2 = 'something' THEN 'cash'
END
)
) v(pay_method) CROSS APPLY
(VALUES (CASE WHEN v.pay_method = 'cc' AND t.user_type = 'subscriber' THEN 'cc-subscribed'
WHEN v.pay_method = 'cash' AND t.user_type = 'subscriber' THEN 'cash-subscribed'
ELSE 'standard'
END)
) v1(user_payment_type)
GROUP BY v1.user_payment_type;
This allows you to define interdependent definitions without nesting subqueries or CTEs or repeating definitions.

SQL Create a new column with if/else condition

I've been working on this task for way too long and I'm still stuck. What I need to do is, working on database AdventureWorks2014, retrieve CustomerIDs and Average of orders they made (all customers of course). My problem begins when I try to insert another column (called Valuable), that is supposed to have values:
'Y' if CustomerOrders > 10*AverageOfOrders and
'N' if CustomerOrders < 10*AverageOfOrders.
I should use CTE, that's not that important though. I did it with CASE statement, yet I keep getting an error
Incorrect syntax near the keyword 'CASE'.
If anyone could explain to me what am I doing wrong, that would be amazing. Below is my code:
WITH CustID AS
(
SELECT CustomerID, COUNT(CustomerID) AS "NrOfOrdersPerCustomer"
FROM Sales.SalesOrderHeader
GROUP BY CustomerID
),
AvgNr AS
(
SELECT AVG("NrOfOrdersPerCustomer") AS "AvgNrOfOrders"
FROM CustID
),
Joint AS
(
SELECT CustID.CustomerID, 'NULL' AS "Valuable", CustID."NrOfOrdersPerCustomer", AvgNr."AvgNrOfOrders", 10*AvgNr."AvgNrOfOrders" AS "MultipliedBy10"
CASE
WHEN "NrOfOrdersPerCustomer" > "MultipliedBy10" THEN 'Y'
ELSE 'N'
FROM CustID, AvgNr
END
)
SELECT * FROM Joint;
There is already an answer that explains where your syntax errors are (missing comma and incorrect case expression), however, I thought I would just post an alternative solution that is much simpler:
WITH CustID AS
(
SELECT CustomerID, COUNT(CustomerID) AS NrOfOrdersPerCustomer
FROM Sales.SalesOrderHeader
GROUP BY CustomerID
)
SELECT CustomerID,
NrOfOrdersPerCustomer,
AVG(NrOfOrdersPerCustomer) OVER() AS AvgNrOfOrders,
AVG(NrOfOrdersPerCustomer) OVER() * 10 AS MultipliedBy10,
CASE WHEN NrOfOrdersPerCustomer > AVG(NrOfOrdersPerCustomer) OVER() * 10 THEN 'Y'
ELSE 'N'
END AS Valuable
FROM CustID;
This leverages the use a window function - AVG(NrOfOrdersPerCustomer) OVER() - meaning you can get the average of all customers without having to do a separate subquery. I have also removed quote marks from your aliases, for no other reason that they are not necessary unless your alias contains special characters, and I find them quite distracting, especially when not used consistently.
Last CTE is wrong as
Joint AS
(
SELECT CustID.CustomerID,
'NULL' AS "Valuable",
CustID."NrOfOrdersPerCustomer",
AvgNr."AvgNrOfOrders",
10*AvgNr."AvgNrOfOrders" AS "MultipliedBy10" <-- missing , here
CASE
WHEN "NrOfOrdersPerCustomer" > "MultipliedBy10" THEN 'Y'
ELSE 'N' <-- END should come here
FROM CustID, AvgNr
END <-- not here
)
Your last CTE should look like
Joint AS
(
SELECT CustID.CustomerID,
NULL AS "Valuable",
CustID."NrOfOrdersPerCustomer",
AvgNr."AvgNrOfOrders",
10*AvgNr."AvgNrOfOrders" AS "MultipliedBy10",
CASE
WHEN "NrOfOrdersPerCustomer" > "MultipliedBy10" THEN 'Y'
ELSE 'N' END AS Computed_Column
FROM CustID, AvgNr
)
At the end of your SELECT line after AS "MultipliedBy10", you need a comma. Also, your CASE statement is out of order at the end. END needs to be before the FROM statement. Corrected below:
WITH CustID AS
(
SELECT CustomerID, COUNT(CustomerID) AS "NrOfOrdersPerCustomer"
FROM Sales.SalesOrderHeader
GROUP BY CustomerID
),
AvgNr AS
(
SELECT AVG("NrOfOrdersPerCustomer") AS "AvgNrOfOrders"
FROM CustID
),
Joint AS
(
SELECT CustID.CustomerID, 'NULL' AS "Valuable", CustID."NrOfOrdersPerCustomer", AvgNr."AvgNrOfOrders", 10*AvgNr."AvgNrOfOrders" AS "MultipliedBy10",
CASE
WHEN "NrOfOrdersPerCustomer" > "MultipliedBy10" THEN 'Y'
ELSE 'N'
END
FROM CustID, AvgNr
)
SELECT * FROM Joint;

Dividing 2 SELECT statements - 'SQL command not properly ended' error

I'm getting the ORA-00933 error referenced in the subject line for the following statement:
select
(select count(name) as PLIs
from (select
a.name,
avg(b.list_price) as list_price
from
crm.prod_int a, crm.price_list_item b
where
a.row_id = b.product_id
and a.x_sales_code_3 <> '999'
and a.status_cd not like 'EOL%'
and a.status_cd not like 'Not%'
and a.x_sap_material_code is not null
group by a.name)
where list_price = 0)
/
(select count(name) as PLIs
from (select
a.name,
avg(b.list_price) as list_price
from
crm.prod_int a, crm.price_list_item b
where
a.row_id = b.product_id
and a.x_sales_code_3 <> '999'
and a.status_cd not like 'EOL%'
and a.status_cd not like 'Not%'
and a.x_sap_material_code is not null
group by a.name))
as result from dual;
I've tried removing the aliases as suggested solution in other posts but that didn't change the problem. Any ideas? Thanks.
If you're running this in SQLPlus, it is possible that it misinterprets the division operator in the first column for the statement terminator character. Other tools may also be susceptible. Try moving the division operator, e.g. where list_price = 0) \
Answer is wrong, see comment by #Ben
Sub-queries to not have to be named... only if they're directly referenced, i.e. if there's more than one column with the same name in the full query
Subqueries have to be named. Consider changing:
from (select
...
group by a.name)
To:
from (select
...
group by a.name) SubQueryAlias
This does not directly answer your question, but I think the query can be simplified:
select case PLIs when 0 then -1 else PLIs_noprice / PLIs end from (
select
count(name) as PLIs,
count(case list_price when 0 then 1 end) as PLIs_noprice
from (
.... your innermost subselect, up to "group by" goes here ...
)
)
Somehow I can't paste your actual subselect code here, getting "Error submitting your post"... Not tested, as I don't have your tables.

How to do a SUM() inside a case statement in SQL server

I want to add some calculation inside my case statement to dynamically create the contents of a new column but I get the error:
Column 'Test1.qrank' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
This is the code I'm working on
case
when test1.TotalType = 'Average' then Test2.avgscore
when test1.TotalType = 'PercentOfTot' then (cnt/SUM(test1.qrank))
else cnt
end as displayscore
I did try to group but it didn't work.
Any hints?
The error you posted can happen when you're using a clause in the GROUP BY statement without including it in the select.
Example
This one works!
SELECT t.device,
SUM(case when transits.direction = 1 then 1 else 0 end) ,
SUM(case when transits.direction = 0 then 1 else 0 end) from t1 t
where t.device in ('A','B') group by t.device
This one not (omitted t.device from the select)
SELECT
SUM(case when transits.direction = 1 then 1 else 0 end) ,
SUM(case when transits.direction = 0 then 1 else 0 end) from t1 t
where t.device in ('A','B') group by t.device
This will produce your error complaining that I'm grouping for something that is not included in the select
Please, provide all the query to get more support.
You could use a Common Table Expression to create the SUM first, join it to the table, and then use the WHEN to to get the value from the CTE or the original table as necessary.
WITH PercentageOfTotal (Id, Percentage)
AS
(
SELECT Id, (cnt / SUM(AreaId)) FROM dbo.MyTable GROUP BY Id
)
SELECT
CASE
WHEN o.TotalType = 'Average' THEN r.avgscore
WHEN o.TotalType = 'PercentOfTot' THEN pt.Percentage
ELSE o.cnt
END AS [displayscore]
FROM PercentageOfTotal pt
JOIN dbo.MyTable t ON pt.Id = t.Id
If you're using SQL Server 2005 or above, you can use the windowing function SUM() OVER ().
case
when test1.TotalType = 'Average' then Test2.avgscore
when test1.TotalType = 'PercentOfTot' then (cnt/SUM(test1.qrank) over ())
else cnt
end as displayscore
But it'll be better if you show your full query to get context of what you actually need.