How do add together a COUNT() using SUM()? - mysql

Basically, I have this -
SELECT COUNT(student_dormpm.DormCode) * dorm_datapm.DormCharge
FROM student_dormpm
JOIN dorm_datapm
USING (DormCode)
GROUP BY DormCode;
with a result of
+---------------------------------------------------------+
| COUNT(student_dormpm.DormCode) * dorm_datapm.DormCharge |
+---------------------------------------------------------+
| 5250.00 |
| 11250.00 |
| 9600.00 |
| 6500.00 |
| 5510.00 |
+---------------------------------------------------------+
But whenever I try to add SUM(), it falls apart and I get an error of Invalid use of group function.
I've tried this SUM(COUNT(student_dormpm.DormCode) * dorm_datapm.DormCharge)

Use sum on entire the first query output where an alias name say t is specified to the first query output (to simulate a new table) and also an alias say total specified to the counter so you can calculate sum(total):
select sum(total) as mysum from
(
SELECT COUNT(student_dormpm.DormCode) * dorm_datapm.DormCharge as total
FROM student_dormpm
JOIN dorm_datapm
USING (DormCode)
GROUP BY DormCode
) t

It looks like dorm_datapm is your dorm table that has one record per DormCode with the associated DormCharge. (In that case a table name dorm ight be more appropriate, though.)
If this is so, then you merely want to sum up the dorm charges:
SELECT DormCode, SUM(dd.DormCharge)
FROM student_dormpm sd
JOIN dorm_datapm dd USING (DormCode)
GROUP BY DormCode
ORDER BY DormCode;
If, however dorm_datapm can have multiple records per DormCode, then you'll have to see, whether above query gets you the results you want or if you want to join a student_dormpm row with only one dorm_datapm row (in which case you would have to extend your join criteria somehow).
If you are only looking for the total, then don't group by DormCode:
SELECT SUM(dd.DormCharge)
FROM student_dormpm sd
JOIN dorm_datapm dd USING (DormCode);

Related

I need getting data from multiple tables, with COUNT included?

I need to create a query from 2 tables, where my company stores e-shop information.
Example of data from the first table:
currentDate: 5.5.2022 | eshopId: 1 | eshopName: test | active: true |
Table 2:
currentDate: 5.5.2022 | eshopId: 1 | orderId: 123 | attribution: direct |
From the first table, I want get how many days in a given period the eshop was active. From the second table, I would like to count all the orders that were attributed directly to our company in the same time period as in the first table.
SELECT i.id, count(*)
from table1 as i
FULL JOIN table1 as e ON e.id= i.id
WHERE i.active = TRUE
GROUP BY i.id
I tried merging the same table twice, because after I used count to get amount of inactive dates, I could not use another variable as it was not aggregated. This still does not work. I cannot imagine how I would do this for 3 tables. Can someone please point me in the right direction on how to do this? Thanks.
If there is one row for each day per eshopId and you want to count number of active days along with number of order per eshopId:
SELECT i.eshopId, count(*)
from table1 as i
left join (select eshopId, count(distinct orderId) from table2 group by eshopId) j on i.eshopId=j.eshopId
WHERE i.active = TRUE
GROUP BY i.eshopId

SQL - Average number of related records with group_by

I have a table of records (lets call them TV shows) with an air_date field.
I have another table of advertisements that are related by a show_id field.
I am trying to get the average number of advertisements per show for each date (with a where clause specifying the shows).
I currently have this:
SELECT
`air_date`,
(SELECT COUNT(*) FROM `commercial` WHERE `show_id` = `show`.`id`) AS `num_commercials`,
FROM `show`
WHERE ...
This gives me a result like so:
air_date | num_commercials
2015-6-30 | 6
2015-6-30 | 3
2015-6-30 | 8
2015-6-30 | 2
2015-6-31 | 9
2015-6-31 | 4
When I do a GROUP_BY, it only gives me one of the records, but I want the average for each air_date.
Not too sure I am clear on what you want - but does this do it
SELECT `air_date`,
AVG((SELECT COUNT(*) FROM `commercial` WHERE `show_id` = `show`.`id`)) AS `num_commercials`,
FROM `show`
WHERE .....
GROUP BY `air_date`
(Note double parentheses for AVG function is required)
You can use a sub-query to select count of commercials by air_date/show, then use an outer query to select the average commercials count per air_date.
Something like this should work:
select air_date, avg(num_commercials)
from
(
select show.air_date as air_date,
show.id as show_id,
count(*) as num_commercials
from show
inner join commercial on commercial.show_id = show.id
group by show.air_date, show.id
where ...
) sub
group by air_date

MySQL Query - Select most recent configuration and most recent action

I really need help solving this problem with a single query.
I have four tables:
[Assets]
[id | serial_number | date_created] (other stuff)
[Parts]
[id | unit_number | date_created] (other stuff)
[Groups]
[id | asset_id | part_id | date_created] (other stuff)
[Activity]
[id | group_id | date_recorded | action_id] (other stuff)
How can I select all the assets and find their most recent pairing (group) and within that group their latest activity. In one record row.
EDIT: What I Have tried:
I did it with php but it is extremely ugly and requires three separate queries.
I selected all the attributes from each table via a separate SELECT, which I assume is a horrible way of doing it
SELECT
*,
(
SELECT
part_id
FROM
groups
ORDER BY
date_created
DESC
LIMIT 1
) AS part_id
FROM
assets
To grab just the part_id I do a nested select, but if I need 9 attributes I need 9 nested selects which is a bad way?
Your query suggests the following:
SELECT *
FROM assets a cross join
(select *
from groups
order by date_created
limit 1
) g
However, I suspect that you might really want to join assets and groups on some field (group id? part id?) and choose the most recent record based on that field. The following query does this, assuming parts is the matching field:
SELECT *
FROM assets a join
(select *
from groups g join
(select g.part_id, max(date_created) as maxdate
from groups g
group by g.part-id
) gmax
on g.part_id = gmax.part_id and
g.date_created = gmax.maxdate
) g
on a.parts_id = g.parts_id

