Aggregate function or the GROUP BY clause in SQL Server - sql

I want to get the sum per day by its specified date, show the sum and the tenant name on it. It should be like this. Does it have any possible way to construct it right??
tenant_id tenant_name Total Amount
-----------------------------------
123 SAMPLE 37100

use both column in group by like below
group by tenant_id ,tenant_name
so your query will be
select s.tenant_id ,i.tenant_name,
sum(s.amount) as total
from sales_data s left join
Tenant_info i
on s.tenant_id=i.tenant_id
group by s.tenant_id ,i.tenant_name
Note: maximum db throwns error if you have not put the selection column in group by in times of using aggregate function

Related

Confused with the Group By function in SQL

Q1: After using the Group By function, why does it only output one row of each group at most? Does this mean that having is supposed to filter the group rather than filter the records in each group?
Q2: I want to find the records in each group whose ages are greater than the average age of that group. I tried the following, but it returns nothing. How should I fix this?
SELECT *, avg(age) FROM Mytable Group By country Having age > avg(age)
Thanks!!!!
You can calculate the average age for each country in a subquery and join that to your table for filtering:
SELECT mt.*, MtAvg.AvgAge
FROM Mytable mt
inner join
(
select mtavgs.country
, avg(mtavgs.age) as AvgAge
from Mytable mtavgs
group by mtavgs.country
) MTAvg
on mtavg.country=mt.country
and mt.Age > mtavg.AvgAge
GROUP BY returns always 1 row per unique combination of values in the GROUP BY columns listed (provided that they are not removed by a HAVING clause). The subquery in our example (alias: MTAvg) will calculate a single row per country. We will use its results for filtering the main table rows by applying the condition in the INNER JOIN clause; we will also report that average by including the calculated average age.
GROUP BY is a keyword that is called an aggregate function. Check this out here for further reading SQL Group By tutorial
What it does is it lumps all the results together into one row. In your example it would lump all the results with the same country together.
Not quite sure what exactly your query needs to be to solve your exact problem. I would however look into what are called window functions in SQL. I believe what you first need to do is write a window function to find the average age in each group. Then you can write a query to return the results you need
Depending on your dbms type and version, you may be able to use a "window function" that will calculate the average per country and with this approach it makes the calculation available on every row. Once that data is present as a "derived table" you can simply use a where clause to filter for the ages that are greater then the calculated average per country.
SELECT mt.*
FROM (
SELECT *
, avg(age) OVER(PARTITION BY country) AS AvgAge
FROM Mytable
) mt
WHERE mt.Age > mt.AvgAge

How to select MAX from AVG?

I'm practicing for my SQL exam and I can't figure out the following question:
"Of the average amount paid per customer, show the highest amount."
So to retrieve the average amount paid, I would do the following:
SELECT AVG(Amount) AS 'Average amount paid'
FROM Payment;
Then I would like to retrieve the highest average amount out of this list of averages. I thought the following would do the trick:
SELECT MAX(AVG(Amount)) AS 'Highest average amount paid'
FROM Payment;
This doesn't seem to work. I get the following error:
Cannot perform an aggregate function on an expression containing an aggregate or a subquery.
I would like some help with this. What is the correct way to approach this? Thank you in advance.
In SQL Server, you can order the records and use TOP 1 to keep only the record that has the highest amount:
SELECT TOP 1 Customer_id, AVG(Amount) AS [Average amount paid]
FROM Payment
GROUP BY customer_id
ORDER BY [Average amount paid] DESC;
Note: for this query to make sense, you need a GROUP BY clause. Without it, it would just return one record, with the average of payments within the whole table.
Try using a sub-query:
SELECT MAX(src.cust_avg) AS "Highest average amount paid"
FROM (
SELECT cust_id, AVG(Amount) AS cust_avg
FROM Payment
GROUP BY cust_id -- Get averages per customer
) src
;
To get the "per customer" averages first, you need include something like GROUP BY cust_id.
SQL Fiddle
Use order by:
select customer, avg(amount)
from payment
group by customer
order by avg(amount) desc
fetch first 1 row only;
The fetch first (although standard) is not supported by all databases, so you should use the version appropriate for your database.
In SQL Server, you would use either select top (1) or offset 0 fetch first 1 row only (the offset is not optional, alas).
There are also databases where avg() on an integer returns an integer. If amount is an integer and your database does this, then use avg(amount * 1.0).

why the following code shows the error? and what was the alternate?

