SQL - Get the latest event from table - mysql

I got two tables.
A dealer table (id, name, etc.) and an event table (id, did(dealerid), eid(fb eventid), venue, etc.) where I save the dealerid, eventid, eventurl and date from facebook.
I can get all data with this sql statement:
SELECT * FROM dealer as t_d INNER JOIN events AS t_e
ON t_d.id = t_e.did;
This works fine.
1 Laden Dortmund Stra 12 45525 Dortmund DE www.google.de 0201-123456 laden#dortmund.de 300 400 1 1 416364098428245 https://www.facebook.com/events/416364098428245/ 2013-01-28
2 Laden Unna Wurststr. 123 45130 Unna DE www.bing.de 0222-11223344 laden#unna.de 400 276 2 2 145457548940302 https://www.facebook.com/events/145457548940302/ 2013-03-08
2 Laden Unna Wurststr. 123 45130 Unna DE www.bing.de 0222-11223344 laden#unna.de 400 276 3 2 405092472902921 https://www.facebook.com/events/405092472902921/ 2013-04-26
As you can see, I get two rows for the dealer id 2, because there are two events listed.
How can I get the event, which is the closest to this date (today).
Later, there will be like 20 Dealer and for each one at least 3-4 events.
A hint would be nice, thank you!
UPDATE:
This is the solution!
SELECT t_d.*, t_e.*, DATE_FORMAT(t_e.date,'%d.%m.%Y') as date
FROM dealer as t_d
INNER JOIN events AS t_e
ON t_d.id = t_e.did
INNER JOIN
(
SELECT did, MIN(date) minDate
FROM events
GROUP BY did
) e ON t_e.did = e.did AND
t_e.date = e.minDate
But is it somehow possible to display ALL dealers, even if no event exists for the dealer?

SELECT t_d.*, t_e.*
FROM dealer as t_d
INNER JOIN events AS t_e
ON t_d.id = t_e.did
INNER JOIN
(
SELECT did, MAX(date) maxDate
FROM events
GROUP BY did
) e ON t_e.did = e.did AND
t_e.date = e.maxDate

Related

How to query all records from multiple tables with joins

I have my main table employee_rates_year:
tier skill rate year
1 28 110 2019
2 28 101 2019
my column skill is connected to an employees table and subcontractors table, for simplicity here is a shortened version of tblEmployees:
EMPLOYEEID Skill FullName
1 28 Employee One
2 28 Employee Two
and tblSubcontractors:
SUBCONTRACTORID Skill FullName
1 28 Sub One
2 28 Sub Two
I am trying to get a tier, rate and year show up for every individual employee & subcontractor.
I've tried using different joins but nothing seems to give me information with every employee/subcontractor.
Here is my query:
SELECT *
FROM employee_rates_year
left join tblsubcontractors on employee_rates_year.skill = tblsubcontractors.skill
left join tblemployees on employee_rates_year.skill = tblemployees.skill
The problem is that my query shows results like this:
tier skill rate year tblEmployees.FullName tblSubcontractors.Fullname
1 28 110 2019 Employee One Sub One
2 28 101 2019 Employee Two Sub Two
Whereas I am trying to get:
tier skill rate year tblEmployees.FullName tblSubcontractors.FullName
1 28 110 2019 Employee One
1 28 110 2019 Sub One
2 28 101 2019 Employee Two
2 28 101 2019 Sub Two
I have also tried using WHERE to try and differentiate between the two tables and pick individual records.
you should never use SELECT *, because.... 😜
Try:
SELECT
tier,
skill,
rate,
year,
tblEmployees.FullName As Employee
'' As Subcontractor
FROM employee_rates_year
left join tblsubcontractors on employee_rates_year.skill = tblsubcontractors.skill
union all
SELECT
tier,
skill,
rate,
year,
'' As Employee
tblSubcontractors.Fullname As Subcontractor
FROM employee_rates_year
left join tblemployees on employee_rates_year.skill = tblemployees.skill
You seem to need UNION ALL and not a double join:
SELECT e.*, t.FullName EmployeesFullName, NULL SubcontractorsFullName
FROM employee_rates_year e
left join tblsubcontractors t on e.skill = t.skill
UNION ALL
SELECT e.*, NULL, t.FullName
FROM employee_rates_year e
left join tblemployees t on e.skill = t.skill
ORDER BY e.tier, e.skill
Each query of the 2 uses a join of employee_rates_year with 1 of the other tables.
Finally the 2 resultsets are merged with UNION ALL.
Think the problem (or part of the problem) is because of the "left join", which creates one row in result for each row in the "left" table. Since employee_rates_year only has two rows, your result for query will only have 2 rows.
Use a union all to bring the employees and subcontactors together and then join and group by. To get values in "vertical lists", you can use row_number():
select er.skill, er.rate, er.year,
max(e_fullname) as e_fullname,
max(s_fullname) as s_fullname
from ((select e.skill, e.fullname as e_fullname, null as s_fullname,
row_number() over (partition by e.skill order by e.fullname) as seqnum
from tblemployees e
) union all
(select s.skill, null as e_fullname, s.fullname as s_fullname,
row_number() over (partition by s.skill order by s.fullname) as seqnum
from tblsubcontractors s
)
) es left join
employee_rates er
on es.skill = er.skill
group by er.skill, er.rate, er.year, seqnum;
If you just want the values in separate lists (with NULLs), then you don't need the row_number() trick:
select er.skill, er.rate, er.year, e_fullname, s_fullname
from ((select e.skill, e.fullname as e_fullname, null as s_fullname
from tblemployees e
) union all
(select s.skill, null as e_fullname, s.fullname as s_fullname
from tblsubcontractors s
)
) es left join
employee_rates er
on es.skill = er.skill;

