How to avoid "Cannot perform an aggregate function on an expression containing an aggregate or a subquery" error - sql-server-2008

I am running this query:
SELECT DISTINCT
SUM(CASE WHEN b.CODNAT IN (SELECT item
FROM fnMAS_Parametro_para_Lista('CON_SPED_FISCAL_CFOPS_BLOCO_C_FORA'))
THEN 0 EKSE ROUND(ISNULL(10, 0), 2)
END)
FROM
##tmpARPCO a
INNER JOIN
ARPCO_ITENS_TOTALIZADORES b ON (b.numped = a.numped
AND b.seqped = a.seqped
AND b.tipo = 'P')
INNER JOIN
ArEmpresa c ON (c.codempresa = a.codempresa)
INNER JOIN
ArNat d ON (d.codnat = b.codnat)
WHERE
1=1
AND a.ESPEC IN ('NFE', 'NF', 'NFCE', 'NFA', 'NFFA', 'NFSE')
AND a.MODNF IN ('01', '1B', '04', '55', '65')
AND a.datentr BETWEEN '20180401' AND '20180430'
GROUP BY
a.codcad, a.numnf, a.datentr, b.sittrib
but I get the following message:
Cannot perform an aggregate function on an expression containing an aggregate or a subquery
The function that you can see, only returns me a list of code string from a table. How to solve that problem?
Thanks a lot for your help and time
Alexandre

Related

Problems with query speed when using a nested query for item count

