Counting and sorting multiple columns - mysql

I have a table in MySQL like this:
+---------+---------+---------+---------+
| teacher | grade_1 | grade_2 | grade_3 |
+---------+---------+---------+---------+
| Paul | 1 | 0 | 3 |
| Mike | 2 | 2 | 1 |
| Jens | 3 | NULL | 2 |
| Jens | 2 | 3 | NULL |
| Mike | 1 | 2 | 1 |
| Paul | 2 | 2 | 2 |
| Mike | 1 | NULL | NULL |
+---------+---------+---------+---------+
I would like to produce an outcome like this:
+---------+-------+-------+
| teacher | grade | count |
+---------+-------+-------+
| Jens | NULL | 2 |
| Jens | 0 | 0 |
| Jens | 1 | 0 |
| Jens | 2 | 2 |
| Jens | 3 | 2 |
| Mike | NULL | 2 |
| Mike | 0 | 0 |
| Mike | 1 | 4 |
| Mike | 2 | 3 |
| Mike | 3 | 0 |
| Paul | NULL | 0 |
| Paul | 0 | 1 |
| Paul | 1 | 1 |
| Paul | 2 | 3 |
| Paul | 3 | 1 |
+---------+-------+-------+
So, every grade could have four different distinct values; NULL, 0, 1, 2 or 3
For every teacher, I would like to count the occurences of each grade in every grade column in total.
Is this possible? The actual table is much bigger with many more grade columns and more teachers.
My brain's totally stuck and I can't seem to think of a way to do it...
Best regards,
Jens

Related

in a m to n table between PKs of table A and B. how to find a PK of A that has a specific set of entries with PKs of B in the m to n table

Given the two tables teacher and student,
table : teacher
+-------+-----------+
| id | name |
+-------+-----------+
| 1 | John |
| 2 | Mary |
| 3 | Jeff |
| 4 | Bill |
| 5 | Bob |
| 6 | Frieda |
+-------+-----------+
table : student
+-------+-----------+
| id | name |
+-------+-----------+
| 1 | mario |
| 2 | lisa |
| 3 | anna |
| 4 | sara |
| 5 | felix |
+-------+-----------+
and the m to n relationship between them
table : teacherStudent
+---------+---------+
|teacherId|studentId|
+---------+---------+
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 3 | 1 |
| 3 | 5 |
| 4 | 4 |
| 4 | 5 |
| 5 | 1 |
| 5 | 2 |
| 5 | 3 |
| 6 | 1 |
| 6 | 2 |
| 6 | 3 |
| 6 | 4 |
+---------+---------+
how to find all teacherId that stand in relation to (exactly) studentId 1,2 and 3 ?
I want my final results to look like this:
+----------+
|teacherId |
+----------+
| 1 |
| 5 |
+----------+

Is there a mySQL procedure that can merge duplicate rows of data into one, then allow me to manipulate that data as if it were one row?