how to select data from multiple table with variable condition | MySQL

I have two tables in the datbase to store client basic info (name, location, phone number) and another table to store client related transactions (date_sub, profile_sub,isPaid,date_exp,client_id) and i have an html table to view the client basic info and transaction if are available, my problem that i can't get a query to select the client info from table internetClient and from internetclientDetails at the same time, because query is only resulting when client have trans in the detail table. the two table fields are as follow:
internetClient
--------------------------------------------------------
id full_name location phone_number
-------------------------------------------------------
4 Joe Amine beirut 03776132
5 Mariam zoue beirut 03556133
and
internetclientdetails
--------------------------------------------------------------------------
incdid icid date_sub date_exp isPaid sub_price
----------------------------------------------------------------------------
6 4 2018-01-01 2018-01-30 0 2000
7 5 2017-01-01 2017-01-30 0 1000
8 4 2018-03-01 2018-03-30 1 50000
9 5 2018-05-01 2019-05-30 1 90000
// incdid > internetClientDetailsId
// icid> internetClientId
if client have trans in orderdetails, the query should return value like that:
client_id full_name date_sub date_exp isPaid sub_price
-------------------------------------------------------------------------------------
4 Joe Amine 2018-03-01 2018-03-30 1 50000
5 Mariam zoue 2018-05-01 2019-05-30 1 90000
else if the client has no id in internetOrederDetails
--------------------------------------------------------
icid full_name location phone_number
-------------------------------------------------------
4 Joe Amine beirut 03776132
5 Mariam zoue beirut 0355613
Thanks in advance
try with left join. It will display all records from internetClient and related record from internetclientdetails
Select internetClient.id, internetClient.full_name
, internetClient.location, internetClient.phone_number
, internetclientdetails.incdid, internetclientdetails.icid
, internetclientdetails.date_sub, internetclientdetails.date_exp
, internetclientdetails.isPaid, internetclientdetails.sub_price
from internetClient
left join internetclientdetails
on internetClient.id=internetclientdetails.icid group by internetclientdetails.icid order by internetclientdetails.incdid desc
if you want to get records of, only paid clients then you can try the following
Select internetClient.id, internetClient.full_name
, internetClient.location, internetClient.phone_number
, internetclientdetails.icid, internetclientdetails.incdid
, internetclientdetails.date_sub, internetclientdetails.date_exp
, internetclientdetails.isPaid, internetclientdetails.sub_price
from internetClient
left join internetclientdetails
on internetClient.id=internetclientdetails.icid
and internetclientdetails.isPaid=1 group by internetclientdetails.icid
order by internetclientdetails.incdid desc
SUMMARY
We generate a dataset containing just the ICID and max(date_sub) (alias:ICDi) We join this to the InternetClientDetails (ICD) to obtain just the max date record per client. Then left join this to the IC record; ensuring we keep all InternetClient(IC) records; and only show the related max Detail Record.
The below approach should work in most mySQL versions. It does not use an analytic which we could use to get the max date instead of the derived table provided the MySQL version you use supported it.
FINAL ANSWER:
SELECT IC.id
, IC.full_name
, IC.location
, IC.phone_number
, ICD.icid
, ICD.incdid
, ICD.date_sub
, ICD.date_exp
, ICD.isPaid
, ICD.sub_price
FROM internetClient IC
LEFT JOIN (SELECT ICDi.*
FROM internetclientdetails ICDi
INNER JOIN (SELECT max(date_sub) MaxDateSub, ICID
FROM internetclientdetails
GROUP BY ICID) mICD
ON ICDi.ICID = mICD.ICID
AND ICDi.Date_Sub = mICD.MaxDateSub
) ICD
on IC.id=ICD.icid
ORDER BY ICD.incdid desc
BREAKDOWN / EXPLANATION
The below gives us a subset of max(date_Sub) for each ICID in clientDetails. We need to so we can filter out all the records which are not the max date per clientID.
(SELECT max(date_sub) MaxDateSub, ICID
FROM internetclientdetails
GROUP BY ICID) mICD
Using that set we join to the details on the Client_ID's and the max date to eliminate all but the most recent detail for each client. We do this because we need the other detail attributes. This could be done using a join or exists. I prefer the join approach as it seems more explicit to me.
(SELECT ICDi.*
FROM internetclientdetails ICDi
INNER JOIN (SELECT max(date_sub) MaxDateSub, ICID
FROM internetclientdetails
GROUP BY ICID) mICD
ON ICDi.ICID = mICD.ICID
AND ICDi.Date_Sub = mICD.MaxDateSub
) ICD
Finally the full query joins the client to the detail keeping client even if there is no detail using a left join.
COMPONENTS:
You wanted all records from InternetClient (FROM internetClient IC)
You wanted related records from InternetClientDetail (LEFT Join InternetClientDetail ICD) while retaining teh records from InternetClient.
You ONLY wanted the most current record from InternetClientDetail (INNER JOIN InternetClientDetail mICD as a derived table getting ICID and max(date))
Total record count should = total record count in InternetClient which means all relationships must be a 1:1o on the table joins -- one-to-one Optional.