Group-by in MySQL: how to specify which data to show from the other columns

Sorry for the ambiguous title; but I don't now how to describe it different.
I have the following table:
imei | date | time | some more fields
345 | 2012-06-28 | 07:18 | .....
345 | 2012-06-28 | 07:20 | .....
345 | 2012-06-28 | 07:21 | .....
987 | 2012-06-28 | 07:19 | .....
etc etc
I want to get the latest row of ervery distinct imei, so:
345 | 2012-06-28 | 07:21
987 | 2012-06-28 | 07:19
Using SELECT * FROM t GROUP BY imei results in using the first line instead of the last one.
Ordering by time obviously orders the result relation instead of the sub.
Using having is only for stating a condition....
How can I write a query to do this?
As stated in the manual:
The server is free to choose any value from each group, so unless they are the same, the values chosen are indeterminate. Furthermore, the selection of values from each group cannot be influenced by adding an ORDER BY clause. Sorting of the result set occurs after values have been chosen, and ORDER BY does not affect which values the server chooses.
To obtain the groupwise maximum (as you want), you need to join the result of a grouped subquery with your table:
SELECT * FROM t JOIN (
SELECT imei, MAX(ADDTIME(date, time)) AS dt FROM t GROUP BY imei
) AS u ON t.imei = u.imei AND t.date = DATE(u.dt) AND t.time = TIME(u.dt)
Fahim is right. Separated date and time columns make life unnecessarily difficult. No matter.
Try this.
SELECT IMEI, MAX(STR_TO_DATE(CONCAT(`date`,` `,'`time`)))
FROM T
GROUP BY IMEI
You may have to muck about to get the MAX/STR/CONCAT expression just right.
This is a summary query that finds the maximum datetime for each of your IMEI items.
Take a look at that post: How to combine date from one field with time from another field - MS SQL Server
In order to this you can simply use the SQL statement:
SELECT imei, (date+time) AS datim, [some more fields] FROM yourTable;
Then you can use max, min, distinct on the virtual field datim.
maybe you should order by both imei and date, time:
SELECT * FROM t GROUP BY imei ORDER BY imei, date DESC, time DESC

Mode calculation without a subquery field in MySQL?

In my application, each product group has many products, and each product has one manufacturer. These relations are stored by MySQL in InnoDB tables product_groups with an id field, and products with id, product_group and manufacturer fields.
Is there a way to find the most common manufacturer in each product group, without resorting to selecting subqueries?
This is how I'm doing it currently:
SELECT product_groups.id,
(
SELECT manufacturer FROM products
WHERE product_group = product_groups.id
GROUP BY manufacturer
ORDER BY count(*) DESC
LIMIT 1
) manufacturer_mode
FROM product_groups;
Try this solution:
SELECT
a.product_group,
SUBSTRING_INDEX(GROUP_CONCAT(a.manufacturer ORDER BY a.occurrences DESC SEPARATOR ':::'), ':::', 1) AS manufacturer_mode
FROM
(
SELECT
aa.product_group,
aa.manufacturer,
COUNT(*) AS occurrences
FROM
products aa
GROUP BY
aa.product_group,
aa.manufacturer
) a
GROUP BY
a.product_group
Explanation:
This still uses a form of subquery, but one which executes only once as opposed to one that executes on a row-by-row basis such as in your original example.
It works by first selecting the product_group id, the manufacturer, and the count of how many times the manufacturer appears for each particular group.
The FROM sub-select will look something like this after execution (just making up data here):
product_group | manufacturer | occurrences
---------------------------------------------------
1 | XYZ | 4
1 | Test | 2
1 | Singleton | 1
2 | Eloran | 2
2 | XYZ | 1
Now that we have the sub-select result, we need to pick out the row that has the maximum in the occurences field for each product group.
In the outer query, we group the subselect once again by the product_group field, but this time, only the product_group field. Now when we do our GROUP BY here, we can use a really compelling function in MySQL called GROUP_CONCAT which we can use to concatenate the manufacturers together and in any order we want.
...GROUP_CONCAT(a.manufacturer ORDER BY a.occurrences DESC SEPARATOR ':::'...
What we are doing here is concatenating the manufacturers together that are grouped together per product_group id, the ORDER BY a.occurrences DESC makes sure that the manufacturer with the most appearances appears first in the concatenated list. Finally we are separating each manufacturer with :::. The result of this for product_group 1 will look like:
XYZ:::Test:::Singleton
XYZ appears first since it has the highest value in the occurance field. We only want to select XYZ, so we encase the concatenation within SUBSTRING_INDEX, which will allow us to only pick the first element of the list based on the ::: delimiter.
The end result will be:
product_group | manufacturer_mode
---------------------------------------
1 | XYZ
2 | Eloran