MySQL LIMIT on a LEFT JOIN - sql

My query:
SELECT issues.*,
comments.author AS commentauthor,
comments.when_posted AS commentposted
FROM issues
LEFT JOIN (SELECT *
FROM comments
ORDER BY when_posted DESC
LIMIT 1) AS comments ON issues.id=comments.issue
ORDER BY IFNULL(commentposted, issues.when_opened) DESC
My problem with it is the "LIMIT 1" on the third line. That limits all comments to only the newest one, so only issues with the newest comment will be reported back as having a comment at all.
If I removed the "LIMIT 1" part from there, I'd get a row for every comment in an issue, and that's not what I want. What I want is only the newest comment for each issue.
In any case, I'm not sure if my IFNULL part even works because that's not where I'm up to in debugging yet.
So how would I achieve what I wanted?

Try:
SELECT i.*,
c.author AS commentauthor,
c.when_posted AS commentposted
FROM ISSUES i
LEFT JOIN COMMENTS c ON c.issue = i.id
JOIN (SELECT c.issue,
MAX(c.when_posted) 'max_when_posted'
FROM COMMENTS c
GROUP BY c.issue) mwp ON mwp.issue = c.issue
AND mwp.max_when_posted = c.when_posted
ORDER BY COALESCE(c.when_posted, i.when_opened) DESC

SELECT issues.*,
comments.author AS commentauthor,
comments.when_posted AS commentposted
FROM issues
LEFT JOIN ( SELECT c1.issue, c1.author, c1.when_posted
FROM comments c1
JOIN
(SELECT c2.issue, max(c2.when_posted) AS max_when_posted
FROM comments c2
GROUP BY issue) c3
on c1.issue = c3.issue and c1.when_posted = c3.max_when_posted
) AS comments ON issues.id=comments.issue
ORDER BY COALESCE(commentposted, issues.when_opened) DESC

Edit
Since MySql does not have CTE's after all, try this:
SELECT i.*
c.author AS CommentAuthor,
c.when_posted AS CommentPosted
FROM Issues i
LEFT JOIN
(SELECT issue, MAX(when_posted) AS LastPostDate
FROM comments GROUP BY issue) ic ON ic.issue = i.id
LEFT JOIN Comment c ON c.issue = i.id AND c.when_posted = ic.LastPostDate
ORDER BY COALESCE(ic.LastPostDate, issues.when_opened) DESC

Related

Filtering group of selected data by the latest dates for specific article

I'm trying to get data from SQL database with SELECT:
SELECT DISTINCT T2D.NO_ARTIKLU,
T2D.NAZEV_ARTIKLU,
T2D.DATUM,
T10.NO_PARTNERA
FROM D3000S.DIA2ZZ0D T2D, D3000S.DIA1ZZ00 T10, D3000S.DIA2ZZ00 T20
WHERE T10.NO_PARTNERA = T2D.NO_PARTNERA AND T2D.AKTIVITA > 0
The problem is ->
There are most of duplicates that I want to filter with SELECT
and I need to show only article with the latest datetime.
Thank you for the answers.
Please see below query .Rank can be used to eliminate the duplicate values.
SELECT * FROM
(
SELECT DISTINCT T2D.NO_ARTIKLU,
T2D.NAZEV_ARTIKLU,
T2D.DATUM,
T10.NO_PARTNERA,Row_Number() OVER(PARTITION BY Duplicatidentifier ORDER
By Datetimecolumn desc)
AS Rank
FROM D3000S.DIA2ZZ0D T2D, D3000S.DIA1ZZ00 T10, D3000S.DIA2ZZ00 T20
WHERE T10.NO_PARTNERA = T2D.NO_PARTNERA AND T2D.AKTIVITA > 0
) AS B WHERE Rank=1
Firstly, echoing a previous comment, you should use ANSI join syntax. Reasons include increased clarity and support for full outer joins. The topic is discussed here
An obvious problem with your query, is that you do not join the third table to anything. Fixing this gives:
SELECT DISTINCT T2D.NO_ARTIKLU,
T2D.NAZEV_ARTIKLU,
T2D.DATUM,
T10.NO_PARTNERA
FROM D3000S.DIA2ZZ0D T2D
INNER JOIN D3000S.DIA1ZZ00 T10 ON T10.NO_PARTNERA = T2D.NO_PARTNERA
INNER JOIN D3000S.DIA2ZZ00 T20 ON T10.NO_PARTNERA = T20.NO_PARTNERA
WHERE T2D.AKTIVITA > 0

