MySQL - multiple count, min, max query - mysql

SELECT
`name`, count(`cid`) AS count, Min(`price-3`) AS min, Max(`price-3`) AS max
FROM ed_prices
WHERE type="M"
GROUP BY cid, type
This query gives me what I want for type M. But I have 4 different types like M and a result for every one of them is necessary. While this query gives me a result like this:
name, count, min, max
I need a result like this:
name, countM, minM, maxM, countP, minP, maxP, countZ, minZ, maxZ ...
How can I achieve this?

I know this is not exactly what you're looking for but could you maybe work with this:
SELECT `name`
, type -- you'll want to include the type for each line item
-- to be able to identify which type the values refer to
, count(`cid`) AS count
, Min(`price-3`) AS min
, Max(`price-3`) AS max
FROM ed_prices
WHERE type IN ("M","P","Z","Q") -- where M, P, Z, Q are the different product types
GROUP BY cid, type
You could also try a self join on this to combine the results into one line, to get the results as you requested in the question but it is less scalable for anything more than a handful of products..
SELECT `name`
, countM
, minM
, maxM
, countZ
, minZ
, maxZ
, countP
, minP
, maxP
, countQ
, minQ
, maxQ
FROM
(SELECT `name`
, count(`cid`) AS countM
, Min(`price-3`) AS minM
, Max(`price-3`) AS maxM
FROM ed_prices
WHERE type = "M"
GROUP BY cid) MType
INNER JOIN
(SELECT `name`
, count(`cid`) AS countP
, Min(`price-3`) AS minP
, Max(`price-3`) AS maxP
FROM ed_prices
WHERE type = "P"
GROUP BY cid) PType ON MType.`name` = PType.`name`
INNER JOIN
(SELECT `name`
, count(`cid`) AS countZ
, Min(`price-3`) AS minZ
, Max(`price-3`) AS maxZ
FROM ed_prices
WHERE type = "Z"
GROUP BY cid) ZType ON MType.`name` = ZType.`name`
INNER JOIN
(SELECT `name`
, count(`cid`) AS countQ
, Min(`price-3`) AS minQ
, Max(`price-3`) AS maxQ
FROM ed_prices
WHERE type = "Q"
GROUP BY cid) QType ON MType.`name` = QType.`name`

Related

SQL Queries to analyse Employee Database