my Question is---> Each Sale made by an employee will get him 10% commission of each total sale amount, find out which employee has so far earned more commission with very less number of orders [Refer Northwind database]
i create a column 'com' to calculate commission percentage.
select distinct(EmployeeID) from orders where MIN(count(employeeid))and max(com)
when i run the sqlserver query it shows the error like
"An expression of non-boolean type specified in a context where a condition is expected, near 'and'."
There are several issues with your query. Briefly, you cannot leave the max() function without comparing it to some other expression. You also cannot specify the aggregation functions inside the where clause: for that purpose you will need to enclose them into (select max()....) subquery. But for your purpose, where you need to check the sum() and max() over the queried table, you need to specify them in the having as below:
SELECT EmployeeID
FROM orders
GROUP BY EmployeeID
HAVING SUM(debet)=
(SELECT MAX (sum(com)) from orders GROUP BY EmployeeID)
AND COUNT(ledger_id)=
(SELECT MIN(COUNT(EmployeeID)) FROM orders GROUP BY EmployeeID)

Column is not contained in either an aggregate function or the GROUP BY clause

I have to tables:
DeviceInstace and Device
They are connected with Foreign Key on DeviceInstance.DeviceId=Device.Id
I have SQL query:
select d.CatalogNo,d.Manufacturer,d.Name, sum(quantity)
from DeviceInstance di
full join Device d
on d.Id=di.DeviceId
group by di.DeviceId
with which I need to make little summary that consist of:
catalog number
manufacturer
device name
number of devices (sum of values in quntity columns for these deviceIds)
But I'm facing some Grouping by issuses.
All I try refuse me error like this one:
Column 'Device.CatalogNo' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
I know I can group by CatalogNo but then ten sum of quantity will return wrong numbers.
Can anyone suggest me how to repair it?
Just modify GROUP BY clause:
group by d.DeviceId, d.CatalogNo,d.Manufacturer,d.Name
You need to Add d.CatalogNo,d.Manufacturer in Group By Clause
Try this
select d.CatalogNo,d.Manufacturer,d.Name, sum(quantity)
from DeviceInstance di
full join Device d
on d.Id=di.DeviceId
group by d.Name, d.CatalogNo,d.Manufacturer

MySQL Single Row Returned From Temporary Table

I am running the following queries against a database:
CREATE TEMPORARY TABLE med_error_third_party_tmp
SELECT `med_error_category`.description AS category, `med_error_third_party_category`.error_count AS error_count
FROM
`med_error_category` INNER JOIN `med_error_third_party_category` ON med_error_category.`id` = `med_error_third_party_category`.`category`
WHERE
year = 2003
GROUP BY `med_error_category`.id;
The only problem is that when I create the temporary table and do a select * on it then it returns multiple rows, but the query above only returns one row. It seems to always return a single row unless I specify a GROUP BY, but then it returns a percentage of 1.0 like it should with a GROUP BY.
SELECT category,
error_count/SUM(error_count) AS percentage
FROM med_error_third_party_tmp;
Here are the server specs:
Server version: 5.0.77
Protocol version: 10
Server: Localhost via UNIX socket
Does anybody see a problem with this that is causing the problem?
Standard SQL requires you to specify a GROUP BY clause if any column is not wrapped in an aggregate function (IE: MIN, MAX, COUNT, SUM, AVG, etc), but MySQL supports "hidden columns in the GROUP BY" -- which is why:
SELECT category,
error_count/SUM(error_count) AS percentage
FROM med_error_third_party_tmp;
...runs without error. The problem with the functionality is that because there's no GROUP BY, the SUM is the SUM of the error_count column for the entire table. But the other column values are completely arbitrary - they can't be relied upon.
This:
SELECT category,
error_count/(SELECT SUM(error_count)
FROM med_error_third_party_tmp) AS percentage
FROM med_error_third_party_tmp;
...will give you a percentage on a per row basis -- category values will be duplicated because there's no grouping.
This:
SELECT category,
SUM(error_count)/x.total AS percentage
FROM med_error_third_party_tmp
JOIN (SELECT SUM(error_count) AS total
FROM med_error_third_party_tmp) x
GROUP BY category
...will gives you a percentage per category of the sum of the categories error_count values vs the sum of the error_count values for the entire table.
another way to do it - without the temp table as seperate item...
select category, error_count/sum(error_count) "Percentage"
from (SELECT mec.description category
, metpc.error_count
FROM med_error_category mec
, med_error_third_party_category metpc
WHERE mec.id = metpc.category
AND year = 2003
GROUP BY mec.id
);
i think you will notice that the percentage is unchanging over the categories. This is probably not what you want - you probably want to group the errors by category as well.