Very basic SQL script with aggregate [duplicate] - sql

This question already has answers here:
"You tried to execute a query that does not include the specified aggregate function"
(3 answers)
Closed 6 years ago.
select Customers.cust_id, count(Orders.cust_id)
from Customers left outer join Orders
on Customers.cust_id=Orders.cust_id
group by Customers.cust_id
This correctly displays everything.
select Customers.cust_id, ***Customers.cust_name***, count(Orders.cust_id)
from Customers left outer join Orders
on Customers.cust_id=Orders.cust_id
group by Customers.cust_id
,,Your query does not include the specified expression 'cust_name' as port of an aggregate function."
Why is that? Each cust_id in Customers has a name in cust_name. Why do I get this error message?

When you use an aggregate function count() all other fields (that aren't used with an aggregate function) must appear in the Group By clause.
Here is my explanation as to why:
Aggregate functions operate across groups.
(That is, unless no groups or other fields are specified, in which case they operate across the whole recordset by default. For example, SELECT Sum(Salary) FROM Staff works.)
If you group by cust_id then it knows what to output, a count for each cust_id. But what would it do with the cust_name's? Which cust_name would it, or should it, display for each cust_id output? What if there are several cust_name's for a cust_id? It will only display one row for each cust_id, so what name should it display alongside it? It won't make the assumption that there is exactly one cust_name to correspond to one cust_id.
If there is one cust_name per cust_id then grouping by both will produce the same number of rows (as for cust_id alone) and provide consistent, and reliable, behaviour.

select Customers.cust_id, Customers.cust_name, count(Orders.cust_id)
from Customers left outer join Orders
on Customers.cust_id=Orders.cust_id
group by Customers.cust_id, Customers.cust_name

Related

Aggregate function error while using group by clause in SQL [duplicate]

This question already has answers here:
Reason for Column is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause [duplicate]
(4 answers)
Closed 3 years ago.
I have table named purchase. It has columns billno, billdate, qty, amount. When I run group by query, it is throwing an error.
Query I used
SELECT
BILLNO,
BILLDATE,
SUM(QTY) AS SUMQTY,
SUM(AMOUNT) AS SUMAMOUNT
FROM
PURCHASE
GROUP BY
BILLNO
This is the error I'm getting - how to get bill wise total amount?
Column 'PURCHASE.BILLDATE' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
The error is pretty obvious. The unaggregated columns in the SELECT of an aggregation query need to match the keys. In your query, BILLDATE is not aggregated and it is not a key.
The simple fix is:
SELECT BILLNO, BILLDATE,
SUM(QTY) AS SUMQTY,
SUM(AMOUNT) AS SUMAMOUNT
FROM PURCHASE
GROUP BY BILLNO, BILLDATE;
If you want only one row per BILLNO -- or if you know that BILLDATE is the same for all BILLNO -- then you can use an aggregation function instead:
SELECT BILLNO, MAX(BILLDATE) as BILLDATE,
SUM(QTY) AS SUMQTY,
SUM(AMOUNT) AS SUMAMOUNT
FROM PURCHASE
GROUP BY BILLNO;
According to the official documentation,‘The column must appear in the FROM clause of the SELECT statement, but is not required to appear in the SELECT list. However, each table or view column in any nonaggregate expression in the list must be included in the GROUP BY list’, it will indicate the cause of your error.
For more details , you can refer to this link and you will see some examples about your issue: https://learn.microsoft.com/en-us/sql/t-sql/queries/select-group-by-transact-sql?view=sql-server-2017#arguments
There is a great example to explain for you : https://www.codeproject.com/Articles/1110163/%2FArticles%2F1110163%2FSQL-GROUP-By-and-the-Column-name-is-invalid-in-the
Here we have to revise the Concept of using the Group By and Order By in A SQL Query.
Remember One thing the name of column that has been came in Order By cannot be used inside aggregate function such as SUM, Average or MAX.
So don't put Same Column Name in Aggregate Function and with Order By too.

Sum matching entries in SQL

In this database I need to find the total amount that each customer paid for books in a category, and then sort them by their customer ID. The code appears to run correctly but I end up with approximately 20 extra rows than I should, although the sum appears to be correct in the right rows.
The customer ID is part of customer, but is not supposed to appear in the select clause, when I try and ORDER BY it, I get strange errors. The DB engine is DB2.
SELECT distinct customer.name, book.cat, sum(offer.price) AS COST
FROM offer
INNER JOIN purchase ON purchase.title=offer.title
INNER JOIN customer ON customer.cid=purchase.cid
INNER JOIN member ON member.cid=customer.cid
INNER JOIN book ON book.title=offer.title
WHERE
member.club=purchase.club
AND member.cid=purchase.cid AND purchase.club=offer.club
GROUP BY customer.name, book.cat;
You should fix your join conditions to include the ones in the where clause (between table relationships usually fit better into an on clause).
SELECT DISTINCT is almost never appropriate with a GROUP BY.
But those are not your question. You can use an aggregation function:
GROUP BY customer.name, book.cat
ORDER BY MIN(customer.id)

calculates between These two columns in SQL server [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I want to add a column to the query that calculates between These two columns In the same query ....................................................................
,isnull(sum(ORDERS.Net_Amount) + 0,0) as orders
,isnull(sum (convert(float,(RECEIPTS.Amount))) + 0,0) as recepts
IN SQL SERVER
SELECT CUSTOMERS.[ID_CUSTOMER]
,[FIRST_NAME]
,[TEL]
,[EMAIL]
,isnull(sum(ORDERS.Net_Amount) + 0,0) as orders
,isnull(sum (convert(float,(RECEIPTS.Amount))) + 0,0) as recepts
,[CRIDIT_LIMIT]
,[CUSTOMER_SINCE]
,[ADRESS]
,CUSTOMERS.[state]
FROM [CUSTOMERS]
LEFT JOIN ORDERS on CUSTOMERS.ID_CUSTOMER = ORDERS.CUSTOMER_ID
LEFT JOIN RECEIPTS on CUSTOMERS.ID_CUSTOMER = RECEIPTS.ID_CUSTOMER
GROUP BY CUSTOMERS.[ID_CUSTOMER]
,[FIRST_NAME]
,[TEL]
,[EMAIL]
,[CRIDIT_LIMIT]
,[CUSTOMER_SINCE]
,[ADRESS]
,CUSTOMERS.[state]
CUSTOMERS table
SELECT [ID_CUSTOMER]
,[FIRST_NAME]
,[TEL]
,[EMAIL]
,[IMAGE_CUSTOMER]
,[CRIDIT_LIMIT]
,[CUSTOMER_SINCE]
,[ADRESS]
,[Balance]
,[state]
FROM [CUSTOMERS]
ORDERS table
SELECT [ID_ORDER]
,[DATE_ORDER]
,[CUSTOMER_ID]
,[DESCRIPTION_ORDERS]
,[SALEMAN]
,[ORDER_TOTAL]
,[Discount_Of_Total]
,[Total_After_Discount]
,[Paid_Up]
,[Net_Amount]
,[state]
FROM [ORDERS]
RECEIPTS table
SELECT [image_state]
,[ID_RECEIPT]
,[ID_CUSTOMER]
,[Date]
,[Ref]
,[Amount]
,[Memo]
,[User_Name]
,[state]
,[Payment_Method]
,[Account_ID]
FROM [RECEIPTS]
Orders and receipts are not really related to each other (the receipt doesn't refer to a specific order), so don't join the two. What you want to do instead is find the order amount and the receipt amount per customer and show them. So aggregate the two tables per customer and outer-join the results to the customer table.
select
c.id_customer,
c.first_name,
c.tel,
c.email,
coalesce(o.sum_net_amount, 0) as order_amount,
coalesce(r.sum_amount, 0) as receipt_amount,
c.cridit_limit,
c.customer_since,
c.adress,
c.balance,
c.state
from customers c
left join
(
select customer_id, sum(net_amount) as sum_net_amount
from orders
group by customer_id
) o on c.id_customer = o.customer_id
left join
(
select id_customer, sum(amount) as sum_amount
from receipts
group by id_customer
) r on c.id_customer = r.id_customer;
I see you have updated your request now asking also for the difference of the sums. Well, the operator for subtraction in SQL is - little surprising - the minus sign:
coalesce(o.sum_net_amount, 0) - coalesce(r.sum_amount, 0) as diff
Please try the following...
SELECT Customers.ID_Customer,
first_name,
tel,
email,
SUM( net_amount ) AS OrdersTotal,
COALESCE( sumAmount, 0 ) AS PaymentsTotal,
SUM( net_amount ) - COALESCE( sumAmount, 0 ) AS DifferenceInTotals,
cridit_limit,
customer_since,
adress,
balance,
state
FROM Customers
INNER JOIN Orders ON Customers.ID_Customer = Orders.Customer_ID
LEFT JOIN ( SELECT ID_Customer,
SUM( amount ) AS sumAmount
FROM Receipts
GROUP BY ID_Customer
) AS sumAmountFinder ON Customers.ID_Customer = sumAmountFinder.ID_Customer
GROUP BY Customers.ID_Customer,
first_name,
tel,
email,
cridit_limit,
customer_since,
adress,
balance,
state;
This Answer is based on the assumption that every Customer will have at least one Order, but possibly no Receipts.
This statement is essentially the one that you supplied with the following modifications...
I have changed the JOIN to Orders to an INNER JOIN, since I am assuming that each Customer will have at least one Order. The LEFT JOIN is only necessary where you wish to retain all records from the left table that do not have at least one matching record from the right table as defined by the ON clause. (Note : If you wish to retain all the records from the right table where there is no matching records from the left table, use a RIGHT JOIN).
I have replaced the JOIN to the Receipts table with a subquery that calculates the total of the amount field for each Customer in the Receipts table. A LEFT JOIN is necessary between Customers and the results of this subquery as not all Customers will have a Receipt. In such situations the LEFT JOIN will set each of the fields from the subquery in the joined dataset to NULL.
Where the SUM() function encounters only NULL values it returns NULL, not 0. So that PaymentsTotal will be set to 0 for records where the Customer has no Receipts, I have used the COALESCE() function. This function will return the first non-NULL argument it encounters. Here I have set it to return the total of amount where it encounters one, and 0 where it encounters no total amount.
I have removed all of the square brackets from your field and table names. They are only required where you have used an otherwise disallowed name, such as names with spaces (use [Full Name] instead of Full Name) or names that are also reserved by SQL-Server (if you had decided to call PaymentsTotal Sum, then you would have had to use AS [Sum]). Many programmers consider giving fields such names to be bad practice, even when it is possible with []'s, but fortunately you have not used any otherwise names.
I have removed the table names from your SUM() calculations. Since only one table has a field called net_amount, then it will be a unique field name in the joined dataset, and you will be able to refer to them without specifying the name of the source table as well. Specifying the source table is still necessary in the case of Customers.ID_Customer as the joined dataset will have more than one field called ID_Customer. Also, you will need to specify the source tables names when creating the joined dataset using the JOIN's.
I have also taken the liberty of changing your capitalisation scheme. Having just about everything in constant upper-case is monotonous to the eye. Using different casing for SQL terms, table names and field names makes recognising each type of statement part much easier, and thus makes debugging code much easier.
Finally, and relatively trivially, cridit is actually spelt credit and adress is actually spelt address.
If you have any questions or comments, then please feel free to post a Comment accordingly.

SQL Inventory Count wont return item name

I am working with our inventory database and I created a query (access 2002 format citrix run server) that counts all items of a type meeting a serviceability status and it runs as I had expected but when I try to display the item name Equipment.Model in the other table which is already left joined via the ID I get the error Tried to execute a query that does not include the specified expression 'model' as part of an aggregate function. I think I would expect to get this if I tried to list something like an asset ID but this is related to the items I am counting. The trouble piece is quoted. The tables are quite large but they are basically the below
Equipment
|EquipmentID|CompanyID|Model|Description|TypeID|...
Inventory
|InventoryID|EquipmentID|Serial|Status|...
SELECT Inventory.EquipmentID, "Equipment.Model", COUNT(*) AS Count
FROM (Inventory LEFT JOIN Equipment ON Inventory.EquipmentID=Equipment.EquipmentID)
WHERE Equipment.TypeID = 14
AND Inventory.Status NOT IN (4,5,6,8)
GROUP BY Inventory.EquipmentID;
SELECT Inventory.EquipmentID, Equipment.Model, COUNT(*) AS Count
FROM Inventory
LEFT JOIN Equipment ON Inventory.EquipmentID=Equipment.EquipmentID
WHERE Equipment.TypeID = 14
AND Inventory.Status NOT IN (4,5,6,8)
GROUP BY Inventory.EquipmentID, Equipment.Model;
You have to use all non aggregate columns in the GROUP BY clause.
You need to include equipment.Model in your group by clause

"Group By" failing - ORACLE

I found a dozen or so different threads that were similar to my question, but I didn't see any that addressed what I am experiencing. I have three databases that keep track of customer/sale transactions. I can join them and get the individual transactions I am looking for without a problem, but when I try to group the results by vendor_name, I get "ORA-00979: not a GROUP BY expression", although vendor_name is one of the columns I am selecting (which I thought was the pre-requisite). Am I overlooking something real simple here?
select tran_date,product_name,quantity,
product_price,vendor_name,quantity*product_price as total
from transactions
join products using(product_num)
join customers using(vendor_id) group by vendor_name;
"Grouping by" vendor name means that you are trying to get one record per vendor name. So, you need to specify how the other columns should be grouped/aggregated.
For example "quantity*product_price", being a number, part of what you need would be
select vendor_name, sum(quantity*product_price)
from transactions
join products using(product_num)
join customers using(vendor_id)
group by vendor_name;
The full answer to your question depends on How you want the other columns to be grouped for a given vendor name.