When I add the nested query for invCount, my query time goes from .03 sec to 14 sec. The query works and I get correct values, but it is very, very slow in comparison. Is that just because I have to many conditions in that query? When I take it out and still have the second nested query, the time is still .03 secs. There is clearly something about the first nested query the database doesn't like, but I am not seeing what it is. I have a foreign key set for all the inner join lines too. Any help or ideas would be appreciated.
SELECT a.*,
f.name,
f.partNumber,
f.showInAdminStore,
f.showInPublicStore,
f.productImage,
r.mastCatID,
(SELECT COUNT(b.inventoryID)
FROM storeInventory b
INNER JOIN events c ON c.eventID = b.eventID
WHERE b.pluID = a.pluID
AND b.listPrice = a.listPrice
AND b.unlimitedQty = a.unlimitedQty
AND (b.packageID = a.packageID OR (b.packageID IS NULL AND a.packageID IS NULL))
AND b.orderID IS NULL
AND c.isOpen = '1'
AND b.paymentTypeID <= '2'
AND (b.inCart < '$cartTime' OR b.inCart IS NULL) ) AS invCount,
(SELECT COUNT(x.inventoryID)
FROM storeInventory x
WHERE x.packageID = a.inventoryID) AS packageCount
FROM storeInventory a
INNER JOIN storePLUs f ON f.pluID = a.pluID
INNER JOIN storeCategories r ON r.catID = f.catID
INNER JOIN events d ON d.eventID = a.eventID
WHERE a.storeFrontID = '1'
AND a.orderID IS NULL
AND a.paymentTypeID <= '2'
AND d.isOpen = '1'
GROUP BY a.packageID, a.unlimitedQty, a.listPrice, a.pluID
Table from query output
UPDATE: 12/12/2022
I changed the line checking the packageID to "AND (b.packageID <=> a.packageID)" as suggested and that cut my query time down to 7.8 seconds from 14 seconds. Thanks for the pointer. I will definitely use that in the future for NULL comparisons.
using "count(*)" took about half a second off. When I take the first nested query out, it drops down to .05 seconds even with the other nested queries in there, so I feel like there is still something causing issues. I tried running it without the other "AND (b.inCart < '$cartTime' OR b.inCart IS NULL)" line and that did take about a second off, but no where what I was hoping for. Is there an operand that includes NULL on a less than comparison? I also tried running it without the inner join in the nested query and that didn't change much at all. Of course removing any of that, throughs the values off and they become incorrect, so I can't run it that way.
Here is my current query setup that still pulls correct values.
SELECT a.*,
f.name,
f.partNumber,
f.showInAdminStore,
f.showInPublicStore,
f.productImage,
r.mastCatID,
(SELECT COUNT(*)
FROM storeInventory b
INNER JOIN events c ON c.eventID = b.eventID
WHERE b.pluID = a.pluID
AND b.listPrice = a.listPrice
AND b.unlimitedQty = a.unlimitedQty
AND (b.packageID <=> a.packageID)
AND b.orderID IS NULL
AND c.isOpen = '1'
AND b.paymentTypeID <= '2'
AND (b.inCart < '$cartTime' OR b.inCart IS NULL) ) AS invCount,
(SELECT COUNT(x.inventoryID)
FROM storeInventory x
WHERE x.packageID = a.inventoryID) AS packageCount
FROM storeInventory a
INNER JOIN storePLUs f ON f.pluID = a.pluID
INNER JOIN storeCategories r ON r.catID = f.catID
INNER JOIN events d ON d.eventID = a.eventID
WHERE a.storeFrontID = '1'
AND a.orderID IS NULL
AND a.paymentTypeID <= '2'
AND d.isOpen = '1'
GROUP BY a.packageID, a.unlimitedQty, a.listPrice, a.pluID
I am not familiar with the term 'Composite indexes' Is that something different than these?
Screenshot of ForeignKeys on Table a
I think
AND (b.packageID = a.packageID
OR (b.packageID IS NULL
AND a.packageID IS NULL)
)
can be simplified to ( https://dev.mysql.com/doc/refman/8.0/en/comparison-operators.html#operator_equal-to ):
AND ( b.packageID <=> a.packageID )
Use COUNT(*) instead of COUNT(x.inventoryID) unless you check for not-NULL.
The subquery to compute packageCount seems strange; you seem to count inventories but join on packages.
The need to reach into another table to check isOpen is part of the performance problem. If eventID is not the PRIMARY KEYforevents, then add INDEX(eventID, isOpen)`.
Some other indexes that may help:
a: INDEX(storeFrontID, orderID, paymentTypeID)
a: INDEX(packageID, unlimitedQty, listPrice, pluID)
b: INDEX(pluID, listPrice, unlimitedQty, orderID)
f: INDEX(pluID, catID)
r: INDEX(catID, mastCatID)
x: INDEX(packageID, inventoryID)
After OP's Update
There is no way to do (x<y OR x IS NULL) except by switching to a UNION. In your case, it is pretty easy to do the conversion. Replace
( SELECT COUNT(*) ... AND ( b.inCart < '$cartTime'
OR b.inCart IS NULL ) ) AS invCount,
with
( SELECT COUNT(*) ... AND b.inCart < '$cartTime' ) +
( SELECT COUNT(*) ... AND b.inCart IS NULL ) AS invCount,
Revised indexes:
storePLUs:
INDEX(pluID, catID)
storeCategories:
INDEX(catID, mastCatID)
events:
INDEX(isOpen, eventID)
storeInventory:
INDEX(pluID, listPrice, unlimitedQty, orderID, packageID)
INDEX(pluID, listPrice, unlimitedQty, orderID, inCart)
INDEX(packageID, inventoryID)
INDEX(storeFrontID, orderID, paymentTypeID)

select query inside select statement with condition

I have this query
select coa_ledgers.name, SUM($var1 - $var2) as amount
FROM entryitems
LEFT JOIN coa_ledgers
ON entryitems.ledger_id = coa_ledgers.id
LEFT JOIN coa_groups
ON coa_ledgers.group_id = coa_groups.id
where coa_groups.id = 13
group by coa_ledgers.id
In above $var1 should be select SUM(entryitems.amount) where dc='D' and $var2 should be select SUM(entryitems.amount) where dc='C'
Please help me to write this query, i am not sure if this need subquery.
You did not say where the dc is coming from, but you can do conditional sum:
select coa_ledgers.name,
SUM(if (dc='D', entryitems.amount, 0)) - SUM(if (dc='C', entryitems.amount, 0)) as amount
FROM entryitems
LEFT JOIN coa_ledgers ON entryitems.ledger_id = coa_ledgers.id
LEFT JOIN coa_groups ON coa_ledgers.group_id = coa_groups.id
where coa_groups.id = 13
group by coa_ledgers.id

Where clause using alias column with IF and IFNULL

I have an mysql query like below:
SELECT
sppt_ticket.*,
IF(sppt_read_support_ticket.ID_aks_user IS NULL,'N', 'Y') AS `read_status`,
IFNULL(readcomment.total_comment, 0) AS unread_comment
FROM
sppt_ticket
LEFT JOIN
sppt_read_support_ticket ON
sppt_ticket.ID_support_ticket = sppt_read_support_ticket.ID_support_ticket AND
ID_aks_user = 1
LEFT JOIN
(SELECT
sppt_comment.ID_support_ticket, SUM(IF(sppt_read_comment.ID_aks_user IS NULL, 1, 0))
AS
total_comment
FROM
sppt_comment
LEFT JOIN
sppt_read_comment
ON
sppt_comment.ID_comment = sppt_read_comment.ID_comment
AND
sppt_read_comment.ID_aks_user = 1
GROUP BY
sppt_comment.ID_support_ticket) AS readcomment ON readcomment.ID_support_ticket = sppt_ticket.ID_support_ticket
What I want to get in where clause is like this
WHERE read_status = 'Y'
I've tried using subquery, but still I didn't get it..
any help?
Have you tried this:
SELECT * FROM
(
-- your original query as a table
SELECT
sppt_ticket.*,
IF(sppt_read_support_ticket.ID_aks_user IS NULL,'N', 'Y') AS `read_status`,
IFNULL(readcomment.total_comment, 0) AS unread_comment
FROM
sppt_ticket
LEFT JOIN
sppt_read_support_ticket ON
sppt_ticket.ID_support_ticket = sppt_read_support_ticket.ID_support_ticket AND
ID_aks_user = 1
LEFT JOIN
(SELECT
sppt_comment.ID_support_ticket, SUM(IF(sppt_read_comment.ID_aks_user IS NULL, 1, 0))
AS
total_comment
FROM
sppt_comment
LEFT JOIN
sppt_read_comment
ON
sppt_comment.ID_comment = sppt_read_comment.ID_comment
AND
sppt_read_comment.ID_aks_user = 1
GROUP BY
sppt_comment.ID_support_ticket) AS readcomment ON readcomment.ID_support_ticket = sppt_ticket.ID_support_ticket
)
as temptable
where read_status = 'Y' -- this should work
Or you can use HAVING instead of WHERE if you do not want to treat your query as a table:
SELECT
sppt_ticket.*,
IF(sppt_read_support_ticket.ID_aks_user IS NULL,'N', 'Y') AS `read_status`,
IFNULL(readcomment.total_comment, 0) AS unread_comment
FROM
sppt_ticket
LEFT JOIN
sppt_read_support_ticket ON
sppt_ticket.ID_support_ticket = sppt_read_support_ticket.ID_support_ticket AND
ID_aks_user = 1
LEFT JOIN
(SELECT
sppt_comment.ID_support_ticket, SUM(IF(sppt_read_comment.ID_aks_user IS NULL, 1, 0))
AS
total_comment
FROM
sppt_comment
LEFT JOIN
sppt_read_comment
ON
sppt_comment.ID_comment = sppt_read_comment.ID_comment
AND
sppt_read_comment.ID_aks_user = 1
GROUP BY
sppt_comment.ID_support_ticket) AS readcomment ON readcomment.ID_support_ticket = sppt_ticket.ID_support_ticket
HAVING read_status = 'Y' -- use HAVING instead of WHERE
The reason why treating your original query as a table works is because of the way values are evaluated in the query. In your original query, the alias read_status cannot be used with the WHERE clause because the actual value might not yet be known when the WHERE clause is evaluated. As documented in Section B.1.5.4, “Problems with Column Aliases”. Treating it as a table ensures that the value for read_status has already been evaluated.
For the HAVING approach, MySQL created an extension to standard SQL that permits references in the HAVING clause to aliased expressions in the select list.

Sql query to search for multiple match in junction table

Hello, I have two tables and one junction table. And I want to find all estates, that has one or multiple comforts. I wrote this query (postrgreSql):
SELECT DISTINCT "estates".*
FROM "estates"
LEFT JOIN "estate_comforts"
ON "estates"."id" = "estate_comforts"."estate_id"
WHERE "estate_comforts"."comfort_id" IN ( '1', '2' )
It finding estates that has the first comfort OR the second, but I need to search in "AND" mode.
This project using Yii2 framewors, so plain sql or ActiveRecord statement are acceptable.
Update. This query select all esates, regardless of the comforts
SELECT DISTINCT "estates".*
FROM "estates"
LEFT JOIN "estate_comforts"
ON "estates"."id" = "estate_comforts"."estate_id"
AND "estate_comforts"."comfort_id" IN ( '1', '2' )
Either JOIN estate_comforts twice, one time for comfort_id 1, and another time for comfort_id 2:
SELECT DISTINCT "estates".*
FROM "estates"
INNER JOIN "estate_comforts" ec1
ON "estates"."id" = ec1."estate_id"
INNER JOIN "estate_comforts" ec2
ON "estates"."id" = ec2."estate_id"
WHERE ec1."comfort_id" = '1'
AND ec2."comfort_id" = '2'
Alternatively, do a GROUP BY on estate_comforts to find estate_id with at least two different comfort_id values. Join with that result:
select e.*
from "estates" e
join (select "estate_id"
from "estate_comforts"
WHERE "comfort_id" IN ( '1', '2' )
group by "estate_id"
having count(distinct "comfort_id") >= 2) ec ON e."id" = ec."estate_id"

MYSQL database IFNULL query

I'm trying to display a 'NULL' value as 0 using 'IFNULL' but it returns all rows as null or 0. Everything works fine until I add the 'lounge2' table and the 'lounge2order2' table. The order2.lounge2orderid is 'NULL'. I know it has something to do with 'JOINS' but not sure where or which to implement.
Thanks all...
SELECT orders2.orderid, orders2.orderdate, branch2.branchname, COUNT(orders2.garment2orderid) AS 'no gar orders', SUM(garment2.hireprice) as 'total gar sold',
COUNT(orders2.lounge2orderid+IFNULL(orders2.lounge2orderid,0)) as 'No of lounge sales', SUM(lounge2.hirerate)
from orders2, branch2, garment2, garment2order2, lounge2, lounge2order2
WHERE orders2.orderid IN
(SELECT orders2.orderid FROM orders2
WHERE orders2.branchid = 2
AND YEAR(orders2.orderdate)= 2011)
AND branch2.branchid IN
(SELECT branch2.branchid from branch2
WHERE branch2.branchid = orders2.branchid)
AND garment2order2.garment2orderid IN
(SELECT garment2order2.garment2orderid FROM garment2order2
WHERE garment2order2.garment2orderid = orders2.garment2orderid)
AND garment2.garmentid IN
(SELECT garment2.garmentid FROM garment2
WHERE garment2.garmentid = garment2order2.garmentid)
AND lounge2order2.lounge2orderid IN
(SELECT lounge2order2.lounge2orderid FROM lounge2order2
WHERE lounge2order2.lounge2orderid = orders2.lounge2orderid)
AND lounge2.loungeid IN
(SELECT lounge2.loungeid FROM lounge2
WHERE lounge2.loungeid = lounge2order2.loungeid)
First of all, try to avoid FROM orders2, branch2, garment2, garment2order2, lounge2, lounge2order2 it must be JOIN ... ON statement. That would help you to debug and us to understand what your logic and table relations are.
And to have any agregate functions like SUM or COUNT working you should set GROUP BY statement.
Since I have no idea what is your database structure like.
Here is my try:
SELECT
orders2.orderid,
orders2.orderdate,
COUNT(orders2.garment2orderid) AS 'no gar orders',
branch2.branchname,
SUM(garment2.hireprice) as 'total gar sold',
SUM(IF(orders2.lounge2orderid IS NULL,1,0)) as 'No of lounge sales',
SUM(lounge2.hirerate)
FROM orders2
LEFT JOIN branch2
ON branch2.branchid = orders2.branchid
LEFT JOIN garment2order2
ON garment2order2.garment2orderid = orders2.garment2orderid
LEFT JOIN garment2
ON garment2.garmentid = garment2order2.garmentid
LEFT JOIN lounge2order2
ON lounge2order2.lounge2orderid = orders2.lounge2orderid
LEFT JOIN lounge2
ON lounge2.loungeid = lounge2order2.loungeid)
WHERE orders2.branchid = 2
AND YEAR(orders2.orderdate)= 2011
GROUP BY orders2.orderid