I am looking for queries, using which I can analyze a general employee database. This is for Data Analysis.
Tried this for monthly employee trend
SELECT
dt.FullDateAlternateKey as 'Date'
, count(1) as ActiveCount
FROM DimDate dt
LEFT JOIN (SELECT 'Active' as 'EmpStatus', * FROM DimEmployee) emp
-- regular active employees
ON (dt.FullDateAlternateKey between emp.StartDate and ISNULL(emp.EndDate,'9999-12-31'))
WHERE
dt.FullDateAlternateKey = EOMONTH(dt.FullDateAlternateKey)
GROUP BY
dt.FullDateAlternateKey
ORDER BY
1;
also found CTE use for finding employee hierarchy
WITH DirectReports (ManagerID, EmployeeID, Title, DeptID, Level)
AS
(
-- Anchor member definition
SELECT e.ParentEmployeeKey, e.EmployeeKey, e.Title, e.DepartmentName,
0 AS Level
FROM DimEmployee AS e
WHERE e.ParentEmployeeKey IS NULL
UNION ALL
-- Recursive member definition
SELECT e.ParentEmployeeKey, e.EmployeeKey, e.Title, e.DepartmentName,
Level + 1
FROM DimEmployee AS e
INNER JOIN DirectReports AS d
ON e.ParentEmployeeKey = d.EmployeeID
)
-- Statement that executes the CTE
SELECT ManagerID, EmployeeID, Title, DeptID, Level
FROM DirectReports
WHERE DeptID = 'Information Services' OR Level = 0
also, some good queries to analyze the sales data
-- Show each sales average for Group, Country, and Region all in one query
SELECT DISTINCT
t.SalesTerritoryGroup
, t.SalesTerritoryCountry
, t.SalesTerritoryRegion
, AVG(s.SalesAmount) OVER(PARTITION BY t.SalesTerritoryGroup ) as 'GroupAvgSales'
, AVG(s.SalesAmount) OVER(PARTITION BY t.SalesTerritoryCountry ) as 'CountryAvgSales'
, AVG(s.SalesAmount) OVER(PARTITION BY t.SalesTerritoryRegion ) as 'RegionAvgSales'
FROM FactInternetSales s
JOIN DimSalesTerritory t ON
s.SalesTerritoryKey = t.SalesTerritoryKey
WHERE
YEAR(s.OrderDate) = 2013
ORDER BY
1,2,3
Use additional aggregations to understand more about product sales such as the distribution of sales etc..
SELECT
cat.EnglishProductCategoryName 'Category'
, sub.EnglishProductSubcategoryName 'SubCategory'
, count(1) 'Count' -- How many sales where there?
, sum(s.SalesAmount) 'Sales' -- How much sales did we have?
, avg(s.SalesAmount) 'Avg_SalesAmount' -- What was the Avg sale amount?
, min(s.SalesAmount) 'Min_SaleAmount' -- What was the Min sale amount?
, max(s.SalesAmount) 'Max_SaleAmount' -- What was the Max sale amount
FROM FactInternetSales s
LEFT JOIN DimProduct p ON s.ProductKey = p.ProductKey
LEFT JOIN DimProductSubcategory sub ON p.ProductSubcategoryKey = sub.ProductSubcategoryKey
LEFT JOIN DimProductCategory cat ON sub.ProductCategoryKey = cat.ProductCategoryKey
-- must use group by in order for aggregation to work properly
GROUP BY
cat.EnglishProductCategoryName -- column aliases aren't allowed
, sub.EnglishProductSubcategoryName
ORDER BY
cat.EnglishProductCategoryName
, sub.EnglishProductSubcategoryName
-- Calculate the customer acquisition funnel
SELECT
c.FirstName
, c.LastName
, c.DateFirstPurchase
, DATEDIFF(d,c.DateFirstPurchase,getdate()) as 'DaysSinceFirstPurchase' -- How long have they been a customer?
FROM DimCustomer c
ORDER BY 3 DESC
-- Calculate a Monthly average of customer tenure
SELECT
EOMONTH(c.DateFirstPurchase) as 'MonthOfFirstPurchase' -- What month did they become a customer?
, DATEDIFF(d,EOMONTH(c.DateFirstPurchase),getdate()) as 'DaysSinceFirstPurchase' -- How long have they been a customer?
, COUNT(1) as 'CustomerCount' -- How manY customers are there for this month?
FROM DimCustomer c
GROUP BY EOMONTH(c.DateFirstPurchase)
ORDER BY 2 DESC
-- Show the top product Sub Categories for each year
SELECT
count(DISTINCT s.SalesOrderNumber) 'OrderCount' -- use 1 instead of a field for faster performance
, RANK() OVER (PARTITION BY YEAR(s.OrderDate) ORDER BY sum(s.SalesAmount) DESC) 'SalesRank'
, sum(s.SalesAmount) 'TotalSales'
, cat.EnglishProductCategoryName 'Category'
, sub.EnglishProductSubcategoryName 'SubCategory'
, YEAR(s.OrderDate) 'Year'
FROM FactInternetSales s
INNER JOIN DimProduct p ON s.ProductKey = p.ProductKey
INNER JOIN DimProductSubcategory sub ON p.ProductSubcategoryKey = sub.ProductSubcategoryKey
INNER JOIN DimProductCategory cat ON sub.ProductCategoryKey = cat.ProductCategoryKey
-- must use group by in order for aggregation to work properly
GROUP BY
cat.EnglishProductCategoryName -- column aliases aren't allowed
, sub.EnglishProductSubcategoryName
, YEAR(s.OrderDate)
ORDER BY YEAR(s.OrderDate), SUM(s.SalesAmount) DESC;
-- first, create weekly sales totals
SELECT SUM(s.SalesAmount) 'WeeklySales'
, DATEPART(ww, s.OrderDate) as 'WeekNum'
FROM FactInternetSales s
WHERE YEAR(s.OrderDate) = 2013
GROUP BY
DATEPART(ww, s.OrderDate)
ORDER BY
DATEPART(ww, s.OrderDate) ASC
-- use that subquery as our source and calculate the moving average
SELECT
AVG(WeeklySales) OVER (ORDER BY WeekNum ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) as AvgSales
, WeeklySales as 'TotalSales'
, WeekNum
FROM (
SELECT SUM(s.SalesAmount) 'WeeklySales'
, DATEPART(ww, s.OrderDate) as 'WeekNum'
FROM FactInternetSales s
WHERE YEAR(s.OrderDate) = 2013
GROUP BY
DATEPART(ww, s.OrderDate)
) AS s
GROUP BY
WeekNum, WeeklySales
ORDER BY
WeekNum ASC
-- Running Total
SELECT
SUM(MonthlySales) OVER (PARTITION BY SalesYear ORDER BY SalesMonth ROWS UNBOUNDED PRECEDING) as YTDSales
, MonthlySales as 'MonthlySales'
, SalesYear
, SalesMonth
FROM (
SELECT SUM(s.SalesAmount) 'MonthlySales'
, MONTH(s.OrderDate) as 'SalesMonth'
, year(s.OrderDate) as 'SalesYear'
FROM FactInternetSales s
GROUP BY
MONTH(s.OrderDate)
, year(s.OrderDate)
) AS s
GROUP BY
SalesMonth, SalesYear, MonthlySales
ORDER BY
SalesYear, SalesMonth ASC
-- Get Prev Year Sales
WITH MonthlySales (YearNum, MonthNum, Sales)
AS
(
SELECT d.CalendarYear, d.MonthNumberOfYear, SUM(s.SalesAmount)
FROM DimDate d
JOIN FactInternetSales s ON d.DateKey = s.OrderDateKey
GROUP BY d.CalendarYear, d.MonthNumberOfYear
)
-- Get Current Year and join to CTE for previous year
SELECT
d.CalendarYear
, d.MonthNumberOfYear
, ms.Sales PrevSales
, SUM(s.SalesAmount) CurrentSales
FROM DimDate d
JOIN FactInternetSales s ON d.DateKey = s.OrderDateKey
JOIN MonthlySales ms ON
d.CalendarYear-1 = ms.YearNum AND
d.MonthNumberOfYear = ms.MonthNum
GROUP BY
d.CalendarYear
, d.MonthNumberOfYear
, ms.Sales
ORDER BY
1 DESC, 2 DESC
-- Now calculate the % change Year over Year
WITH MonthlySales (YearNum, MonthNum, Sales)
AS
(
SELECT d.CalendarYear, d.MonthNumberOfYear, SUM(s.SalesAmount)
FROM DimDate d
JOIN FactInternetSales s ON d.DateKey = s.OrderDateKey
GROUP BY d.CalendarYear, d.MonthNumberOfYear
)
-- Get Current Year and join to CTE for previous year
SELECT
d.CalendarYear
, d.MonthNumberOfYear
, ms.Sales PrevSales
, SUM(s.SalesAmount) CurrentSales
, (SUM(s.SalesAmount) - ms.Sales) / SUM(s.SalesAmount) 'PctGrowth'
FROM DimDate d
JOIN FactInternetSales s ON d.DateKey = s.OrderDateKey
JOIN MonthlySales ms ON
d.CalendarYear-1 = ms.YearNum AND
d.MonthNumberOfYear = ms.MonthNum
GROUP BY
d.CalendarYear
, d.MonthNumberOfYear
, ms.Sales
ORDER BY
1 DESC, 2 DESC