MySQL: Select Most Recent Response By Max Date from JOINing Tables

I have a survey table that compiles non-unique records whenever that person responds to a survey, so they can be in there multiple times -- I'm trying to figure out how to bring back the just the row with the most recent date.
Here's the person table:
ID First Last Employer
1 Jerry Seinfeld NBC
2 Elaine Benes Pendant Publishing
3 George Costanza Kruger Industrial Smoothing
4 Cosmo Kramer Kramerica Industries
And here's the survey table:
ID Survey Response Date
1 9 Yes 4/14/15
1 9 No 8/9/15
2 9 No 10/13/15
3 9 No 6/19/15
3 9 Yes 2/3/15
3 8 IQ 7/27/15
4 9 Yes 5/12/15
If the IDs duplicate and the survey number is 9, I only want returned the row with the most recent date.
Here's what I've been trying:
SELECT p.id, p.first, p.last, p.employer, s.response, s.date
FROM person p
LEFT JOIN
(SELECT s1.id, s1.survey, s1.response, s1.date, MAX(s1.date)
FROM survey s1
WHERE s1.survey = 9
GROUP BY s1.id) AS s ON s.id = p.id
ORDER BY s.date;
But whenever I do that the max date and the actual date for the row don't match sometimes -- so the MAX function is working correctly but only with regards to the ID, not with regards to giving me that row. But I have to group on the ID in order to properly match the two tables and that's where I'm getting stuck.
And when I try something like this I get the Invalid use of group function error:
SELECT p.id, p.first, p.last, p.employer, s.response, s.date
FROM person p
LEFT JOIN
(SELECT s1.id, s1.survey, s1.response, s1.date, MAX(s1.date)
FROM survey s1
WHERE s1.survey = 9 AND MAX(s1.date) = s1.date
GROUP BY s1.id) AS s ON s.id = p.id
ORDER BY s.date;
My desired result looks like this:
ID First Last Employer Response Date
3 George Costanza Kruger Industrial Smoothing Yes 2/3/15
4 Cosmo Kramer Kramerica Industries Yes 5/12/15
1 Jerry Seinfeld NBC No 8/9/15
2 Elaine Benes Pendant Publishing No 10/13/15
Here is tested query:
select `person`.*,`survey`.`Response`,`survey`.`Date`
from `survey`
inner join
(
SELECT ID,max(`Date`) as `d`
FROM `survey`
WHERE `Survey`=9
group by ID
) as `t` on `t`.`ID` = `survey`.`ID` and
`t`.`d` = `survey`.`Date`
inner join `person` on `person`.`ID` = `survey`.`ID`

