Obtaining last occurance of row on MySQL LEFT JOIN - php

I have the following tables in my Database:
USERS
+-------+-------------------------------------+
| id | name |
+-------+-------------------------------------+
| 1 | Johnny Appleseed |
| 2 | Pete Jones |
| 3 | John Doe |
| 4 | Jane Plick |
+-------+-------------------------------------+
REPORTS
+-------+-------+-----------------------------+
| id | owner | title |
+-------+-------+-----------------------------+
| 1 | 1 | Weekly report #86 |
| 2 | 1 | Weekly report #87 |
| 3 | 1 | Weekly report #88 |
| 4 | 2 | Weekly report #1 |
| 5 | 3 | Weekly report #33 |
| 6 | 3 | Weekly report #34 |
+-------+-------------------------------------+
What I need to do is GROUP the results by first name, so that the list itself is alphabetical order, but I need the LAST occurrence of the row matching the user's id.
The "owner" column of the REPORTS table matches the "id" column of the USERS table.
My desired results look like:
Jane Plick |
John Doe | Weekly Report #34
Johnny Appleseed | Weekly Report #88
Pete Jones | Weekly Report #1
My current query ALMOST works, however it only shows the FIRST weekly report for that user, not the last.
SELECT * FROM users AS a LEFT JOIN ppp_reports AS b ON a.id=b.owner WHERE a.active=1 GROUP BY a.id ORDER BY a.firstname ASC
I have tried a lot of different variations, but I'm always left with the FIRST row from the REPORTS table.
Any help is greatly appreciated.

In your particular case where all reports are named "Weekly report #X", you can try this:
SELECT a.id, a.name, MAX(b.title)
FROM users AS a
LEFT JOIN ppp_reports AS b ON a.id=b.owner
WHERE a.active=1
GROUP BY a.id, a.name
ORDER BY a.name ASC
See this fiddle.
If the reports may have other names, you'll have to find another way to discriminate the last report from the others.

Assuming that your reports ID are numbered by date, i.e report ID 2 is always after report ID 1, these two queries should work:
select t.id, t.name, r.title from
(select u.id, u.name, max(r.id) as report_id
from users u
left join reports r on r.owner = u.id
group by u.id, u.name) as t
left join reports r on t.report_id = r.id;
OR
select u.id, u.name, r.title from
users u
left join
(select r.owner, max(r.id) as report_id
from reports r
group by r.owner) as latest_report on u.id = latest_report.owner
left join reports r on latest_report.report_id = r.id;
The idea is that you need to identify the correct report, by user ID, and then join the reports table back to that to get the correct name for the report.
Link to SQL Fiddle

Related

PHP query to meet a condition has to be present in a second table