I'm trying to come up with a stored procedure that takes multiple rows that are exactly identical, and combines them into one row while summing one column, which can then be run through more stored procedures based on the sum of that one column.
I've tried a GROUP BY statement, but that doesn't actually group the rows together, because if I run the table through another procedure it performs actions as if each row were not combined. Performing a SELECT * FROM mytable query shows that each row was not actually combined into one.
Is there any way to permanently combine multiple rows into one singular row?
To start, I've got a table like this:
+-------+-----+--------+---------+------+-----+-----------+
| RowID | pID | Name | Date | Code | QTY | Purchased |
+-------+-----+--------+---------+------+-----+-----------+
| 1 | 1 | bob | 9/29/20 | 123 | 1 | |
| 2 | 1 | bob | 8/10/20 | 456 | 1 | |
| 3 | 2 | rob | 9/15/20 | 123 | 1 | |
| 4 | 2 | rob | 9/15/20 | 123 | 1 | |
| 5 | 2 | rob | 9/15/20 | 123 | 1 | |
| 6 | 2 | rob | 9/15/20 | 123 | 1 | |
| 7 | 2 | rob | 9/15/20 | 123 | 1 | |
| 8 | 3 | john | 7/12/20 | 987 | 1 | |
| 9 | 3 | john | 7/12/20 | 987 | 1 | |
| 10 | 4 | george | 9/12/20 | 684 | 1 | |
| 11 | 5 | paul | 2/2/20 | 454 | 1 | |
| 12 | 6 | amy | 1/12/20 | 252 | 1 | |
| 13 | 7 | susan | 5/30/20 | 131 | 1 | |
| 14 | 7 | susan | 6/6/20 | 252 | 1 | |
| 15 | 7 | susan | 5/30/20 | 131 | 1 | |
+-------+-----+--------+---------+------+-----+-----------+
By the end, i'd like to have a table like this:
+-------+-----+--------+---------+------+-----+-----------+
| RowID | pID | Name | Date | Code | QTY | Purchased |
+-------+-----+--------+---------+------+-----+-----------+
| 1 | 1 | bob | 9/29/20 | 123 | 1 | |
| 2 | 1 | bob | 8/10/20 | 456 | 1 | |
| 3 | 2 | rob | 9/15/20 | 123 | 5 | |
| 4 | 3 | john | 7/12/20 | 987 | 2 | |
| 5 | 4 | george | 9/12/20 | 684 | 1 | |
| 6 | 5 | paul | 2/2/20 | 454 | 1 | |
| 7 | 6 | amy | 1/12/20 | 252 | 1 | |
| 8 | 7 | susan | 5/30/20 | 131 | 2 | |
| 9 | 7 | susan | 6/6/20 | 252 | 1 | |
+-------+-----+--------+---------+------+-----+-----------+
Where exactly identical rows are combined into one row, and the QTY field is summed, that I can then add purchases to, or make deductions from the quantity as a total. Using GROUP BY statements can achieve this, but when I go to alter the quantity or add purchases to each person, it treats it like the first table, as if nothing was actually grouped.
So you have this table:
| RowID | pID | Name | Date | Code | QTY | Purchased |
+-------+-----+--------+---------+------+-----+-----------+
| 1 | 1 | bob | 9/29/20 | 123 | 1 | |
| 2 | 1 | bob | 8/10/20 | 456 | 1 | |
| 3 | 2 | rob | 9/15/20 | 123 | 1 | |
| 4 | 2 | rob | 9/15/20 | 123 | 1 | |
| 5 | 2 | rob | 9/15/20 | 123 | 1 | |
| 6 | 2 | rob | 9/15/20 | 123 | 1 | |
| 7 | 2 | rob | 9/15/20 | 123 | 1 | |
| 8 | 3 | john | 7/12/20 | 987 | 1 | |
| 9 | 3 | john | 7/12/20 | 987 | 1 | |
| 10 | 4 | george | 9/12/20 | 684 | 1 | |
| 11 | 5 | paul | 2/2/20 | 454 | 1 | |
| 12 | 6 | amy | 1/12/20 | 252 | 1 | |
| 13 | 7 | susan | 5/30/20 | 131 | 1 | |
| 14 | 7 | susan | 6/6/20 | 252 | 1 | |
| 15 | 7 | susan | 5/30/20 | 131 | 1 | |
The best way, as has been suggested, is to create a new table with the content of your query, then to rename the old table, and the new table to the original table's name, to check if everything is all right, and to drop the original table if yes.
CREATE TABLE indata_new AS
WITH grp AS (
SELECT
MIN(rowid) AS orowid
, pid
, name
, MAX(date) AS date
, code
, SUM(qty) AS qty
FROM indata
GROUP BY
pid
, name
, code
)
SELECT
ROW_NUMBER() OVER(ORDER BY orowid ASC) AS rowid
, *
FROM grp;
ALTER TABLE indata RENAME TO indata_old;
ALTER TABLE indata_new RENAME TO indata;
-- if "indata" now contains the data you want ...
SELECT * FROM indata;
-- out rowid | orowid | pid | name | date | code | qty
-- out -------+--------+-----+--------+------------+------+-----
-- out 1 | 1 | 1 | bob | 2020-09-29 | 123 | 1
-- out 2 | 2 | 1 | bob | 2020-08-10 | 456 | 1
-- out 3 | 3 | 2 | rob | 2020-09-15 | 123 | 5
-- out 4 | 8 | 3 | john | 2020-07-12 | 987 | 2
-- out 5 | 10 | 4 | george | 2020-09-12 | 684 | 1
-- out 6 | 11 | 5 | paul | 2020-02-02 | 454 | 1
-- out 7 | 12 | 6 | amy | 2020-01-12 | 252 | 1
-- out 8 | 13 | 7 | susan | 2020-05-30 | 131 | 2
-- out 9 | 14 | 7 | susan | 2020-06-06 | 252 | 1
-- you can ...
DROP TABLE indata_old;

Grouping, yet concatenating values from within the group in MySQL

