getting latest data in one to many relation table - mysql

i would like to fetch data from table a,b,c but order by most recent data of table response
table casework has this structure ( simplified):
casework_id | problem | user_id
------------+-----------+-------
1 | Problem1 | 1
2 | Problem2 | 2
3 | Problem3 | 1
4 | Problem4 | 3
table user has this structure ( simplified):
user_id | name
--------+-----------------
1 | peter
2 | Sam
3 | Tom
4 | Steve
table response has this structure ( simplified):
response_id | response | casework_id | created
------------+-----------+--------------+-------
1 | responce1 | 1 | 2012-10-14 11:28:31
2 | responce2 | 1 | 2012-9-10 11:28:31
3 | responce3 | 1 | 2012-9-2 11:28:31
4 | responce4 | 3 | 2012-8-3 11:28:31
4 | responce5 | 3 | 2012-8-2 11:28:31
I am looking the query to fetch data order by latest responce and group by casework_id
I. e. required out put is
casework_id | problem | name | responce | created
------------+-----------+-------+-----------+---------
1 | Problem1 | peter | responce1 | 2012-10-14 11:28:31
2 | Problem2 | Sam | Null | Null
3 | Problem3 | peter | responce4 | 2012-8-3 11:28:31
4 | Problem4 | Tom | Null | Null
I would be most grateful if one of you kind people could point me in the right direction.

You can use the following:
select c.casework_id,
c.problem,
u.name,
r2.response,
r1.created
from casework c
left join user u
on c.user_id = u.user_id
left join
(
select max(created) created, casework_id
from response r
group by casework_id
) r1
on c.casework_id = r1.casework_id
left join response r2
on r1.created = r2.created
and r1.casework_id = r2.casework_id
See SQL Fiddle with Demo
If you want to include both the user that created the casework and then who responsed, then you will want to join on the user table twice:
select c.casework_id,
c.problem,
u1.name CreatedByName,
r2.response,
r1.created,
u2.name ReponseName
from casework c
left join user u1
on c.user_id = u1.user_id
left join
(
select max(created) created, casework_id
from response r
group by casework_id
) r1
on c.casework_id = r1.casework_id
left join response r2
on r1.created = r2.created
and r1.casework_id = r2.casework_id
left join user u2
on r2.user_id = u2.user_id
See SQL Fiddle with demo

I have not tested it, but it might give you an idea
select c.casework_id, c.problem,
(select name from user u where u.user_id = c.user_id ),
(select r.reponse from response r where r.casework_id = c.casework_id ORDER BY r.created DESC LIMIT 1),
(select r.created from response r where r.casework_id = c.casework_id ORDER BY r.created DESC LIMIT 1),
from casework c

SELECT responce.casework_id, problem, name, responce, created
FROM responce
JOIN
(SELECT casework_id, problem, name
FROM casework JOIN user
ON casework.userid=user.userid) AS A
ON responce.casework_id=A.casework_id
ORDER BY responce, responce.casework_id

Try this
select c.caseword_id, c.problem, u.name, response.response, responce.created from asework c inner join user u on u.user_id = c.user_id left outer join select casework_id from response having max(created) group by casework_id) responsedata on responsedata.casework_id = c.casework_id

Related

Mysql left join with limit returning join record for one row

How do i join a table using limit?
I have the below query but it doesn't work as expected.
Am using left join to select only one row from table, but it only select one record as expected for the first row while it returns null on others
Even when they have file saved in TABLE_USER_FILES.
TABLE_USERS
uid | u_name
----|---------
p1 | Peter
j1 | John
f1 | Foo
b1 | Bar
TABLE_USER_POST
pid | p_name | p_uid
----|---------|--------
xp1 | PHP | p1
xp2 | SQL | p1
xp3 | JS | j1
xp4 | CSS | b1
TABLE_USER_FILES
fid | f_uid | f_url | f_path
----|--------|---------|----------
fa1 | p1 | ax.png | gallery
fb2 | p1 | bc.png | gallery
bc3 | j1 | cc.png | gallery
fd4 | f1 | cx.png | gallery
fe5 | j1 | qd.png | gallery
Query
SELECT post.*, user.u_name, files.f_url
FROM TABLE_USER_POST post
INNER JOIN TABLE_USERS user
ON user.uid = post.p_uid
LEFT JOIN (
SELECT f_url, f_uid
FROM TABLE_USER_FILES
WHERE f_path = "gallery"
ORDER BY fid DESC
LIMIT 1
) files
ON files.f_uid = post.p_uid
ORDER BY post.pid DESC
LIMIT 0, 20
Expected result
pid | p_name | p_uid | u_name | f_url
----|---------|--------|---------|---------
xp1 | PHP | p1 | Peter | bc.png
xp2 | SQL | p1 | Peter | bc.png
xp3 | JS | j1 | John | qd.png
xp4 | CSS | b1 | Bar | NULL
There are many solutions here. For example, LATERAL in MySQL 8.0.14+
SELECT post.*, user.u_name, files.f_url
FROM TABLE_USER_POST post
INNER JOIN TABLE_USERS user
ON user.uid = post.p_uid
LEFT OUTER JOIN LATERAL (
SELECT f_url, f_uid
FROM TABLE_USER_FILES tuf
WHERE f_path = "gallery"
AND tuf.f_uid = post.p_uid
ORDER BY fid DESC
LIMIT 1
) files ON true
ORDER BY post.pid DESC
LIMIT 0, 20
If only one column from TABLE_USER_FILES is needed, then the query in the SELECT clause:
SELECT post.*, user.u_name,
( SELECT f_url
FROM TABLE_USER_FILES tuf
WHERE f_path = "gallery"
AND tuf.f_uid = post.p_uid
ORDER BY fid DESC
LIMIT 1
) AS f_url
FROM TABLE_USER_POST post
INNER JOIN TABLE_USERS user
ON user.uid = post.p_uid
ORDER BY post.pid DESC
LIMIT 0, 20
db<>fiddle
Please try this instead.
SELECT post.*, user.u_name, files.f_url
FROM TABLE_USER_POSTS post
LEFT JOIN TABLE_USER_FILES files
ON files.f_uid = post.p_uid
AND files.fid = (SELECT MAX(fid) FROM TABLE_USER_FILES WHERE f_uid = files.f_uid)
INNER JOIN TABLE_USERS user
ON user.uid = post.p_uid
ORDER BY post.pid DESC;
Thank you!