I have two tables.
First has the following:
id | Company | Field | Country
-------------------------------------
1 | Widgets Inc | Parts | USA
2 | Moo Corp | Toys | GBR
3 | Dingles S.A | Music | GER
4 | Deutsh Import | Import | AUT
5 | Clean Inc | Clean | USA
and second table
id | Employee | Company_id | Country
----------------------------------------
1 | Paul Allen | 2 | USA
2 | Andrew Cur | 2 | GBR
3 | Paul Hanz | 4 | GER
4 | Angela Dow | 1 | AUT
5 | Dana Loconto | 4 | USA
I want to filter (mysql query on php) the first table with ONLY the companies that actually have an employee on the second table. The ones with no employees should be ignored.
Thank you for your advice
EDIT: Using INNER JOIN seems to fix this, but then I have a different problem.
If I use INNER JOIN as suggested below, it gives me one result for EACH time the occurence happens on the join table.
For example: Using my table below, it will return the company id 2 twice, and id 4 twice. To better explain, I'm using this to generate a list of the companies that actually have employees, but I don't need it to repeat itself everytime it finds a new employee of the same company. Not sure if I'm making myself clear.
SELECT C.id, C.field, C.country
FROM first_table as C
INNER JOIN second_table as E ON E.company_id = C.id
This returns the following
Moo Corp | Toys | USA
Moo Corp | Toys | USA
Deutsch Import | Import | AUT
Widgets Inc | Parts | USA
Deutsch Import | Import | AUT
And what I was expecting is only
Moo Corp
Deutsch Import
Widget Inc
Any extra help?
Try an inner join :
SELECT C.id, C.field, C.country
FROM first_table as C
INNER JOIN second_table as E ON E.company_id = C.id AND E.employee is not null
Or as suggested in the comment, if the second_table data about employee only exist if there is a company :
SELECT C.id, C.field, C.country
FROM first_table as C
INNER JOIN second_table as E ON E.company_id = C.id
It works like this :
You select the element you want (here only element from table_one)
You make your inner join based on the common field (here company_id from second_table and id from first_table)
You add your condition on the inner_join, here E.employee is not null, adapt according to how it looks when no employee (maybe empty string, maybe 0, I don't know)
The inner join will make you return only element that respect this condition
EDIT :
To only get one result by company, add this at the end :
GROUP BY C.company
But you need to add C.company to your SELECT before

PDO Query : Count related and repeated values then inner join

I work with PHP and PDO.
So I have 2 tables like,
Table 1
| id | name | age |
| 1 | John | 25 |
| 2 | Tom | 32 |
| 3 | James| 45 |
Table 2
| id | Comment | Link |
| 1 | some text | 3 |
| 2 | some text | 3 |
| 3 | some text | 1 |
So, Link column numbers represent id's in table1. For example Link = 3s in table 2 represent James in table 1. I need a query which brings all table1's data and also a number of repeated value for related Link column which comes from table2.
For example, the query should give me (let's choose James),
| id | name | age | Value |
| 3 | James | 45 | 2 |
value=2, because there are two 3s in link column which related to James
I tried somethings but got lots of errors.
I think you just need the GROUP BY
SELECT a.id,
a.name,
a.age,
count(*) as value
FROM table1 a
JOIN table2 b ON a.id = b.link
GROUP BY a.id, a.name, a.age
If you really want just one row then add WHERE
SELECT a.id,
a.name,
a.age,
count(*) as value
FROM table1 a
JOIN table2 b ON a.id = b.link
WHERE a.name = 'James'
GROUP BY a.id, a.name, a.age
or use subquery
SELECT a.id,
a.name,
a.age,
(SELECT count(*) FROM table2 b WHERE a.id = b.link) as value
FROM table1 a
WHERE a.name = 'James'

SQL inner join of multiple tables and search through database

I'm making a search function in PHP and I have three tables that I wish to join to a single one; the three tables looks as follow:
band
ID | bands
---+----------
1 | Muse
2 | Coldplay
3 | etc.
release
ID | releases
---+----------
1 | Showbiz
2 | Origin of Symmentry
3 | etc.
track
ID | tracks
---+-----------
1 | Sunburn
2 | Muscle Museum
3 | etc.
I want these tables to be put into this:
discografic
ID | band_id | release_id | track_id
---+----------+-------------+---------
1 | 1 | 1 | 1
2 | 1 | 1 | 2
3 | etc.
So that the table with the SQL code looks like this:
discografic
ID | bands | releases | tracks
---+----------+-------------+---------
1 | Muse | Showbiz | Sunburn
2 | Muse | Showbiz | Muscle Museum
3 | etc.
I want to INNER JOIN these tables. I joined one but I can't really figure out how the get the last joined as well.
SELECT *
FROM band
INNER JOIN discografic
ON band.id = discografic.band_id
This should probably have its own question; I also want to be able to search this database, but only have the result show up once, and also reference to the band every time. For example, if I search "Showbiz" it will give me "Muse", and only show it once.
Note: This is for testing purposes only, security is none of my concerns.
Try with this query:
select d.id,b.bands,r.releases,t.tracks from discografic as d INNER JOIN band as b on
d.band_id=b.id INNER JOIN release as r on d.release_id=r.id INNER JOIN track as t on
d.track_id=t.id GROUP BY d.id
Try This query
Select a.ID,b.bands,c.releases,d.tracks from discografic as a
inner join band as b on a.band_id = b.ID
inner join release as c on a.release_id = c.ID
inner join track as d on a.track_id = d.ID
where b.bands = 'Muse'
Use this query to insert the data like you wanted:
Insert into discograpy
(id,bands,releases,tracks)
SELECT band.ID,bands,releases,tracks
FROM band
INNER JOIN releases
ON band.id = releases.id
inner join track
on band.id = track.id
Use this query to show you only one band:
Declare #releases varchar(50)
Set #releases = 'showbiz'
SElect distinct bands from discograpy where releases = #releases
Here any variable can be passed or set in place of showbiz. This is an example

how do i select data from multiple columns from two tables where there is a common column in both?

seems like a cake walk, because of the common column thing, but i've looked and i've looked and can't find the answer anywhere. there may be very similar things people are trying to do, but everyone always needs it slightly different than how i need it. anyway here goes...
jobs table
+----+--------+----+----+----+
| id | userid | i1 | i2 | i3 |
+----+--------+----+----+----+
| 1 | 1 | a | k | t |
| 2 | 1 | b | l | u |
| 3 | 1 | c | m | v |
| 4 | 2 | d | n | w |
| 5 | 2 | f | o | x |
| 6 | 2 | g | p | y |
| 7 | 3 | h | q | z |
| 8 | 3 | i | r | a |
| 9 | 4 | j | s | b |
+----+--------+----+----+----+
user_table table
+--------+----+----+----+
| userid | fn | ln | i4 |
+--------+----+----+----+
| 1 | a | b | w |
| 2 | c | d | x |
| 3 | e | f | y |
| 4 | g | h | z |
+--------+----+----+----+
i want to select multiple columns from one table and multiple columns from another table, and the amount of columns don't have the same amount. so if i'm selecting id, i1, i2, and i3 from jobs table and selecting fn, ln, and i4 from user_table table, then that means i'm selecting 4 pieces of info from jobs table and 3 pieces of info from user_table table.
so let's say i want to select a specific job and display the info for that job, but also i want to display the info of the user that belongs to the job then it might go something like this...
job 1:
id: 1, i1: a, i2: k, i3: t, fn: a, ln: b, i4: w
for job 4 it would be:
id: 4, i1: d, i2: n, i3: w, fn: c, ln: d, i4: x
the jobs table and user_table table have the common column of userid. so how do i write my query to do the above using this common column?
i tried all sorts of things with SELECT and WHERE and AND and JOIN and UNION and AS and GROUP and BY and writing the table names separate from the column names and writing the table names and column names together with a period in between. i just can't find the correct way to write this query.
in these examples below that don't work i'm just trying to select one thing from the user_table table and everything from the jobs table that isn't the userid, but i will need the ability to select multiple things from the 2nd table if needed. so i want to select everything from first table and just certain things from second table.
doesn't work:
SELECT id, i1, i2, i3, i4 FROM jobs, user_table WHERE jobs.id = $id GROUP BY id
doesn't work:
SELECT * from jobs where id = $id UNION SELECT i4 from user_table where userid = $userid
The query
SELECT * FROM jobs
INNER JOIN user_table on jobs.userid = user_table.userid
will join your jobs information with the user information. Then just add your where clause:
SELECT * FROM jobs
INNER JOIN user_table on jobs.userid = user_table.userid
where jobs.id = $id
You want to join the tables like so:
SELECT j.column1, j.column2, u.column5, u.column6
FROM
jobs j
INNER JOIN
user_table u
ON
u.userid = j.userid
WHERE
j.id = $id
try
SELECT id, i1, i2, i3, i4 FROM jobs
inner join user_table on jobs.id = user_table.id WHERE jobs.id = $id GROUP BY id

MySQL FULL JOIN one table, and LEFT JOIN another in the same query?

i have three tables i would like to link in this one query.
The script is an attendance register, so it records an attendance mark for each meeting, per user.
The three tables used:
"team":
id | fullname | position | class | hidden
1 | Team | -- | black | 1
2 | Dan S | Team Manager | green | 0
3 | Harry P | Graphic Engineer | blue | 0
"register":
id | mid | uid | mark
1 | 1 | 2 | /
2 | 1 | 3 | I
3 | 2 | 1 | /
4 | 2 | 3 | /
"meetings":
id | maintask | starttime | endtime
1 | Organise Year Ahead | 1330007400 | 1330012800
2 | Gather Ideas | 1330612200 | 1330617600
3 | TODO | 1331217000 | 1331222400
There is a sample of the data. What i want to do is:
Select all the results from the register, group them by the user, and order them by the meeting start time. But, if there is not a mark in the register table, i want it to display "-" (can be done via php if needed) So an expected result like so:
fullname | mark | mid
Dan S | / | 1
Dan S | / | 2
Dan S | - | 3
Harry P | I | 1
Harry P | / | 2
Harry P | - | 3
My SQL Query is this at the moment:
SELECT u.fullname,u.id,r.mark,r.mid FROM team u FULL JOIN register r ON r.uid=u.id LEFT JOIN meetings m ON
r.mid=m.id GROUP BY u.id ORDER BY m.starttime ASC
And i get an error back from MySQL:
You have an error in your SQL syntax; check the manual that
corresponds to your MySQL server version for the right syntax to use
near 'FULL JOIN register r ON r.uid=u.id LEFT JOIN meetings m
ON r.mid=m.`id' at line 1
But, i cant see an issue with it :S
Please could someone help out, point me in the right direction or give me a possible solution to this. Much Appreciated
Dan
Answer:
Query that worked:
SELECT
u.fullname, u.id as uid,
if(r.uid = u.id, r.mark, '-') as mark,
if(r.uid = u.id, r.mid, '-') as mid,
r.mid, m.starttime
FROM
team u
CROSS JOIN
register r ON u.id = r.uid
LEFT OUTER JOIN
meetings m ON r.mid = m.id
WHERE
u.hidden = 0
GROUP BY
u.id, r.mid
ORDER BY
m.starttime, u.id ASC
Full outer join is not supported by MySQL. At least to version 5.6, you can check MySQL Join doc. A cross join may be a workaround:
EDITED
SELECT
UxM.fullname,
r.mark,
UxM.mid,
UxM.starttime
FROM
( select u.id as uid, m.id as mid, u.fullname, m.starttime
from
team u
CROSS JOIN
meetings ) UxM
left join
register r
on UxM.uid = r.uid and UxM.mid = r.mid
ORDER BY
UxM.starttime ASC
Let me know if this solve your issue.
A simplification:
SELECT
u.fullname,
u.id AS uid,
COALESCE(r.mark, '-') AS mark,
COALESCE(r.mid, '-') AS mid,
m.id,
m.starttime
FROM
team u
CROSS JOIN
meetings m
LEFT JOIN
register r
ON r.mid = m.id
AND r.id = u.uid
WHERE
u.hidden = 0
GROUP BY
m.id, u.id
ORDER BY
m.starttime, u.id

Categories