I have a simple MySQL table as such:
| CUST_ID | VISIT | PROD_ID |
|---------|-------|---------|
| 1 | 1 | 3473 |
| 1 | 2 | 324 |
| 1 | 2 | 324 |
| 2 | 1 | 426 |
| 2 | 2 | 4418 |
| 3 | 1 | 4523 |
| 4 | 1 | 976 |
| 4 | 1 | 86 |
| 4 | 2 | 3140 |
| 4 | 3 | 1013 |
And I would like to transform it to this:
| CUST_ID | VISIT | PROD_IDs |
|---------|-------|----------|
| 1 | 1 | 3473 |
| 1 | 2 | 324, 324 |
| 2 | 1 | 426 |
| 2 | 2 | 4418 |
| 3 | 1 | 4523 |
| 4 | 1 | 976, 86 |
| 4 | 2 | 3140 |
| 4 | 3 | 1013 |
This is kinda an ugly hack, I get it.
I have no idea how to cleanly create such a thing. I've tried a variety of unsuccessful grouping strategies. Even a clue or hint in the right direction would be great. Thanks.
If you're trying to group by cust_id + visit, then you can do that and use a GROUP CONCAT on the PROD_ID field, for example:
SELECT
CUST_ID,
VISIT,
GROUP_CONCAT(PROD_ID) PROD_IDS
FROM
table
GROUP BY
CUST_ID,
VISIT
Reference: GROUP CONCAT

How do I combine two nested MySQL queries into one View?