adding different columns in same table usin inner join in mysql

I want to make a report of time entry of particular projects. I tried below query.
Table1: Projects
id | Name
------------
1 | A
2 | B
Table2: EmployeeTimeEntry
proj | activity |time
----------------------
1 | coding | 5
2 | coding | 2
1 | testing | 2
1 | coding | 2
My desired Outpput for proj A:
proj | TotalDur | activity | Activitytime
--------------------------------------------
A | 9 | coding | 7
A | 9 | testing | 2
My Query :
$query = "SELECT
name as 'Proj',
TimeEntry.Total as 'TotalDur',
ATimeEntry.ADetails as 'activity',
ATimeEntry.ATotal as 'Activitytime'
FROM Projects pr
INNER JOIN(SELECT project,SUM(time) as Total from EmployeeTimeEntry group by project ) TimeEntry on pr.id = TimeEntry.project
INNER JOIN(SELECT project,details as ADetails,SUM(time) as ATotal from EmployeeTimeEntry where id = pr.id group by details ) ATimeEntry on pr.id = TimeEntry.project";
But i got output as
proj | TotalDur | activity | Activitytime
--------------------------------------------
A | 9 | coding | 9
A | 9 | testing | 2
All activity times for all projects get added .
I use combobo to select which projects to show the report.
I think you are over complicating it
select
p.name as Proj,
x.TotalDur,
et.activity,
sum(et.time) as Activitytime
from Projects p
join (
select proj, sum(time) as TotalDur from EmployeeTimeEntry group by proj
)x on x.proj = p.id
join EmployeeTimeEntry et on et.proj = p.id
where p.name = 'A'
group by p.name,et.activity
DEMO
Maybe this is what you want?
select
p.Name as Proj,
(select sum(time) as TotalDur from EmployeeTimeEntry where proj = p.id group by proj) TotalDur,
activity,
sum(e.time) as ActivityTime
from Projects p
inner join EmployeeTimeEntry e on e.proj = p.id
where p.Name = 'A'
group by name, activity, p.id
Sample SQL Fiddle

How to get count for each row mysql query?

I have Three tables
1)review_trans
2)user_comment_trans
3)helpful_review_trans
The table structure looks like this
review_trans
review_id(pk) | review_desc | user_id
--------------+----------------+-----------
1 | hello world | 1
2 | test2 | 1
3 | test3 | 2
user_comment_trans
comment_id | review_id | user_id
------------+--------------+------------
1 | 1 | 4
2 | 1 | 2
3 | 2 | 3
helpful_review_trans
helpful_review_id | review_id | user_id
------------------+------------+------------
1 | 1 | 4
2 | 1 | 2
3 | 2 | 3
I want count on each review for helpful votes and comments.
So output i want is like this
OUTPUT
review_id review_desc count(helpful_review_id) count(comment_id)
------------+------------------+----------------------------+--------------------
1 | hello world | 2 | 2
2 | test2 | 1 | 1
3 | test3 | |
Iam unable to get this record.I tried joining the tables but it only shows just one review_desc
Please advise and help.
Use left join with count(distinct)
select r.review_id,
r.review_desc,
count(distinct u.comment_id),
count(distinct h.helpful_review_id)
from review_trans r
left join user_comment_trans u on(r.review_id = u.review_id)
left join helpful_review_trans h on(r.review_id = h.review_id)
group by r.review_id
Demo
SELECT rt.review_id, rt.review_desc,
COUNT(DISTINCT hrt.helpful_review_id), COUNT(DISTINCT uct.comment_id)
FROM review_trans rt
LEFT JOIN helpful_review_trans hrt ON rt.review_id = hrt.review_id
LEFT JOIN user_comment_trans uct ON uct.review_id = rt.review_id
GROUP BY rt.review_id
SELECT rt.review_id, rt.review_desc, helpful_count, comment_count
FROM review_trans AS rt
LEFT JOIN (
SELECT review_id, COUNT(*) AS comment_count
FROM user_comment_trans
GROUP BY review_id) AS uct ON rt.review_id = uct.review_id
LEFT JOIN (
SELECT review_id, COUNT(*) AS helpful_count
FROM helpful_review_trans
GROUP BY review_id) AS hrt ON rt.review_id = hrt.review_id
You could do this:
SELECT
review_trans.review_id,
review_trans.review_desc,
(
SELECT
COUNT(*)
FROM
helpful_review_trans
WHERE
helpful_review_trans.review_id=review_trans.review_id
) AS helpful_review_id,
(
SELECT
COUNT(*)
FROM
user_comment_trans
WHERE
user_comment_trans.review_id=review_trans.review_id
) AS CountComment_id
FROM
review_trans