SELECT statement where rows are omitted based on another table

Table with orders has another table with positions. I want the orders table to show but then only have the most up to-date position on it. Below is a picture of the 3 rows I want showing. Omit the rest.
SELECT DispatchTable.ordernumber, DispatchTable.truck,
DispatchTable.driver, DispatchTable.actualpickup,
DispatchTable.actualdropoff, orders.pickupdateandtime,
orders.dropoffdateandtime, Truck002.lastposition,
Truck002.lastdateandtime
FROM DispatchTable
INNER JOIN orders ON DispatchTable.ordernumber = orders.id
INNER JOIN Truck002 ON DispatchTable.truck = Truck002.name
WHERE (orders.status = 'onRoute')
Assuming that you want the row having the latest lastdateandtime for the truck name, this should work:
SELECT DispatchTable.ordernumber,
DispatchTable.truck,
DispatchTable.driver,
DispatchTable.actualpickup,
DispatchTable.actualdropoff,
orders.pickupdateandtime,
orders.dropoffdateandtime,
TruckLatest.lastposition,
TruckLatest.lastdateandtime
FROM DispatchTable
INNER JOIN orders ON DispatchTable.ordernumber = orders.id
INNER JOIN (SELECT name,
lastposition,
lastdateandtime
FROM Truck002 Truck1
WHERE lastdateandtime =
(SELECT MAX(lastdateandtime)
FROM Truck002 Truck2
WHERE Truck2.name = Truck1.name)) TruckLatest
ON DispatchTable.truck = TruckLatest.name
WHERE (orders.status = 'onRoute')
If I understand correctly, you can get the most recent record for a truck using ROW_NUMBER():
SELECT dt.ordernumber, dt.truck,
dt.driver, dt.actualpickup,
dt.actualdropoff, o.pickupdateandtime,
o.dropoffdateandtime, t.lastposition,
t.lastdateandtime
FROM DispatchTable dt INNER JOIN
orders o
ON dt.ordernumber = o.id INNER JOIN
(SELECT t.*,
ROW_NUMBER() OVER (PARTITION BY t.name ORDER BY t.lastdateandtime DESC) as seqnum
FROM Truck002 t
) t
ON dt.truck = t.name
WHERE o.status = 'onRoute' AND seqnum = 1;
Firstly, why are you using Truck002's name field rather than its id field as the link to DispacthTable? This is considered a less efficient way of doing it than using id (which is either a numerical field or a shorter string than name).
Secondly, you should mention in your Question that each Order can have many DispatchTable's and that each DispacthTable can have many Truck002's, otherwise many people will start by assuming that it is the other way round between DispatchTable and Truck002.
Thirdly, please try...
SELECT DispatchTable.ordernumber,
DispatchTable.truck,
DispatchTable.driver,
DispatchTable.actualpickup,
DispatchTable.actualdropoff,
orders.pickupdateandtime,
orders.dropoffdateandtime,
Truck002.lastposition,
Truck002.lastdateandtime
FROM DispatchTable
INNER JOIN orders ON DispatchTable.ordernumber = orders.id
INNER JOIN Truck002 ON DispatchTable.truck = Truck002.name
WHERE (orders.status = 'onRoute')
GROUP BY ordernumber
HAVING lastdateandtime = MAX( lastdateandtime )
If you have any questions or comments, then please feel free to post a Comment accordingly.
Further Reading
https://msdn.microsoft.com/en-us/library/bb177906(v=office.12).aspx (on HAVING)
https://www.w3schools.com/sql/sql_having.asp (on HAVING)
https://msdn.microsoft.com/en-us/library/bb177905(v=office.12).aspx (on GROUP BY)
https://www.w3schools.com/sql/sql_groupby.asp (on GROUP BY)

SQL - select only newest record with WHERE clause

