Select from multiple tables joined by column where condition is met - mysql

There are two tables,
table1:
name | surname | firstname
cookie | Smith | John
cake | Miller | Ben
table2:
name | day | points1 | points2
cookie | 1 | 5 | 5
cookie | 1 | 4 | 6
cake | 1 | 7 | 3
cake | 1 | 7 | 3
cookie | 2 | 4 | 4
cookie | 2 | 4 | 4
cake | 2 | 1 | 2
cake | 2 | 3 | 4
We need the day
and SUM(points1 + points2) AS total
GROUP BY day, name
as well as surname and firstname from table1,
where the name from table1 and table2 match,
if the total is larger than 15.
Additionally the result should be ORDER BY total DESC, surname ASC.
The result should yield:
surname | firstname | day | total
Miller | Ben | 1 | 20
Smith | John | 1 | 20
Smith | John | 2 | 16
Ben Miller (cake) does not appear, since his total of day 2 is only 10.
Note that each name in table2 has an entry in table1.

Well, if you want "surname" and "firstname" to appear on your results, you will have to GROUP by these fields too (All SELECT fields in a GROUP BY expression must be an aggregation (SUM, AVG,...) or appear in the GROUP BY clause).
By using HAVING you can restrict the results of the GROUP BY.
I think this code would work:
SELECT surname, firstname, day, (SUM(points1) + SUM(points2)) AS total
FROM table1, table2
WHERE table1.name = table2.name
GROUP BY surname, firstname, day
HAVING (SUM(points1) + SUM(points2) > 15
ORDER BY total DESC, surname ASC;

Related

MySQL statement that returns only rows with exact equal amounts per ID

Table t1
id | provider
_________
1 | bob
1 | ted
2 | bob
2 | bob
2 | ted
2 | ted
3 | bob
3 | bob
3 | ted
3 | ted
3 | joe
3 | joe
4 | bob
4 | bob
4 | ted
4 | joe
4 | joe
MySQL statement that returns id's where all names show up in equal amount per ID. For ID 4, the name "ted" shows up only once where the other names show up twice, so it would be excluded from the results.
id
__
1
2
3
Use two levels of aggregation:
select id
from (select id, name, count(*) as cnt
from t1
group by id, name
) ni
group by id
having min(cnt) = max(cnt);

Return multiple records, but it should limit 1 record per each similar condition

+----+--------------------+
| id | name | age |
+----+--------------------+
| 1 | James | 20 |
| 2 | Ruth | 20 |
| 3 | Blue | 15 |
| 4 | Redd | 15 |
| 5 | Arkk | 30 |
| 6 | Arthur | 30 |
Expected results:
+----+--------------------+
| id | name | age |
+----+--------------------+
| 1 | James | 20 |
| 3 | Blue | 15 |
| 6 | Arthur | 30 |
Explanation:
In the results, James is representing all people aged 20. And Blue is representing all people aged 15. And so on..
Question:
How can this query type of query be achieved? Thank you.
If you want one name per age, you can use:
select max(name), age
from t
group by age;
If you want the first row, then:
select t.*
from t
where t.id = (select min(t2.id) from t t2 where t2.age = t.age);
Using Row_number.
WITH cte1 AS
(SELECT id, name, age, row_number() over(partition by age order by id) rn
FROM table1)
SELECT id, name, age FROM cte1 WHERE rn = 1;
If you're using Microsoft SQL Server:
SELECT TOP 1 id, name, age
ORDER BY id
GROUP BY age
FROM table

MySQL Selecting Rows and Grouping

I have a ( Joomla) database table called field_values, the contents are below;
+----+----------+---------+---------+
| id | field_id | item_id | value |
+----+----------+---------+---------+
| 1 | 2 | 446 | Jones |
| 2 | 2 | 447 | Smith |
| 3 | 2 | 448 | Jenkins |
| 4 | 3 | 446 | Paul |
| 5 | 3 | 447 | Peter |
| 6 | 3 | 448 | Sally |
| 7 | 4 | 446 | London |
| 8 | 4 | 447 | Dublin |
| 9 | 4 | 448 | Paris |
+----+----------+---------+---------+
I'm only displaying 9 rows from the table, but I actually have thousands, so the successful query would need to take this into account.
Columns explained;
id (primary / auto-increment)
field_id (FK to another fields table, 2 = surname, 3 = first name, 4 = location)
item_id (FK to another users table)
value (contents of field)
How can I select all the values from the above table but display them as follows;
+------------+-----------+----------+
| first_name | last_name | location |
+------------+-----------+----------+
| Paul | Jones | London |
| Peter | Smith | Dublin |
| Sally | Jenkins | Paris |
+------------+-----------+----------+
The id field isn't really necessary in the desired results above, I just added it to emphasise that each row is unique.
I'm not sure if I need to use a subquery or group by, maybe neither?
Thanks in advance.
A pivot query should work here:
SELECT
MAX(CASE WHEN field_id = 3 THEN value END) AS first_name,
MAX(CASE WHEN field_id = 2 THEN value END) AS last_name,
MAX(CASE WHEN field_id = 4 THEN value END) AS location
FROM yourTable
GROUP BY
item_id
ORDER BY
item_id;
Your current table structure is a denormalized key value store, a style which WordPress uses in some of its tables.
you could avoid subquery and grou by.
You could use the same table 3 times
select a.id, b.value firts_name, a.value last_name , c.value location
from field_values a
inner join field_values b on a.item_id = b.item_id and b.field_id = 3
inner join field_values bc on a.item_id = c.item_id and b.field_id = 4
where a.item_id = 2

Mins of Max SQL

Semesters Table
+----+------+
| ID | Name |
+----+------+
| 1 | 1st |
| 2 | 2nd |
+----+------+
Subjects Table
+----+-------------+-------------+
| ID | Semester Id | Name |
+----+-------------+-------------+
| 1 | 1 | Mathematics |
| 2 | 1 | English |
| 3 | 2 | Mathematics |
| 4 | 2 | English |
+----+-------------+-------------+
Tests Table
+----+------------+-------+
| ID | Subject ID | Score |
+----+------------+-------+
| 1 | 1 | 70 |
| 2 | 1 | 75 |
| 3 | 2 | 75 |
| 4 | 2 | 70 |
| 5 | 3 | 75 |
| 6 | 3 | 70 |
| 7 | 4 | 70 |
| 8 | 4 | 75 |
+----+------------+-------+
I can get the scores of the 2nd test by using MAX on the ID of the tests, and then grouping them by the subject id. However, then I have to get the minimums of the scores grouped by the semester.
Is it possible to get the lowest scoring 2ND test of each semester in a single SQL statement?
The result set would look like this.
+----------+-------------+-------+
| Semester | Subject | Score |
+----------+-------------+-------+
| 1st | English | 70 |
| 2nd | Mathematics | 70 |
+----------+-------------+-------+
This is in MySQL.
You are looking for the second lowest tests per semester.
Build row numbers for the ordered tests per semester and stay with those numbered #2. One way to do this is a correlated subquery. Another would be variables.
select
sem.name as semester,
sub.name as subject,
tst.score
from semesters sem
join subjects sub on sub.semester_id = sem.id
join tests tst on tst.subject_id = sub.id
where
(
select count(*)
from subjects sub2
join tests tst2 on tst2.subject_id = sub2.id
where sub2.semester_id = sub.semester_id
and sub2.id <= sub.id
and tst2.score <= tst.score
) = 2
order by sub.semester_id;
In case of ties one of the rows is picked, just as shown in your example.
Working with variables is probably faster than above query. You will easily find the method by looking for how to emulate ROW_NUMBER in MySQL. (Other DBMS use ROW_NUMBER which is much simpler, but MySQL doesn't feature this function.)
select a.name as semester
, b.name as subject
, min(c.score) as lowestscore
from subjects as b
join semesters as a on a.id = b.semester_id
join tests as c on c.subject_id = b.id
group by a.name, b.name
You will probably want to order by or something but this should give you what you are looking for. You could add more discriminators for range of semesters or subjects, but this will yield the name of the semester, the name of the subject and the minimum score for that semester/subject.

Mysql Cross Joining

I have three Tables
Countries
id | name
1 | USA
2 | UAE
3 | UK
4 | INDIA
Users
id | name | countryid
1 | Philip| 1
2 | Aby | 3
3 | Sam | 3
Happiness
id | userid | mark
1 | 1 | 10
1 | 2 | 50
1 | 3 | 70
I need to get a result of happiness country ranking as
Rank | Country | Total
1 | UK | 120
2 | UAE | 10
3 | USA | 0
4 | INDIA | 0
I need a mysql query for this solution..
Maybe something like this:
SET #rank=0;
SELECT
#rank:=#rank+1 AS rank,
tbl.*
FROM
(
SELECT
Countries.name,
COALESCE(SUM(Happiness.mark),0) AS Mark
FROM
Countries
LEFT JOIN Users
on Countries.id=Users.countryid
LEFT JOIN Happiness
ON Happiness.userid=Users.id
GROUP BY
Countries.Name
) AS tbl
ORDER BY tbl.Mark DESC
References:
MySql - Get row number on select
How do I get SUM function in MySQL to return '0' if no values are found?
SQL fiddle here