avg in query - mysql - mysql

I have this query
SELECT salary
FROM worker W
JOIN single_user U ON u.users_id_user = W.single_user_users_id_user
JOIN university_has_single_user US ON US.single_user_users_id_user = U.users_id_user
JOIN course C ON C.id_course = US.course_id_course
JOIN formation_area FA ON FA.id_formation_area = C.formation_area_id_formation_area
WHERE FA.area = "Multimédia"
GROUP BY users_id_user
...that gave this output:
salary
--------
1400.00
800.00
How can I calculate the avg of this output? If I add:
SELECT round(avg (salary), 0)
...the output is again 1400.00 and 800.00, not the avg (because the group by).

Use:
SELECT AVG(DISTINCT salary)
FROM worker W
JOIN single_user U ON u.users_id_user = W.single_user_users_id_user
JOIN university_has_single_user US ON US.single_user_users_id_user = U.users_id_user
JOIN course C ON C.id_course = US.course_id_course
JOIN formation_area FA ON FA.id_formation_area = C.formation_area_id_formation_area
WHERE FA.area = "Multimédia"
Because the salary column is not wrapped in an aggregate, per the documentation, the values you see are arbitrary (can't be guaranteed 100% of the time).
Usually, you'd need a derived table to get the average of the distinct values but MySQL's AVG supports using DISTINCT within it.

Related

Need count of transactional table based on other tables including zeros where there are no matches

I have four tables, three of which are pretty static: haul_types, dumpster_type_team (the dumpster_type_team has the many-to-many relationship between dumpster_types and teams), and users. The fourth table, hauls, has transactional data.
haul_types:
id
name
dumpster_type_team:
id
dumpster_type_id
team_id
users:
id
first_name
last_name
is_driver
team_id
hauls:
haul_type_id
haul_status_id
set_dumpster_type_id
completed_driver_id
team_id
I would like a query that has a combination of dumpster_types, haul_types, and drivers (users) and a count of the hauls they were involved in. In some cases, there should be a count of zero because some drivers haven't completed hauls for every haul_type / dumpster type combination.
Here's the query I have so far that seems to be behaving as if it is an inner join because the records are getting filtered to only show where there are matches:
SELECT
c.haul_type_id,
c.dumpster_type_id,
c.driver_id,
count(h.id) AS haul_count
FROM
hauls h
RIGHT JOIN ( SELECT DISTINCT
ht.id AS haul_type_id,
dtt.dumpster_type_id AS dumpster_type_id,
dtt.team_id AS team_id,
u.id AS driver_id
FROM
haul_types ht
CROSS JOIN dumpster_type_team dtt
CROSS JOIN users u
WHERE
u.team_id = dtt.team_id
AND u.is_driver = TRUE) c ON c.haul_type_id = h.haul_type_id
AND c.dumpster_type_id = h.set_dumpster_type_id
AND c.driver_id = h.completed_driver_id
AND c.team_id = h.team_id
WHERE
h.team_id = 9
AND h.haul_status_id = 3
AND h.completed_driver_id IS NOT NULL
GROUP BY
c.haul_type_id, c.dumpster_type_id, c.driver_id
When I run the subquery in isolation:
SELECT DISTINCT
ht.id AS haul_type_id,
dtt.dumpster_type_id AS dumpster_type_id,
dtt.team_id AS team_id,
u.id AS driver_id
FROM
haul_types ht
CROSS JOIN dumpster_type_team dtt
CROSS JOIN users u
WHERE
u.team_id = dtt.team_id
AND u.is_driver = TRUE
I get the results I want: a row for each permutation of haul_type, dumpster_type, driver_id, and team_id. However, when I run the entire query, I get filtered results despite the right join.
What I would like to have is the following:
If I have 4 haul_types: delivery, swap, live, pickup
and 2 dumpster_types: 10YD, 15YD
and 2 drivers: 1, 2
I would like a haul count for the combination of haul_type, dumpster_type, and driver. If there are no hauls matching the row, show 0:
Any help is appreciated. Thank you
The description of the question and the query seem to have little to do with each other. I don't know what a "pivot table" is supposed to be.
I would like a query that has a combination of dumpster_types, haul_types, and drivers (users) and a count of the hauls they were involved in.
This sounds like a cross join to generate the rows and then a left join/group by to calculate the results:
select d.dumpster_id, ht.haul_type_id, d.driver_id, count(h.driver_id)
from dumpster_types d cross join
haul_types ht cross join
drivers d left join
hauls h
on h.dumpster_id = d.dumpster_id and
h.haul_type_id = ht.haul_type_id and
h.driver_id = d.driver_id
group by d.dumpster_id, ht.haul_type_id, d.driver_id;
Running the query #GordonLinoff provided, exposed the issue I was facing - when applying a where clause on the top level query, the results were getting filtered to only matches. I moved the where clause to individual subqueries and now I am getting all expected results.
Not sure if this is the most efficient way to write it but it yields the correct results:
SELECT
d.dumpster_type_id,
ht.id AS haul_type_id,
u.id AS driver_id,
count(h.id) AS haul_count
FROM (
SELECT
dumpster_type_id,
team_id
FROM
dumpster_type_team
WHERE
team_id = 9) d
CROSS JOIN haul_types ht
CROSS JOIN (
SELECT
users.id
FROM
users
WHERE
users.is_driver = TRUE
AND users.team_id = 9) u
LEFT JOIN (
SELECT
id, set_dumpster_type_id, haul_type_id, completed_driver_id, team_id
FROM
hauls
WHERE
haul_status_id = 3
AND team_id = 9) h ON h.set_dumpster_type_id = d.dumpster_type_id
AND h.haul_type_id = ht.id
AND h.completed_driver_id = u.id
AND h.team_id = d.team_id
GROUP BY
d.dumpster_type_id,
ht.id,
u.id

Get several data from SQL query based on different conditions

I have the following code:
SELECT DISTINCT m.solde_total_client
,c.client_nom
,co.contenant_nom
FROM `mouvement` m, `client` c, `contenant` co
WHERE c.client_id = m.client_id
AND co.contenant_id = m.contenant_id
ORDER BY m.movement_date DESC
LIMIT 1;
And I get as a result one total sold of one client. But I want to get one for each contenant for each client. (But it still need to be the last one by date)
I'm getting as a result:
And I want to get several result like that such as:
Leclerc | Geobox | 50
SuperU | Box | 40
...
sold_total_client is what the client as after a shipment, there is several shipment and the sold is updated at every move, so the last one by date is the actual sold. So I have to get the last move of every contenant of every client.
You could try using a subquery for max_date group by client_id, contenant_id
SELECT
m.solde_total_client,
m.`mouvement_date`,
c.client_nom,
co.contenant_nom
FROM
`mouvement` m
INNER JOIN
(SELECT
MAX(mouvement_date) max_date, client_id, contenant_id
FROM
`mouvement`
GROUP BY
client_id, contenant_id) t ON t.client_id = m.client_id
AND m.contenant_id = t.contenant_id
AND t.max_date = m.`mouvement_date`
INNER JOIN
`client` c ON c.client_id = m.client_id
INNER JOIN
`contenant` co ON co.contenant_id = m.contenant_id
ORDER BY
m.`mouvement_date`

Create One Result set from 3 different Queries

I am trying to create a result set using three queries. I have three tables an inventory table, a form order table, and a form order detail table. I need to be able to input a date range and get how many forms were ordered, how many are in current inventory, and how many were destroyed based on if they contain a destruction date. Ultimately i want a result set that shows:
InventoryId, FormDescription, Product, Ordered, Shipped, Destroyed, Total ending
What would be the best way to get that result set using these queries?
These are my three Queries
SELECT FOD.InventoryId, SUM(FOD.FormOrderAmount) as totalOrdered, FOD.FormShippedAmount FROM tblFormOrder FMO
JOIN tblFormOrderDetails FOD ON FOD.FormOrderId = FMO.FormOrderId
WHERE FMO.OrderDateTime BETWEEN '20110101' and '20120101'
AND FMO.OrderStatus IN ('S')
GROUP BY FOD.InventoryId, FOD.FormShippedAmount -- total shipped by date and inventoryid
SELECT INV.InventoryId, SUM(INV.CurrentAmount) as currentAmount, SUM(INV.OrderAmount) as OrderAmount,
(SUM(INV.OrderAmount) - SUM(INV.CurrentAmount)) as InventoryUsed
FROM tblInventory INV
where INV.CreatedOn
BETWEEN '20110101' and '20120101'
GROUP BY INV.InventoryId -- current amount based off ordered and used
select INV.InventoryId, count(*) as total
, FMO.OrderDateTime as OrderDate, Inv.FormNo, INV.FormDescription, INV.Product
from [tblinventory] INV
join tblformorderdetails FOD ON FOD.InventoryId = inv.InventoryId
join tblformorder FMO on FMO.FormOrderId = FOD.FormOrderId
where INV.DestructionDate
BETWEEN '20110101' and '20120101'
group by
FMO.OrderDateTime,
Inv.FormNo, INV.FormDescription, INV.Product, INV.InventoryId -- using count to find how many destroyed if they have a destruction date
If you want an inner join you can do this
SELECT *
FROM (...) AS Q1, (...) AS Q2, (...) AS Q3
WHERE Q1.InventoryID = Q2.InventoryID AND Q2.InventoryID = Q3.InventoryID
This will only give you the InventoryIDs that are in all 3 queries.
You probably don't want this you probably want all inventory IDs... so you do this.
SELECT *
FROM (SELECT DISTINCT InventoryID FROM tblFormOrderDetails
UNION ALL
SELECT DISTINCT InventoryID FROM tblInventory) I
LEFT JOIN (...) Q1 ON I.InventoryID = Q1.InventoryId
LEFT JOIN (...) Q2 ON I.InventoryID = Q2.InventoryId
LEFT JOIN (...) Q3 ON I.InventoryID = Q3.InventoryId
Make each query a subquery that you join together.
SELECT *
FROM (
SELECT FOD.InventoryId, SUM(FOD.FormOrderAmount) as totalOrdered, FOD.FormShippedAmount FROM tblFormOrder FMO
JOIN tblFormOrderDetails FOD ON FOD.FormOrderId = FMO.FormOrderId
WHERE FMO.OrderDateTime BETWEEN '20110101' and '20120101'
AND FMO.OrderStatus IN ('S')
GROUP BY FOD.InventoryId, FOD.FormShippedAmount -- total shipped by date and inventoryid
) AS q1
LEFT JOIN (
SELECT INV.InventoryId, SUM(INV.CurrentAmount) as currentAmount, SUM(INV.OrderAmount) as OrderAmount,
(SUM(INV.OrderAmount) - SUM(INV.CurrentAmount)) as InventoryUsed
FROM tblInventory INV
where INV.CreatedOn
BETWEEN '20110101' and '20120101'
GROUP BY INV.InventoryId -- current amount based off ordered and used
) AS q2 ON q1.InventoryId = q2.InventoryId
LEFT JOIN (
select INV.InventoryId, count(*) as total
, FMO.OrderDateTime as OrderDate, Inv.FormNo, INV.FormDescription, INV.Product
from [tblinventory] INV
join tblformorderdetails FOD ON FOD.InventoryId = inv.InventoryId
join tblformorder FMO on FMO.FormOrderId = FOD.FormOrderId
where INV.DestructionDate
BETWEEN '20110101' and '20120101'
group by
FMO.OrderDateTime,
Inv.FormNo, INV.FormDescription, INV.Product, INV.InventoryId -- using count to find how many destroyed if they have a destruction date
) AS q3 ON q1.InventoryId = q3.InventoryId

How to filter on Access Report subtotal

Have an access report that shows training programs, and which employees should be but are not trained on that program. This query is fine. Problem is that we want to only display on the report training programs which have more than 10 employees untrained. So we have the total of untrained for each program in a subtotal, but we want to filter on that value.
How can this be done?
EDIT:
Here is pass-through query to SQL Server
SELECT T.ProgramTitle
,T.ProgramCode
,AE.Code AS 'AvantiCode'
,AE.FullName
,AE.FirstName
,AE.LastName
,AE.Department
,C.Position
,AE.Shift
FROM HR_Curriculum C
INNER JOIN HR_Trainings T ON C.TrainingID = T.TrainingID
INNER JOIN HR_EmployeeDetails ED ON C.Position = ED.Postion
INNER JOIN Avanti_Employees AE ON ED.AvantiRecID = AE.RecID
LEFT JOIN HR_Employeetrainings ET ON C.TrainingID = ET.TrainingID
AND ED.AvantiRecID = ET.AvantiRecID
LEFT JOIN HR_TrainingVersion V ON V.VersionID = ET.VersionID
WHERE terminated = 0
AND T.Active = - 1
AND CompletedDate IS NULL
GROUP BY T.ProgramTitle
,T.ProgramCode
,AE.Code
,AE.FullName
,AE.FirstName
,AE.LastName
,AE.Department
,C.Position
,AE.Shift
Order by programtitle
Consider an inline view, using a grouped by table alias with HAVING clause.
Try adding one more inner join:
INNER JOIN
(SELECT TrainingID, ProgramTitle, ProgramCode
FROM HR_Trainings
GROUP BY TrainingID, ProgramTitle, ProgramCode
HAVING Count(TrainingID) > 10) AS Trainings10More
ON Trainings10More.TrainingID = T.TrainingID

counting methodolegy in SQL Server query

Good day everyone…
I have a database that has the following:
Division table that linked to Employee table.
Group table, i.e. courses categories, that linked to Courses table.
and these table linked together thru Curses_Employee table .
so far I managed to come up with a query that give me the number of users who toke certain course in each group/category like the following output table:
groupName | DivisionName| courseName|Total Number of Participants
and here is my query for the above scheme:
SELECT dbo.groups.GroupName, dbo.Divisions.DivisionName, dbo.courses.CourseName, COUNT(dbo.employee_courses.courseId) AS [Total Number of Participants]
FROM dbo.employee AS employee_1 INNER JOIN
dbo.Divisions ON employee_1.DivisionCode = dbo.Divisions.SapCode INNER JOIN
dbo.employee_courses ON employee_1.Username = dbo.employee_courses.employeeId INNER JOIN
dbo.courses ON dbo.employee_courses.courseId = dbo.courses.CourseID INNER JOIN
dbo.groups ON dbo.courses.GroupID = dbo.groups.ID
WHERE (dbo.courses.GroupID = 2)
GROUP BY dbo.courses.CourseID, dbo.courses.CourseName, dbo.Divisions.DivisionName, dbo.groups.GroupName
now I want to add two columns the total number of employee in each division as well as the % like the following table:
groupName | DivisionName| courseName|Total Number of Participants |Total Number of Employee |%
I tried this query but it give me an error:
SELECT dbo.groups.GroupName, dbo.Divisions.DivisionName, dbo.courses.CourseName, COUNT(dbo.employee_courses.courseId) AS [Total Number of Participants],
(SELECT COUNT(Name) AS Expr1
FROM dbo.employee
WHERE (DivisionCode = employee_1.DivisionCode)
GROUP BY DivisionCode) AS [Total Number of Employee]
FROM dbo.employee AS employee_1 INNER JOIN
dbo.Divisions ON employee_1.DivisionCode = dbo.Divisions.SapCode INNER JOIN
dbo.employee_courses ON employee_1.Username = dbo.employee_courses.employeeId INNER JOIN
dbo.courses ON dbo.employee_courses.courseId = dbo.courses.CourseID INNER JOIN
dbo.groups ON dbo.courses.GroupID = dbo.groups.ID
WHERE (dbo.courses.GroupID = 2)
GROUP BY dbo.courses.CourseID, dbo.courses.CourseName, dbo.Divisions.DivisionName, dbo.groups.GroupName
the error message:
column 'dbo.employee.DivisionCode' is invalid in the select list
because it is not contained in either as aggregate function or the
GROUP BY clause.