I have been trying to get some data off our database but got stuck when I needed to only get the newest file upload for each file type. I have done this before using the WHERE clause but this time there is an extra table involved that is needed to determine the file type.
My query looks like this so far and i am getting six records for this user (2x filetypeNo4 and 4x filetypeNo2).
SELECT db_file.fileID
,db_profile.NAME
,db_applicationFileType.fileTypeID
,> db_file.dateCreated
FROM db_file
LEFT JOIN db_applicationFiles
ON db_file.fileID = db_applicationFiles.fileID
LEFT JOIN db_profile
ON db_applicationFiles.profileID = db_profile.profileID
LEFT JOIN db_applicationFileType
ON db_applicationFiles.fileTypeID = > > db_applicationFileType.fileTypeID
WHERE db_profile.profileID IN ('19456')
AND db_applicationFileType.fileTypeID IN ('2','4')
I have the WHERE clause looking like this which is not working:
(db_file.dateCreated IS NULL
OR db_file.dateCreated = (
SELECT MAX(db_file.dateCreated)
FROM db_file left join
db_applicationFiles on db_file.fileID = db_applicationFiles.fileID
WHERE db_applicationFileType.fileTypeID = db_applicationFiles.FiletypeID
))
Sorry I am a noob so this may be really simple, but I just learn this stuff as I go on my own..
SELECT
ff.fileID,
pf.NAME,
ff.fileTypeID,
ff.dateCreated
FROM db_profile pf
OUTER APPLY
(
SELECT TOP 1 af.fileTypeID, df.dateCreated, df.fileID
FROM db_file df
INNER JOIN db_applicationFiles af
ON df.fileID = af.fileID
WHERE af.profileID = pf.profileID
AND af.fileTypeID IN ('2','4')
ORDER BY create_date DESC
) ff
WHERE pf.profileID IN ('19456')
And it looks like all of your joins are actually INNER. Unless there may be profile without files (that's why OUTER apply instead of CROSS).
What about an obvious:
SELECT * FROM
(SELECT * FROM db_file ORDER BY dateCreated DESC) AS files1
GROUP BY fileTypeID ;

Returning DISTINCT rows from database query

I am fairly new to SQL so apologies if there is a simple solution to this.
I have this piece of SQL that performs a join on 3 tables.
SELECT a.group_leader, b.forum_name
FROM flightuser_group a
INNER JOIN flightacl_groups c ON a.group_id = c.group_id
JOIN flightforums b ON c.forum_id = b.forum_id
WHERE a.user_id = '60'
ORDER BY a.group_leader DESC
This query returns this:
group_leader forum_name
1 tmpSQJ
0 jobby7
0 jobby5
0 tmpSQJ
I am trying to only keep the first tmpSQJ entry and remove the second but cannot determine where the DISTICT clause goes.
Many thanks in advance.
Try This:
SELECT MAX(a.group_leader), b.forum_name
FROM flightuser_group a INNER JOIN flightacl_groups c ON a.group_id = c.group_id
JOIN flightforums b ON c.forum_id = b.forum_id
WHERE a.user_id = '60'
GROUP BY b.forum_name
ORDER BY a.group_leader DESC
For MySQL, add a LIMIT 1 after the ORDER BY.
For MS SQL, add a TOP 1 after the SELECT.
These two flavors will get you only the first record in the recordset.
You could try a GROUP BY which essentially behaves the same:
SELECT a.group_leader, b.forum_name
FROM flightuser_group a
INNER JOIN flightacl_groups c ON a.group_id = c.group_id
JOIN flightforums b ON c.forum_id = b.forum_id
WHERE a.user_id = '60'
GROUP BY b.forum_name
ORDER BY a.group_leader DESC
You could also look at using "INNER JOIN" for flightforums

Max date in view on left outer join

Thanks to a previous question, I found out how to pull the most recent data based on a linked table. BUT, now I have a related question.
The solution that I found used row_number() and PARTITION to pull the most recent set of data. But what if there's a possibility for zero or more rows in a linked table in the view? For example, the table FollowUpDate might have 0 rows, or 1, or more. I just want the most recent FollowUpDate:
SELECT
EFD.FormId
,EFD.StatusName
,MAX(EFD.ActionDate)
,EFT.Name AS FormType
,ECOA.Account AS ChargeOffAccount
,ERC.Name AS ReasonCode
,EAC.Description AS ApprovalCode
,MAX(EFU.FollowUpDate) AS FollowUpDate
FROM (
SELECT EF.FormId, EFD.ActionDate, EFS.Name AS StatusName, EF.FormTypeId, EF.ChargeOffId, EF.ReasonCodeId, EF.ApprovalCodeId,
row_number() OVER ( PARTITION BY EF.FormId ORDER BY EFD.ActionDate DESC ) DateSortKey
FROM Extension.FormDate EFD INNER JOIN Extension.Form EF ON EFD.FormId = EF.FormId INNER JOIN Extension.FormStatus EFS ON EFD.StatusId = EFS.StatusId
) EFD
INNER JOIN Extension.FormType EFT ON EFD.FormTypeId = EFT.FormTypeId
LEFT OUTER JOIN Extension.ChargeOffAccount ECOA ON EFD.ChargeOffId = ECOA.ChargeOffId
LEFT OUTER JOIN Extension.ReasonCode ERC ON EFD.ReasonCodeId = ERC.ReasonCodeId
LEFT OUTER JOIN Extension.ApprovalCode EAC ON EFD.ApprovalCodeId = EAC.ApprovalCodeId
LEFT OUTER JOIN (Select EFU.FormId, EFU.FollowUpDate, row_number() OVER (PARTITION BY EFU.FormId ORDER BY EFU.FollowUpDate DESC) FUDateSortKey FROM Extension.FormFollowUp EFU INNER JOIN Extension.Form EF ON EFU.FormId = EF.FormId) EFU ON EFD.FormId = EFU.FormId
WHERE EFD.DateSortKey = 1
GROUP BY
EFD.FormId, EFD.ActionDate, EFD.StatusName, EFT.Name, ECOA.Account, ERC.Name, EAC.Description, EFU.FollowUpDate
ORDER BY
EFD.FormId
If I do a similar pull using row_number() and PARTITION, I get the data only if there is at least one row in FollowUpDate. Kinda defeats the purpose of a LEFT OUTER JOIN. Can anyone help me get this working?
I rewrote your query - you had unnecessary subselects, and used row_number() for the FUDateSortKey but didn't use the column:
SELECT t.formid,
t.statusname,
MAX(t.actiondate) 'actiondate',
t.formtype,
t.chargeoffaccount,
t.reasoncode,
t.approvalcode,
MAX(t.followupdate) 'followupdate'
FROM (
SELECT t.formid,
fs.name 'StatusName',
t.actiondate,
ft.name 'formtype',
coa.account 'ChargeOffAccount',
rc.name 'ReasonCode',
ac.description 'ApprovalCode',
ffu.followupdate,
row_number() OVER (PARTITION BY ef.formid ORDER BY t.actiondate DESC) 'DateSortKey'
FROM EXTENSION.FORMDATE t
JOIN EXTENSION.FORM ef ON ef.formid = t.formid
JOIN EXTENSION.FORMSTATUS fs ON fs.statusid = t.statusid
JOIN EXTENSION.FORMTYPE ft ON ft.formtypeid = ef.formtypeid
LEFT JOIN EXTENSION.CHARGEOFFACCOUNT coa ON coa.chargeoffid = ef.chargeoffid
LEFT JOIN EXTENSION.REASONCODE rc ON rc.reasoncodeid = ef.reasoncodeid
LEFT JOIN EXTENSION.APPROVALCODE ac ON ac.approvalcodeid = ef.approvalcodeid
LEFT JOIN EXTENSION.FORMFOLLOWUP ffu ON ffu.formid = t.formid) t
WHERE t.datesortkey = 1
GROUP BY t.formid, t.statusname, t.formtype, t.chargeoffaccount, t.reasoncode, t.approvalcode
ORDER BY t.formid
The change I made to allow for FollowUpDate was to use a LEFT JOIN onto the FORMFOLLOWUP table - you were doing an INNER JOIN, so you'd only get rows with FORMFOLLOWUP records associated.
It's pretty hard to guess what's going on without table definitions and sample data.
Also, this is confusing: "the table FollowUpDate might have 0 rows" and you "want the most recent FollowUpDate." (especially when there is no table named FollowUpDate) There is no "most recent FollowUpDate" if there are zero FollowUpDates.
Maybe you want
WHERE <follow up date row number> in (1,NULL)
I figured it out. And as usual, I need a nap. I just needed to change my subselect to something I would swear I'd tried with no success:
SELECT field1, field2
FROM Table1 t1
LEFT JOIN (
SELECT field3, max(dateColumn)
FROM Table2
GROUP BY
field3
) t2
ON (t1.field1 = t2.field3)