I feel like this is a stupid question, but I haven't been able to find a solution by searching. I have a dataset with sales data, where I want to group some of the ID groups together and show the sum of sales. I'm not concerned with individual items, I want to see only the groups of items and the sum of their sales.
A simplified version of what I'm doing now is:
SELECT year, quarter, company, segment, sum(sales) AS total_sales
FROM table
WHERE segment = 001 OR segment = 015
AND producer LIKE '%ACME Inc.%'
AND year = 2015 OR year = 2016
GROUP BY quarter, year, producer, segment
ORDER BY year, quarter, producer, segment ASC
;
My main problem is getting segments 001 and 015 into the same group, for instance 'Jelly' so that the output shows
year|quarter|company|segment|total_sales
2015|1|ACME Inc.|Jelly|100
where 'Jelly' includes both segments 001 and 015.
I'm able to list alle the individual items, but not group them up with in aggregated groups. My problem is being able to filter only the companies I want to look at, and only the segments I want to look at, at the same time as I'm creating and listing custom groups of the segments.
Thanks for any help :)
Edit: MCVE here - http://sqlfiddle.com/#!9/2414bd/3
CREATE TABLE Table1
(`company` text, `sales` int, `year` int, `quarter` int,
`segment` text)
;
INSERT INTO Table1
(`year`, `quarter`, `company`, `segment`, `sales`)
VALUES
(2015,1,'ACME',001,100),
(2015,1,'ACME',015,100),
(2015,1,'HAL',001,25),
(2015,1,'HAL',015,25),
(2015,1,'ACME',002,50),
(2015,1,'HAL',003,50)
/*many other companies and segments as well*/
;
First, I think you need to fix your where clause. Numbers that start with 0 are usually strings. Plus, you should be using in and careful about the and/or logic:
SELECT year, quarter, company, segment, sum(sales) AS total_sales
FROM table
WHERE segment IN ('001', '015') AND
producer LIKE '%ACME Inc.%' AND
year IN (2015, 2016)
GROUP BY quarter, year, producer, segment
ORDER BY year, quarter, producer, segment ASC;
Next, if you want to combine segments, use case. You seem to want:
SELECT year, quarter, company, 'Jelly' as segement,
SUM(sales) AS total_sales
FROM table
WHERE segment IN ('001', '015') AND
producer LIKE '%ACME Inc.%' AND
year IN (2015, 2016)
GROUP BY quarter, year, producer
ORDER BY year, quarter, producer ASC;
SELECT year, quarter, company,
CASE
WHEN segment IN (001,015)
THEN 'Jelly'
WHEN segment IN (002,003)
THEN 'Bread' ELSE segment END segment,
SUM(sales) AS total_sales
FROM Table1
WHERE company LIKE '%ACME%' OR company LIKE '%HAL%'
AND year IN (2015,2016)
GROUP
BY year
, quarter
, company
, CASE WHEN segment IN (001,015) THEN 'Jelly'
WHEN segment IN (002,003) THEN 'Bread'
ELSE segment
END
ORDER
BY year, quarter, company, segment ASC
;
Related
Company_name
Quarter
Year
Revenue
TCS
Q1
2001
50
CTS
Q2
2010
60
ZOHO
Q2
2007
70
CTS
Q4
2015
90
This is my sample table where I store the names of the companies, quarters of the years, years and revenue for each year per a certain quarter.
I want to find the company with top revenue for each quarter, regardless of the year, and display its revenue too.
In the above case the resultant output should be something like this:
QUARTER
COMPANY_NAME
REVENUE
Q1
TCS
50
Q2
ZOHO
70
Q4
CTS
90
Here's what I've tried:
SELECT DISTINCT(C1.QUARTER),
C1.REVENUE
FROM COMPANY_REVENUE C1,
COMPANY_REVENUE C2
WHERE C1.REVENUE = GREATEST(C1.REVENUE, C2.REVENUE);
There are a couple of problems in your query, among which:
the fact that the DISTINCT keyword can be applied to full rows rather than single fields,
the SELF JOIN should be explicit, though most importantly it requires a matching condition, defined by an ON clause (e.g. SELECT ... FROM tab1 JOIN tab2 ON tab1.field = tab2.field WHERE ...)
Though probably you could solve your problem in another way.
Approach for MySQL 8.0
One way of computing values on partitions (in your case you want to partition on quarters only) is using window functions. In the specific case you can use ROW_NUMBER, which will compute a ranking over your revenues descendently for each selected partition. As long as you want the highest revenue for each quarter, you can select the row number equal to 1 for each quarter group.
WITH cte AS (
SELECT *,
ROW_NUMBER() OVER(
PARTITION BY Quarter
ORDER BY Revenue DESC
) AS rn
FROM tab
)
SELECT Quarter,
Company_name,
Revenue
FROM cte
WHERE rn = 1
Check the demo here.
Approach for MySQL 5.7
In this case you can use an aggregation function. As long as you want your max "Revenue" for each "Quarter", you need first to select the maximum value for each "Quarter", then you need to join back to your original table on two conditions:
table's quarter matches subquery quarter,
table's revenue matches subquery max revenue
SELECT tab.Quarter,
tab.Company_name,
tab.Revenue
FROM tab
INNER JOIN (SELECT Quarter,
MAX(Revenue) AS Revenue
FROM tab
GROUP BY Quarter ) max_revenues
ON tab.Quarter = max_revenues.Quarter
AND tab.Revenue = max_revenues.Revenue
Check the demo here.
Note: the second solution will find for each quarter all companies that have the maximum revenue for that quarter, which means that if two or more companies have the same maximum value, both will be returned. This won't happen for the first solution, as long as the ranking ensures only one (the ranked = 1) will be retrieved.
You can just use a cte:
with x as (
select Quarter, max(Revenue) as Revenue
from table
group by Quarter
)
select t.Company_name, x.Quarter, x.Revenue
from x
join table t
on x.Revenue = t.Revenue
and t.Quarter = x.Quarter;
see db<>fiddle.
First you select the max Revenue group by Quarter, then I'm joining to the table on the returned max(Revenue) but as #lemon pointed out in comments that's not enough because what would happen when there's two revenues on same company but different quarters it will return more rows as shown in this db<>fiddle.
So that's why I need to add the join on quarter so it will only return one result per quarter.
But if you're using a version of MySql that doesn't support cte you can use a subquery like:
select t.Company_name, x.Quarter, x.Revenue
from
(
select Quarter, max(Revenue) as Revenue
from test
group by Quarter
) x
join test t
on x.Quarter = t.Quarter
and x.Revenue = t.Revenue;
Try this,
SELECT quarter, company_name,max(revenue) FROM table_name GROUP BY quarter
How do I query the following:
For each customer, product and month, count the number of sales transactions that were between the previous and the following month's average sales quantities. For January and December, display NULL or 0.
Can only use: 5 aggregate functions (sum, count, avg, max & min)
This is the table reference:
create table sales
(
cust varchar(20),
prod varchar(20),
day integer,
month integer,
year integer,
state char(2),
quant integer,
date date
);
Schema:
Example of my Desired Result
I am stuck with the following codes. I'm having a hard time how to execute it.
SELECT cust, prod, month, COUNT(*) AS SALES_COUNT_BETWEEN_AVGS
FROM sales
I use MySQL. Please guide me thank you.
Maybe try a query like below
the first part is to calculate averages using group by
second part is to use to those averages in a JOIN twice for past month and future month
third part is WHERE clause in which we compare data. Note we have used greatest and least functions to determine min and max between two values from past and next month
Query
WITH T AS
(SELECT cust, prod, month, AVG(quant) AS avg_quantity
FROM sales
group by cust, prod, month
)
SELECT S.cust, S.prod, S.month, COUNT(1) AS Sales_count
FROM sales S
LEFT JOIN T T1
ON T1.cust=S.Cust AND
T1.prod=S.Prod AND
T1.Month=S.Month-1
LEFT JOIN T T2
ON T2.cust=S.Cust AND
T2.prod=S.Prod AND
T2.Month=S.Month+1
WHERE S.quant BETWEEN IFNULL(LEAST(T1.avg_quantity,T2.avg_quantity),0) AND IFNULL(GREATEST(T1.avg_quantity,T2.avg_quantity),0)
I am working with a table that has the following information for 20 different years
Income for citizens for a given year
Region which shows where the citizens live
Year which represents the income of the citizen in the current year
I am using a group by function in order to get average income level for each group,year. And recently I got help here (SQL Group by. Add new row with average result for all groups)
so I could add an extra row with avg income for all regions.
select avg(income),region,year,count(*) as population_size
from income_region group by region,year
union all
select avg(income),'All','All',count(*) as population_size from income_region
However, when I add in an extra column "year" to the group and try the "union all" solution for both year and region it only calculates the average income for all years and all regions.
Ideally I would also have the following types of new groups:
Average income when year = 2001
Average income when year = 2002' ...etc (for all years)
Average income for all years when region = 'North America'
Average income for all years when region = 'Europe'.. etc. (for all regions)
How can be this be done?
Try using with rollup:
select region, year, count(*) as population_size, avg(income)
from income_region
group by region with rollup;
You can refer to the documentation for more details.
just use rollup
select avg(income),region,year,count(*) as population_size
from income_region group by region with rollup
I have a table in which I have the following columns
FirstDate,
LastDate,
Grade_Category,
CR_Tones,
CR_grade
I created a query where this data is grouped by date and material type.
I need to see at the end of the grade column weighted average of the Grade with Tones.
Table is as below:
This is a query that I have designed and I have grouped movement date, grade category, etc the summed up tones, etc.
A query like below can be good starting point
select
lastdate as [date],
grade_category as [material type],
SUM(CR_grade*CR_Tones)/SUM(CR_Tones) as [weighted grade]
from table
group by lastdate, grade_category
Looks like you are looking for grouping sets
select
lastdate as [date],
grade_category as [material type],
SUM(CR_grade*CR_Tones)/SUM(CR_Tones) as weightedgrade --your formula for weighted grade
from yourtable
group by Grouping Sets (lastdate, grade_category)
I have a SQL/Java code issue. The basic overlay is as follows: a MySQL database with a table. In this table there are multiple columns. One column consists of names. An associated column is months. In the third column there is counts. So a sample table would be
john - january - 5
john - january - 6
mary - january - 5
Alex - February- 5
John - February - 6
John - February - 4
Mary - February - 3
John - march - 4
The table continues to month May.
So John appears in five months, Mary in 3, and Alex in one. Currently, my SQL query somewhat looks like this.
select name, sum(count)/4
from table where (category ='something'
AND month not like 'May') group by name;
Basically, what this query is supposed to do is just display each name with the average counts per month. Hence, the sum will be divided by four (because I exclude May, so it must divide Jan-April/4). However, the issue is that some names only appear in one month (or two or three).
This means for that name, the sum of the counts would only be divided by that specific number, to get the average counts over the months. How would I go about this? I feel as if this will require some if statement in a where clause. Kind of like where if the count of the distinct (because months may repeat) is a certain number, then divide the sum(count) by that number for each name?
Also, I think it may not be a where if clause issue. I've read some forums where possibly some use of case could be utilized?
If you need average per month, you can GROUP BY name and month and use AVG function:
SELECT `name`, `month`, avg(`count`)
FROM table
WHERE `category` ='something' AND `month` NOT LIKE 'May'
GROUP BY `name`, `month`;
If you need average for all period, just GROUP BY name and AVG count:
SELECT `name`, avg(`count`)
FROM table
WHERE `category` ='something' AND `month` NOT LIKE 'May'
GROUP BY `name`;
And another option, if you don't like AVG:
SELECT `name`, sum(`count`)/(SELECT count(*) FROM `table` AS `t2` WHERE `category` ='something' AND `month` NOT LIKE 'May' and `t1`.`name` = `t2`.`name`)
FROM `table` AS `t1`
WHERE `category` ='something' AND `month` NOT LIKE 'May')
GROUP BY name;
But I would stay with AVG.
Actually, i prefer to use != instead of NOT LIKE it's improves readability
Just for completness sake here is a WORKING FIDDLE. using the AVG function is the way to go as it will do the average per person per month. look at John in January.. his result is 5.5 when the count (in january) is 5 and 6.. average = 5.5.
SELECT
person,
month,
avg(counter)
FROM testing
where
(
category ='something'
AND month <> 'May'
)
GROUP BY person, month;
If you want to see the data in one like as it sounds like that from your post then you can do this. ANOTHER FIDDLE
SELECT
person,
group_concat(month),
group_concat(average_count)
FROM(
SELECT
person,
month,
avg(counter) as average_count
FROM testing
where
(
category ='something'
AND month <> 'May'
)
GROUP BY person, month
) as t
group by person;
Try this :
SELECT name, SUM(count) / COUNT(DISTINCT month)
FROM table
WHERE month != 'May'
AND category = 'something'
GROUP BY name