How to optimize SQL query more?

First at all i am nood into SQL thing, Now i am working on a class project where
I have some tables like
Table user
user_id | username | name
1 | nihan | Nihan Dip
2 | dip | Meaw ghew
more | more | more
Table Friend
you | friend_id
1 | 2
1 | 27
2 | 9
more | more
Table Follow
user_id | follows
1 | 99
7 | 34
Table post
post_id | user_id | type | content | post_time
1 | 1 | text | loren toren | timestamp
2 | 2 | text | ipsum | timestamp
Now i want to get post by users friend and who he follows and offcourse his so i made this SQL
SELECT
username, name,content, post_time
FROM
post
INNER JOIN
user ON user.user_id = post.user_id
WHERE
post.user_id IN (SELECT
friend_id
FROM
friend
WHERE
you = 1
UNION ALL
SELECT
follows
FROM
follow
WHERE
user_id = 1)
OR post.user_id = 1
ORDER BY post_time DESC
LIMIT 10
this query works just fine. I just wanted to know is there anymore optimization could be done? Then how? Please teach me :)
Instead of using IN try it with JOIN add add few more indexes.
SELECT DISTINCT u.name, u.username,
p.content, p.post_time
FROM post p
INNER JOIN user u
ON u.user_id = p.user_id
INNER JOIN
(
SELECT friend_id id
FROM friend
WHERE you = 1
UNION ALL
SELECT follows id
FROM follow
WHERE user_id = 1
) s ON p.user_id = s.ID
ORDER BY post_time DESC
LIMIT 10

Trouble with join statement for selecting data across tables with MYSQL

I'm trying to display events that a user has created and events that he has signed up for. I have three tables for this.
//events
| event_id | event_title | event_details | event_timestamp | userid
1 title1 test 1234 1
2 title2 testing2 123 2
//registration_items : event_id references events.event_id
| id | event_id | task_name
1 2 task 1
//registration_signup : id references registration_items.id
| id | userid | timestamp
1 1 1234
Here's the current query I have. Right now it only displays the event the user created. It should display both created events and ones he signed up for
select events.*, registration_items.*, registration_signup.*, users.username from events
INNER JOIN users on users.userid = events.userid
LEFT JOIN registration_items ON registration_items.event_id = events.event_id
LEFT JOIN registration_signup ON registration_signup.id = registration_items.id
WHERE events.userid = '$user_id' OR registration_signup.userid = '$user_id' ORDER BY events.event_timestamp DESC
For userid1 the output should be
Title
title1 (the user created this)
title2 (the user signed up for this)
For userid2 the output should be
Title
title2
select events.*, registration_items.*, registration_signup.*, users.username
from events
INNER JOIN users on users.userid = events.userid
LEFT JOIN registration_items ON registration_items.event_id = events.event_id
LEFT JOIN registration_signup ON registration_signup.id = registration_items.id
WHERE registration_signup.userid = '$user_id'
union
select events.*, registration_items.*, registration_signup.*, users.username
from events
INNER JOIN users on users.userid = events.userid
INNER JOIN registration_items ON registration_items.event_id = events.event_id
INNER JOIN registration_signup ON registration_signup.id = registration_items.id
WHERE events.userid = '$user_id'
ORDER BY events.event_timestamp DESC
I am not sure if it's correct to guess that you have a typo in the sample data. Because your query works the moment you change the user id to 1 for both events, signed up events.. So please take a look at this reference demo and comment if it's not a typo...
SQLFIDDLE DEMO
query: (your query..)
select u.userid,e.event_id as id,
ri.event_id as evt, e.event_title,
ri.task_name,
rs.timestamp,
u.name from events e
INNER JOIN users u on
u.userid = e.userid
LEFT JOIN registration_items ri ON
ri.event_id = e.event_id
LEFT JOIN registration_signup rs ON
rs.id = ri.id
WHERE e.userid = '1' or
rs.userid = '1'
ORDER BY e.event_timestamp DESC
;
Results:
| USERID | ID | EVT | EVENT_TITLE | TASK_NAME | TIMESTAMP | NAME |
------------------------------------------------------------------
| 1 | 1 | 1 | title1 | task 1 | 1234 | john |
| 1 | 2 | 2 | title2 | task 1.2 | 3456 | john |