I am trying to figure out the most occurring values within a table in groups.
This is for SQL
Part | location | PartDesc
-----+----------+-------------
A | 2 | Part A
A | 2 | Part A
A | 2 | Part A
A | 1 | Part A
A | 1 | Part A
B | 1 | Part B
B | 2 | Part B
So the output needs to show
Part | Location | PartDesc | Occurrence
-----+----------+----------+--------------
A | 2 | Part A | 3
A | 1 | Part A | 2
B | 1 | Part B | 1
B | 2 | Part B | 1
So far I have
Select Part, count(*) as occurrence
from table1
group by Part
order by count(*desc)
SELECT
Part,
Location,
PartDesc,
COUNT(*) AS Occurrence
FROM
table1
GROUP BY
Part,
Location,
PartDesc
ORDER BY
Occurrence DESC
Thanks.
Related
I wanted to get badge list with issued times.
This is brief info of my tables.
table Badge:
+----+-----------+
| id | name |
+----+-----------+
| 1 | professor |
| 2 | campaign |
| 3 | test |
+----+-----------+
table issue_history:
+----+-----------+--------+
| id | badge_id | ts |
+----+-----------+--------+
| 1 | 1 | 0908 |
| 2 | 1 | 0909 |
| 3 | 3 | 0909 |
+----+-----------+--------*
To get result I used LEFT JOIN.
SELECT
b.id,
b.name,
COUNT(*) AS issued_times
FROM
badge b
LEFT JOIN
issue_history h
ON
b.id = h.badge_id
GROUP BY
b.id
I expected result like below
+----+-----------+--------------+
| id | name | issued_times |
+----+-----------+--------------+
| 1 | professor | 2 |
| 2 | campaign | 0 |
| 3 | test | 1 |
+----+-----------+--------------+
But I got wrong result
+----+-----------+--------------+
| id | name | issued_times |
+----+-----------+--------------+
| 1 | professor | 2 |
| 2 | campaign | 1 |
| 3 | test | 1 |
+----+-----------+--------------+
As you can see, the issues times of campaign badge is 0.
But the result shows its value as 1.
How can I fix this issue?
The issue here is that Count(*) counts all the rows in a particular group. Now, even when you don't have any history row for a specific badge, you you would still have one row for the badge corresponding to the base table badge. That is why, you were getting the count as 1.
To count the history rows, you need to Count() the badge_id from the history table. So if there is no matching row in the history table, badge_id on right side table would be NULL and COUNT(NULL) = 0:
SELECT
b.id,
b.name,
COUNT(h.badge_id) AS issued_times
FROM
badge b
LEFT JOIN
issue_history h
ON
b.id = h.badge_id
GROUP BY
b.id,
b.name
Refer this official MySQL document for further understanding: https://dev.mysql.com/doc/refman/8.0/en/counting-rows.html
Also, your GROUP BY usage was not valid; I added b.name in the GROUP BY for it to be valid. Check this to get an understanding: https://stackoverflow.com/a/34115425/2469308
I'm trying to figure out a MYSQL string and my noob-ness is getting in my way. I'm trying to count the total number of teams per phase.
Tables to consider:
phases
+----+------------+
| id | phase_name |
+----+------------+
| 1 | start |
| 2 | middle |
| 3 | end |
| 4 | finish |
+----+------------+
teams
+----+-----------+----------+
| id | team_name | phase_id |
+----+-----------+----------+
| 1 | team1 | 2 |
| 2 | team2 | 3 |
| 3 | team3 | 3 |
| 4 | team4 | 4 |
| 4 | team5 | 3 |
+----+-----------+----------+
Desired result
+----------+------------+-----------+
| phase_id | phase_name | tot_teams |
+----------+------------+-----------+
| 1 | start | NULL |
| 2 | middle | 1 |
| 3 | end | 3 |
| 4 | finish | 1 |
+----------+------------+-----------+
I've tried:
SELECT
T.phase_id, P.phase_name, COUNT(*) AS tot_teams
FROM
teams T
LEFT JOIN
phases P ON P.id = T.phase_id
GROUP BY
phase_id;
but that only shows the affected phase_id's...and I'm hoping to get ALL phase_id's in a table. I also tried:
SELECT
P.phase_name, T.phase_id, COUNT(*)
FROM
teams T
RIGHT JOIN
phases P on P.`id` = T.`phase_id`
GROUP BY
P.id
but that shows invalid data. (For example, phase_id has a qty of 1 but doesn't show up in the teams table.
Can you point me in the right direction?
Thanks!
The RIGHT JOIN is correct, but you need to use COUNT(T.phase_id) instead of COUNT(*). Otherwise, you're counting the row containing NULL that's generated for the phase with no teams.
Most people prefer to use LEFT JOIN, putting the master table first.
SELECT P.phase_name, P.phase_name, COUNT(T.phase_id)
FROM phase AS P
LEFT JOIN teams AS T ON P.id = T.phase_id
GROUP BY P.id
Why ordering isn't working right for 2th column. Can some one explain, please.
select a,b from d:
+------+------+
| a | b |
+------+------+
| 1 | 3 |
| 1 | 3 |
| 2 | 1 |
| 2 | 1 |
| 3 | 2 |
| 3 | 2 |
| 3 | 2 |
+------+------+
select a,b from d order by a,b;
+------+------+
| a | b |
+------+------+
| 1 | 3 |
| 1 | 3 |
| 2 | 1 |
| 2 | 1 |
| 3 | 2 |
| 3 | 2 |
| 3 | 2 |
+------+------+
I think it's ordering correctly. In your order by you have asked system to order by First column first so it have ordered then you have asked it to order by second column so it have
1. It have to keep ordering of first column.
2. Order by second column too
So it does ordering within group means if ..
Table Test
A| B
--------
1 1
1 3
1 2
Select * from test order by A, B
Output
A | B
1 1
1 2
1 3
Hope this clears your doubt.
Each record/row in the output has to be consistent. When you use order by, you are printing record/row which is sorted on the basis of specific column value. You can't sort individual column by breaking the consistency of of a row. Otherwise it will create a havoc, imagine something like 'select bank_account_id, balance from bank_record order by bank_account_id, balance;'. What do you think would happen if bank_account_id and balance is sorted individually?
I have this 2 tables and I need to return the moset used office. Note: 1 office can be used by more than 1 guys and the column ido from TableB is populate from TableA
Probaly is a query with group by and desc limit 1
TableA
| ido| office | guy |
---------------------
| 1 | office1| guy1|
| 2 | office2| guy2|
| 3 | office1| guy3|
| 4 | office1| guy4|
| 5 | office5| guy5|
| 6 | office2| guy6|
TableB
| idb| vizit | ido|
---------------------
| 1 | date | 4 |
| 2 | date | 2 |
| 3 | date | 5 |
| 4 | date | 6 |
| 5 | date | 1 |
| 6 | date | 6 |
Thanks!
You were correct in that GROUP BY, LIMIT and DESC are useful here; it leads to a fairly straight forward query;
SELECT TableA.office
FROM TableA
JOIN TableB
ON TableA.ido = TableB.ido
GROUP BY TableA.office
ORDER BY COUNT(*) DESC
LIMIT 1
What it does is basically create rows with all valid combinations, counting the number of generated rows per office. A plain descending sort by that count will give you the most frequently used office.
An SQLfiddle to test with.
For example, if Column A and Column B have values:
+---+---+
| A | B |
+---+---+
| 2 | 1 |
| 5 | 1 |
| 6 | 1 |
| 1 | 2 |
| 5 | 2 |
| 0 | 2 |
| 2 | 3 |
| 7 | 3 |
| 4 | 3 |
| 5 | 4 |
+---+---+
From each group of B, I want to get the highest number from A. However, I don't want to include results where the number in B is higher, yet has a smaller A value than the previous one. I know this doesn't make sense in words, but this is what I want the final result to look like:
+---+---+
| A | B |
+---+---+
| 6 | 1 |
| 7 | 3 |
+---+---+
So far I have something like "select max(a), b from table1 group by b" but this doesn't omit the ones where B is higher but the max A is smaller. I know that I could just peruse the results of that query in PHP and remove the ones where the A value is smaller than the previous A value, but I want to put it all in the mysql query if possible.
This technique joins the table against the aggregated version of itself, but the join is offset by one, so that every row is joined to the knowledge of the previous-B's MAX(A) value. It then matches rows where the current A is greater than any of those, and if it doesn't find any, it doesn't include the row. We then aggregate the final selection to get the results you are after.
SELECT
MAX(source_row.A) as A,
source_row.B
FROM ab as source_row
LEFT JOIN (SELECT MAX(A) as A, B FROM ab GROUP BY B) AS one_back
ON one_back.B = source_row.B-1
WHERE (one_back.A IS NULL)
OR one_back.A < source_row.A
GROUP BY B
I have tested this :-)
edit: extra insight
I wanted to share a little insight into how I come up with these kind of solutions; 'cause I think it's important for folks to start to "think in sets"... that's the best advice I ever read regarding JOINS, that you need to envision the intermediate "sets" that your query was working with. To illustrate this, here is a representation of the intermediate "set" that is the critical part of this query; it is the table as it exists "joined" to the aggregated version of itself off-by-one.
+------+------+------------+------------+
| A | B | one_back.B | one_back.A |
+------+------+------------+------------+
| 2 | 1 | NULL | NULL |
| 5 | 1 | NULL | NULL |
| 6 | 1 | NULL | NULL |
| 1 | 2 | 1 | 6 |
| 5 | 2 | 1 | 6 |
| 0 | 2 | 1 | 6 |
| 2 | 3 | 2 | 5 |
| 7 | 3 | 2 | 5 |
| 4 | 3 | 2 | 5 |
| 5 | 4 | 3 | 7 |
+------+------+------------+------------+
And then the set as it actually is created in-memory (the full join'd version is never fully in memory, since MySQL can eliminate rows as soon as it knows they are not going to "make the cut":
+------+------+------------+------------+
| A | B | one_back.B | one_back.A |
+------+------+------------+------------+
| 2 | 1 | NULL | NULL |
| 5 | 1 | NULL | NULL |
| 6 | 1 | NULL | NULL |
| 7 | 3 | 2 | 5 |
+------+------+------------+------------+
And then, of course, it aggregates the results from there into the final form, selecting only the A and B from the original rows.
A simpler solution would be to use a variable to store the value of a from the previous row and make the comparison on each iteration. This also accounts for the case where you might have gaps in the b column, where numbers aren't exactly in perfect sequential order:
SELECT #val:=a.a AS a, a.b
FROM
(
SELECT MAX(a) AS a, b
FROM tbl
GROUP BY b
) a
WHERE a.a > IFNULL(#val,-1)
Select Z.a, Z.b from
(select a, b, rank() over (order by b) as ranker from (select max(a) a, b from table1 group by b) Y) Z left join
(select a, b, rank() over (order by b) as ranker from (select max(a) a, b from table1 group by b) Y1) Z1
on Z.ranker = Z1.ranker + 1
where Z.a > isnull(Z1.a, -100000)