MySQL select values from Multiple Tables dependent on latest value in one

I have the following three tables to look after support tickets in a small web application, but I need some help getting the data I need.
Table 1 (ticket):
user_ID site_ID support_ID timestamp priority title
12 25 3 2014-09-26 14:09:25 0 A Test Row
12 26 4 2014-09-27 09:41:18 0 A 2nd Test Row
Table 2 (ticket_reply):
reply_ID support_ID user_ID support_reply reply_timestamp
3 3 12 some really boring text 2014-09-26 14:09:25
4 3 25 some really boring reply 2014-09-26 15:35:18
5 4 12 some really boring text 2014-09-27 09:41:18
Table 3 (ticket_status):
ticket_status_ID support_ID status_ID status_timestamp
3 3 40 2014-09-26 14:09:25
4 3 41 2014-09-26 15:35:18
5 4 40 2014-09-27 09:41:18
The 1st table holds the key ticket information, the 2nd, any replies made to the corresponding ticket, and the third tracks the change in status (statuses are held in another table, but don't need anything from there).
What I need to do is get the number of tickets where the latest status is == 40, and if this is greater than 0, get the latest reply along with the data from the first table.
I've tried multiple ways of doing this, but I am stuck. Don't really want to paste them here as they will likely confuse people, and I doubt they are even close.
This one was rather tricky, however here is a working solution for you.
This query will get the most recent support_reply value for all tickets where the most recent status_ID is 40.
SELECT
ticket_status_ID,
support_ID,
status_ID,
status_timestamp,
reply_ID,
support_reply,
reply_timestamp,
`timestamp` ticket_timestamp,
`priority` ticket_priority,
title
FROM (
SELECT * FROM (
SELECT * FROM (
SELECT
ticket_status.ticket_status_ID,
ticket_status.support_ID,
ticket_status.status_ID,
ticket_status.status_timestamp,
ts1.reply_ID,
ts1.user_ID,
ts1.support_reply,
ts1.reply_timestamp
FROM
ticket_status
INNER JOIN (SELECT * FROM ticket_reply ORDER BY reply_timestamp DESC) ts1 ON ts1.support_ID = ticket_status.support_ID
GROUP BY support_ID, status_ID
ORDER BY status_timestamp DESC
) ts2
GROUP BY ts2.support_ID
) ts3
INNER JOIN (SELECT support_ID as `ticket_support_ID`, site_ID, `timestamp`, priority, title FROM ticket) ts4 ON ts4.ticket_support_ID = ts3.support_ID
WHERE ts3.status_ID = 40
) ts5
From the example given, it looks that all timestamp are equivalent, so a query like this should be enough:
SELECT
ticket.*,
ticket_reply.*
FROM
(SELECT support_ID, MAX(status_timestamp) as max_timestamp
FROM ticket_status
GROUP BY support_ID) m
INNER JOIN ticket
ON m.support_ID=ticket.support_ID
AND m.max_timestamp=ticket.`timestamp`
INNER JOIN ticket_reply
ON m.support_ID=ticket_reply.support_ID
AND m.max_timestamp=ticket_reply.reply_timestamp
INNER JOIN ticket_status
ON m.support_ID=ticket_status.support_ID
AND m.max_timestamp=ticket_status.status_timestamp
WHERE
status_ID=40;
but depending on the logic of your application, it might happen that the last row in a table has a timestamp of 2014-09-27 09:41:18 and the last in another has for example 2014-09-27 09:41:19.
In this case, you should use a query like this one:
SELECT
ticket.*,
ticket_reply.*
FROM
(SELECT support_ID, MAX(status_timestamp) AS max_status_timestamp
FROM ticket_status
GROUP BY support_ID) m_status
INNER JOIN
(SELECT support_ID, MAX(reply_timestamp) AS max_reply_timestamp
FROM ticket_reply
GROUP BY support_ID) m_reply
ON m_status.support_ID=m_reply.support_ID
INNER JOIN
(SELECT support_ID, MAX(`timestamp`) AS max_ticket_timestamp
FROM ticket
GROUP BY support_ID) m_ticket
ON m_status.support_ID=m_ticket.support_ID
INNER JOIN ticket_status
ON ticket_status.support_ID=m_status.support_ID
AND ticket_status.status_timestamp=m_status.max_status_timestamp
INNER JOIN ticket_reply
ON ticket_reply.support_ID=m_reply.support_ID
AND ticket_reply.reply_timestamp=m_reply.max_reply_timestamp
INNER JOIN ticket
ON ticket.support_ID=m_ticket.support_ID
AND ticket.`timestamp`=m_ticket.max_ticket_timestamp
WHERE
ticket_status.status_ID=40;
Please see fiddle here.
You can try this one:
SELECT t.*, tr.support_reply, ts.status_timestamp
FROM ticket_status as ts
left join ticket_reply as tr on(ts.support_ID=tr.support_ID)
left join ticket as t on(t.support_ID=tr.support_ID)
where status_ID=40
order by status_timestamp desc
limit 1;

SUM 2 Field from 2 different tables

I have a mysql query like this :
SELECT SUM(bills.Amount) AS AmountExpense, SUM(assets.Amount) as AmountIncome
FROM bills, assets where bills.UserId = 11 and assets.UserId =11
Sample Bills table
id payee description UserId Amount
1 john advance 11 15.0
2 dave request 2 13.0
3 er request 11 12.0
Sample assets table
id payee description UserId Amount
1 john advance 11 40.2
2 dave request 2 13.0
3 ww request 11 14.00
I have a problem with AmountExpense, the record SUM record multiple time. I have successed with Amount Income. Any suggestions?
You have most likely more than one row per user on one or both of those tables. You'll need to join them after performing the aggregation. Also, please don't use old style non ANSI implicit joins:
SELECT AmountExpense, AmountIncome
FROM ( SELECT UserId,
SUM(Amount) AS AmountExpense
FROM bills
GROUP BY UserId) AS b
LEFT JOIN ( SELECT UserId,
SUM(Amount) AmountIncome
FROM assets
GROUP BY UserId) AS a
ON b.UserId = a.UserId
WHERE b.UserId = 11
If you have the possibility that users can be in either table, but not the other, then you want the equivalent of a full outer join. MySQL doesn't support that syntax, but it does support this:
select userid, sum(amountexpense) as amountexpense, sum(amountincome) as amountincome
from (select userid, amount as amountexpense, null as amountincome
from bills
union all
select userid, null, amount as amountincome
from assets
) ba
group by userid;