Error GROUP BY Dates MysQL

I am trying to group by dates 2 different tables. However, something is going wrong as I am not able to group by dates.
I have 2 tables First "Budget" and Second "Sales Performance By Region"
The Idea is to show the Budget for all the months (12 months)
and each month we have data we will see the Sales for each specific month.
SELECT
BB.RG,
BB.YEAR,
DATE_FORMAT( BB.MONTH, '%M' ) AS `MONTH`,
SPR.Bookings,
SPR.`Bookings PY`,
SPR.Billing,
SPR.`Billing PY`,
SPR.`GP Amt`,
SPR.`GP Amt PY`,
SUM( BB.BUDGET ) AS BUDGET
FROM
BRANCH_BUDGET BB
LEFT JOIN Sales_Performance_Region SPR
ON BB.MONTH = SPR.MONTH
WHERE
BB.RG = 'FE'
AND SPR.RG = 'FE'
AND BB.YEAR = '2018'
GROUP BY
BB.MONTH
Above you can see the code. Instead of showing the 12 Months due to I only have data for 2 Months is showing January and February.
I hope the question makes sense. Can you guide me?
Whenever you invoke a GROUP BY after a WHERE statement or any other aggregate function inside a SELECT statement you will need to treat everything inside the select statement as an aggregate, otherwise you will face problems:
In your code:
SELECT `BRANCH_BUDGET`.`RG` ,
`BRANCH_BUDGET`.`YEAR` AS `YEAR` ,
`DATE_FORMAT( `BRANCH_BUDGET`.`MONTH` , '%M' ) AS `MONTH` ,
`Sales_Performance_Region`.`Bookings` ,
`Sales_Performance_Region`.`Bookings PY` ,
`Sales_Performance_Region`.`Billing` ,
`Sales_Performance_Region`.`Billing PY` ,
`Sales_Performance_Region`.`GP Amt` ,
`Sales_Performance_Region`.`GP Amt PY` ,
SUM( `BRANCH_BUDGET`.`BUDGET` ) AS `BUDGET`
FROM (
`BRANCH_BUDGET`
LEFT JOIN `Sales_Performance_Region` ON ( `BRANCH_BUDGET`.`MONTH` =
`Sales_Performance_Region`.`MONTH` )
)
WHERE `BRANCH_BUDGET`.`RG` = 'FE'
AND `Sales_Performance_Region`.`RG` = 'FE'
AND `BRANCH_BUDGET`.`YEAR` = '2018'
GROUP BY `BRANCH_BUDGET`.`MONTH`
You only group by BRANCH_BUDGET.MONTH, but do not group by any other column or perform an aggregate function on any other column (save BRANCH_BUDGET.BUDGET). Thus your output is faulty in that it only returns two months.
First thanks for the comments I want to post the result in case someone is interested.
The issue was: I didn't join the Region (RG) from both tables. So the result should look like the code below:
SELECT `BRANCH_BUDGET`.`RG` ,
`BRANCH_BUDGET`.`YEAR` AS `YEAR` ,
DATE_FORMAT( `BRANCH_BUDGET`.`MONTH` , '%M' ) AS `MONTH` ,
`Sales_Performance_Region`.`Bookings` ,
`Sales_Performance_Region`.`Bookings PY` ,
`Sales_Performance_Region`.`Billing` ,
`Sales_Performance_Region`.`Billing PY` ,
`Sales_Performance_Region`.`GP Amt` ,
`Sales_Performance_Region`.`GP Amt PY` ,
SUM( `BRANCH_BUDGET`.`BUDGET` ) AS `BUDGET`
FROM (
`BRANCH_BUDGET`
LEFT JOIN `Sales_Performance_Region`
ON ( `Sales_Performance_Region`.`MONTH` = `BRANCH_BUDGET`.`MONTH` )
AND ( `Sales_Performance_Region`.`RG` = `BRANCH_BUDGET`.`RG` )
)
WHERE `BRANCH_BUDGET`.`RG` = 'FE'
AND `BRANCH_BUDGET`.`YEAR` = '2018'
GROUP BY `BRANCH_BUDGET`.`MONTH`

Use join for three tables

I have three tables and I would like sum over values by month from three tables.
The structure of database:
1)costs_1
-id
-total
-updated_at(timestamp)
2)costs_2
-id
-total_1
-updated_at_1(timestamp)
3)costs_3
-id
-total_2
-updated_at_2(timestamp)
Structure of result table: 1)total; 2)total_1; 3)total_2; 4)month
I have code that work for two tables, but don't know how to adapte it
SELECT t1.y year,
t1.m month,
COALESCE(t1.total, 0),
COALESCE(t2.total, 0)
FROM
(
SELECT YEAR(date_month) y,
MONTH(date_month) m,
SUM(total) total
FROM market_costs
GROUP BY YEAR(date_month), MONTH(date_month)
) t1
LEFT JOIN
(
SELECT YEAR(date_month) y,
MONTH(date_month) m,
SUM(total) total
FROM general_costs
GROUP BY YEAR(date_month), MONTH(date_month)
) t2 ON t1.y = t2.y and t1.m = t2.m
UNION
SELECT t2.y year,
t2.m month,
COALESCE(t1.total, 0),
COALESCE(t2.total, 0)
FROM
(
SELECT YEAR(date_month) y,
MONTH(date_month) m,
SUM(total) total
FROM market_costs
GROUP BY YEAR(date_month), MONTH(date_month)
) t1
RIGHT JOIN
(
SELECT YEAR(date_month) y,
MONTH(date_month) m,
SUM(total) total
FROM general_costs
GROUP BY YEAR(date_month), MONTH(date_month)
) t2 ON t1.y = t2.y and t1.m = t2.m
Combine the 3 tables using UNION ALL then group the data:
SELECT
YEAR(t1.date_month) y
, MONTH(t1.date_month) m
, SUM(t1.total) total
, SUM(t1.total_1) total_1
, SUM(t1.total_2) total_2
FROM (
SELECT
date_month
, total
, NULL as total_1
, NULL as total_2
FROM costs
UNION ALL
SELECT
date_month
, NULL as total
, total_1
, NULL as total_2
FROM costs_1
UNION ALL
SELECT
date_month
, NULL as total
, NULL as total_1
, total_2
FROM costs_2
) t1
GROUP BY
YEAR(t1.date_month)
, MONTH(t1.date_month)
added
SELECT
YEAR(t1.date_month) y
, MONTH(t1.date_month) m
, SUM(t1.total) total
, SUM(t1.total_1) total_1
, SUM(t1.total_2) total_2
FROM (
SELECT
date_month
, total
, NULL as total_1
, NULL as total_2
FROM costs
UNION ALL
SELECT
date_month
, NULL as total
, total as total_1 -- changed
, NULL as total_2
FROM costs_1
UNION ALL
SELECT
date_month
, NULL as total
, NULL as total_1
, total as total_2 -- changed
FROM costs_2
) t1
GROUP BY
YEAR(t1.date_month)
, MONTH(t1.date_month)

Create a Running Balance Total on Query with Union

We have a webapp that tracks rewards points for customers. We are using a MySQL database.
I originally had a query that pulled data from a single table and showed the amount of points in each transaction along with the balance (RunningTotal) the code is below:
SELECT DateSubmitted
, PointTotal as Points
, ( SELECT SUM( PointTotal )
FROM ptrans_detail x
WHERE x.CustID = a.CustID
AND ( x.DateSubmitted < a.DateSubmitted OR x.DateSubmitted = a.DateSubmitted) ) AS RunningTotal
, comment
FROM ptrans_detail a
WHERE CustID='10009'
Order by TransID Desc
This worked fine until it was discovered that there were some entries that didn't exists in the ptrans_detail table and that question was posted here:
Query Data from 2 MySQL tables with some duplicate records
As suggested, I used UNION to combine 2 queries from 2 tables to get ALL the records, that query is:
SELECT CustID
, DateSubmitted
, Type
, Points
FROM `trans_summary`
WHERE CustID = '10009'
UNION
SELECT CustID
, DateSubmitted
, Type
, PointTotal
FROM `ptrans_detail`
WHERE CustID = '10009'
and DateSubmitted NOT IN
(SELECT DateSubmitted FROM
`trans_summary`
WHERE CustID = '10009')
That worked great but now I would like to add the RunningTotal to this like in the first query. Is this possible?
Do you want this:
SELECT CustID, DateSubmitted, Type, SUM(Points) FROM (SELECT CustID
, DateSubmitted
, Type
, Points
FROM `trans_summary`
WHERE CustID = '10009'
UNION
SELECT CustID
, DateSubmitted
, Type
, PointTotal as Points
FROM `ptrans_detail`
WHERE CustID = '10009'
and DateSubmitted NOT IN
(SELECT DateSubmitted FROM
`trans_summary`
WHERE CustID = '10009')) AS tr_summery
I would advise you to use union all, unless you really need union.
The easiest way to get a running sum in MySQL is to use variables:
SELECT t.*,
(#sump := if(#c = CustId, #sump + Points,
if(#c := CustId, Points, Points)
)
) as runningTotal
FROM (SELECT CustID, DateSubmitted, Type, Points
FROM trans_summary
WHERE CustID = '10009'
UNION ALL -- Maybe it should be `UNION`
SELECT CustID, DateSubmitted, Type, PointTotal
FROM ptrans_detail
WHERE CustID = '10009' AND
DateSubmitted NOT IN (SELECT ts.DateSubmitted FROM trans_summary ts WHERE ts.CustID = '10009')
) t CROSS JOIN
(SELECT #c := -1, #sump := 0) params
ORDER BY CustId, DateSubmitted;

Get the count and total count joining 2 tables in mysql

I have 2 tables in the MySQL database :
1.
p_code{
code varchar(10) primary key,
discount decimal(4,2) not null,
valid_till date not null,
daily int not null,
total int non null,
max_amount decimal (6, 2) not null
}
2.
p_user{
code varchar(10) not null,
email varchar(50) not null,
date date not null,
primary key (code, email, date),
foreign key (code) references p_code(code)
}
now I want to get for a code in p_code total how many times an email has been used, total how many time the email has been used today and the details of the code.
I have tried the following query :
SELECT pc.discount, pc.valid, pc.daily, pc.total, pc.max_amount, c.tcount, c.count
FROM p_code AS pc
LEFT JOIN (
SELECT t.code, t.email, t.tcount, p.count
FROM (
SELECT code, email, COUNT( email ) AS tcount
FROM p_user
GROUP BY code, email
) AS t
LEFT JOIN (
SELECT code, email, COUNT( email ) AS count
FROM p_user
WHERE `date` = CURDATE( )
GROUP BY code, email
) AS p ON ( t.code, t.email ) = ( p.code, p.email )
) AS c ON pc.code = c.code
WHERE c.email = ?
AND pc.code = ?
But the problem is that if I do not have any entry for the code and email in the table p_user, it does not return any row.
What I require that it should return all the columns from p_code and 0 and 0 for tcount and count columns.
I think you can simplifiy your query this way, and anyway you'll need to put the condition on the left joined data... in the left join.
SELECT
c.discount,
c.valid,
c.daily,
c.total,
c.max_amount,
count(u.email) as totalCount,
sum(case when u.`date` = CURDATE() then 1 else 0 end) as dailyCount
FROM p_code c
LEFT JOIN p_user u on u.code = c.code and u.email = ?
WHERE c.code = ?
GROUP BY c.discount, c.valid, c.daily, c.total, c.max_amount
You could also do, for the "filter" on email :
WHERE c.code = ? and (u.email is null or u.email = ?)
You need to use the IFNULL function.
IFNULL(expr1,expr2)
If expr1 is not NULL, IFNULL() returns expr1; otherwise it returns
expr2.
You need to modify your query like:
SELECT pc.discount
, pc.valid
, pc.daily
, pc.total
, pc.max
, IFNULL(c.tcount, 0) AS tcount
, IFNULL(c.count, 0) as count
FROM p_code AS pc
...