I have two queries, almost similar, but never the less,They must be treated as separate as they have different meanings and values, I want to combine them into one view, I tied doing UNION, but the result was they were all combined into one table, which is not what I want, I would like them to appear as entirely separate tables under one view, here is what I did:
CREATE VIEW TEAM_SUMMARY AS
SELECT DISTINCT COUNTRY.country_name AS CountryName_T1,count(Team1)AS NoOfGames,
SUM(Team1_score) AS TotalGoalsFor,SUM(Team2_score) AS TotalGoalsAgainst
FROM COUNTRY,MATCH_RESULTS WHERE
country_name = Team1
group by country_name
UNION
SELECT DISTINCT COUNTRY.country_name AS CountryNameT_2,count(Team2)AS NoOfGames,
SUM(Team2_score) AS TotalGoalsFor,SUM(Team1_score) AS TotalGoalsAgainst
FROM COUNTRY,MATCH_RESULTS WHERE
country_name = Team2
group by country_name;
UPDATE:
So, the output of my current query is something like this:
mysql> SELECT * FROM TEAM_SUMMARY;
+----------------------+-----------+---------------+-------------------+
| CountryName | NoOfGames | TotalGoalsFor | TotalGoalsAgainst |
+----------------------+-----------+---------------+-------------------+
| Algeria | 1 | 1 | 1 |
| Argentina | 4 | 5 | 1 |
| Australia | 2 | 2 | 6 |
| Belgium | 3 | 5 | 2 |
| Bosnia & Herzegovina | 1 | 3 | 1 |
| Brazil | 6 | 7 | 13 |
| Cameroon | 2 | 1 | 8 |
| Chile | 1 | 3 | 1 |
| Columbia | 3 | 7 | 1 |
| Costa Rica | 2 | 1 | 1 |
| Croatia | 1 | 1 | 3 |
| Ecuador | 1 | 0 | 0 |
| England | 1 | 1 | 2 |
| France | 3 | 5 | 1 |
| Germany | 4 | 9 | 3 |
| Ghana | 1 | 1 | 2 |
| Greece | 1 | 2 | 1 |
| Honduras | 2 | 1 | 5 |
| Iran | 1 | 0 | 0 |
| Italy | 2 | 0 | 2 |
| Ivory Coast | 1 | 2 | 1 |
| Japan | 2 | 1 | 4 |
| Mexico | 1 | 1 | 0 |
| Netherlands | 4 | 4 | 1 |
| Nigeria | 2 | 3 | 3 |
| Portugal | 1 | 2 | 1 |
| Russia | 1 | 1 | 1 |
| South Korea | 2 | 2 | 5 |
| Spain | 2 | 1 | 7 |
| Switzerland | 2 | 4 | 6 |
| Uruguay | 2 | 3 | 4 |
| USA | 2 | 2 | 3 |
| Algeria | 3 | 6 | 6 |
| Argentina | 3 | 3 | 3 |
| Australia | 1 | 1 | 3 |
| Belgium | 2 | 1 | 1 |
| Bosnia & Herzegovina | 2 | 1 | 3 |
| Brazil | 1 | 4 | 1 |
| Cameroon | 1 | 0 | 1 |
| Chile | 3 | 3 | 3 |
| Columbia | 2 | 5 | 3 |
| Costa Rica | 3 | 4 | 1 |
| Croatia | 2 | 5 | 3 |
| Ecuador | 2 | 3 | 3 |
| England | 2 | 1 | 2 |
| France | 2 | 5 | 2 |
| Germany | 3 | 9 | 1 |
| Ghana | 2 | 3 | 4 |
| Greece | 3 | 1 | 4 |
| Honduras | 1 | 0 | 3 |
| Iran | 2 | 1 | 4 |
| Italy | 1 | 2 | 1 |
| Ivory Coast | 2 | 2 | 4 |
| Japan | 1 | 1 | 2 |
| Mexico | 3 | 4 | 3 |
| Netherlands | 3 | 11 | 3 |
| Nigeria | 2 | 0 | 2 |
| Portugal | 2 | 2 | 6 |
| Russia | 2 | 1 | 2 |
| South Korea | 1 | 1 | 1 |
| Spain | 1 | 3 | 0 |
| Switzerland | 2 | 3 | 1 |
| Uruguay | 2 | 1 | 2 |
| USA | 2 | 3 | 3 |
+----------------------+-----------+---------------+-------------------+
64 rows in set (0.01 sec)
UPDATE2: Each query provides 32 row, and here they are combined into 64 rows so I don't know which belongs to which query, you can see that USA is the last row of each query and then it starts with Algeria again for the second query with different values that do not represent the column description.
What I want is something like this:
+------+--------+ +------+--------+
| code | SUM(*) | | code | SUM(*) |
+------+--------+ +------+--------+
| AAA | 4 | | AAA | 4 |
| BBB | 3 | | CCC | 1 |
+------+--------+ +------+--------+
Then I did some searching in order to use JOIN as shown here Combine results of two unrelated queries into single view but, this scenario is much less complicated than mine and couldn't apply it on my scenario, Any Idea?
One view doesn't product two result sets. But you can identify where they come from:
CREATE VIEW TEAM_SUMMARY AS
SELECT 'Team1' as which,
c.country_name AS CountryName_T1, count(Team1) AS NoOfGames,
SUM(Team1_score) AS TotalGoalsFor,
SUM(Team2_score) AS TotalGoalsAgainst
FROM COUNTRY c JOIN
MATCH_RESULTS mr
ON c.country_name = mr.Team1
GROUP BY country_name
UNION ALL
SELECT 'Team2' as which,
c.country_name AS CountryNameT_2,
count(Team2) AS NoOfGames,
SUM(Team2_score) AS TotalGoalsFor,
SUM(Team1_score) AS TotalGoalsAgainst
FROM COUNTRY c JOIN
MATCH_RESULTS mr
ON c.country_name = mr.Team2
GROUP BY country_name;
Notes:
SELECT DISTINCT with GROUP BY is almost always unnecessary (as in this case.
Use UNION ALL by default. Only use UNION when you specifically want to incur the overhead for removing duplicates.
Table aliases make the query easier to write and to read.
The above adds a column which to specify where each row comes from.

Mysql - pivot indeterminate number of rows to multiple columns

Given the following two tables:
+- Members -+
| ID | Name |
+----+------+
| 1 | Bob |
| 2 | Jim |
| 3 | Judy |
etc...
This table represents the members' children. Each parent may have many or no children
+- Children -------------+-----+
| ID | ParentID | Name | Age |
+----+----------+--------+-----+
| 1 | 3 | Jeff | 4 |
| 2 | 3 | Casey | 3 |
| 3 | 1 | Steven | 10 |
| 4 | 2 | Mary | 7 |
| 5 | 1 | Esther | 8 |
| 6 | 2 | Abe | 11 |
| 7 | 3 | Paul | 6 |
etc...
I need to create a table that looks like this:
+----+------+--------+------+---------+------+--------+------+
| ID | Name | Child1 | Age1 | Child2 | Age2 | Child3 | Age3 |
+----+------+--------+------+---------+------+--------+------+
| 1 | Bob | Steven | 10 | Esther | 8 | | |
| 2 | Jim | Abe | 11 | Mary | 7 | | |
| 3 | Judy | Paul | 6 | Jeff | 4 | Casey | 3 |
+----+------+--------+------+---------+------+--------+------+
I've tried various pivot table approaches, but every one that I've seen requires a known number of rows in the second table for each row in the first table. I essentially need an unknown number of columns. A group_concat isn't going to meet my requirements.
Is this possible with MySQL or do I need to do this in the backend?