Join Using Maximum Date - sql

I have a table that I am trying to join with based on an ID, however I only want to join with the rows that have the maximum "PeriodDT" (a datetime column) for that ID.
I have tried using the Top 1 order by that "PeriodDT" however it will only let me select one column or I get the error:
Only one expression can be specified in the select list when the
subquery is not introduced with EXISTS
Here is the query I Used:
Select a.Name as PropertyName,
a.PropertyNum as PropertyNum,
a.City as City,
a.State as State,
b.Name as LoanName,
b.LoanNum,
(select Top 1 c.IntRate as IntRate,
c.MaturityDT
from vNoteDetail c where c.LoanID = b.LoanID Order By c.PeriodDT DESC)
from vProperty a join vLoan b on a.LoanID = b.LoanId
Is there a better way to do this?

Try
Select a.Name as PropertyName,
a.PropertyNum as PropertyNum,
a.City as City,
a.State as State,
b.Name as LoanName,
b.LoanNum,
v1.IntRate,
v1.MaturityDT
from vProperty a join vLoan b on a.LoanID = b.LoanId
CROSS APPLY (select Top 1 c.IntRate as IntRate,
c.MaturityDT
from vNoteDetail c where c.LoanID = b.LoanID Order By c.PeriodDT DESC) AS V1

try this..
;WITH cte
AS (SELECT Row_number() OVER(partition BY clientid ORDER BY perioddt DESC) rn,
intrate,
perioddt MaturityDT,
loanid
FROM vnotedetail)
SELECT a.NAME AS PropertyName,
a.propertynum AS PropertyNum,
a.city AS City,
a.state AS State,
b.NAME AS LoanName,
b.loannum,
c.intrate,
c.maturitydt,
FROM vproperty a
JOIN vloan b
ON a.loanid = b.loanid
JOIN cte c
ON c.loanid = b.loanid
WHERE c.rn = 1
FYI restrictions of subquery CHECK THIS

Related

Join two tables returning only one row from the second table

I have this query:
SELECT t_ticket.ticketID, t_ticket.addedDate, t_ticket.question,
t_ticket.code, t_ticket.priority, t_actionTicket.addedDateAction, t_actionTicket.title
FROM t_actionTicket INNER JOIN
t_ticket ON t_actionTicket.ticketID_FK = t_ticket.ticketID INNER JOIN
(SELECT ticketID_FK, MAX(addedDateAction) AS maxDate
FROM t_actionTicket AS t_actionTicket_1
WHERE (t_actionTicket.userID_FK <> #userid)
GROUP BY ticketID_FK) AS b ON t_actionTicket.ticketID_FK = b.ticketID_FK AND t_actionTicket.addedDateAction = b.maxDate
WHERE (t_ticket.supporterID_FK IN
(SELECT supporterID
FROM t_Supporter
WHERE (userID_FK = #userid)))
I want to return just the latest record in t_actionTicket table for each row in t_ticket table that t_actionTicket.userID_FK <> #userid.
but I have this error:
The multi-part identifier "t_actionTicket.userID_FK" could not be
bound.
Problem in your query is
FROM t_actionTicket AS t_actionTicket_1
WHERE t_actionTicket.userID_FK <> #userid -- here
You cannot use t_actionTicket alias name inside inner join select query. You need to use t_actionTicket_1. It is possible only in sub-query
Try this better way of doing it
;WITH cte
AS (SELECT t_ticket.ticketID,
t_ticket.addedDate,
t_ticket.question,
t_ticket.code,
t_ticket.priority,
t_actionTicket.addedDateAction,
t_actionTicket.title,
Row_number()
OVER(
partition BY ticketID_FK
ORDER BY addedDateAction DESC) RN
FROM t_actionTicket
INNER JOIN t_ticket
ON t_actionTicket.ticketID_FK = t_ticket.ticketID
WHERE t_ticket.supporterID_FK IN (SELECT supporterID
FROM t_Supporter
WHERE userID_FK = #userid))
SELECT *
FROM cte
WHERE rn = 1
You can write this logic using row_number() instead of additional nested queries:
SELECT t.ticketID, t.addedDate, t.question, t.code, t.priority,
ta.addedDateAction, ta.title AS Expr1
FROM t_Ticket t INNER JOIN
(SELECT ta.*,
ROW_NUMBER() OVER (PARTITION BY ta.ticketID_FK ORDER BY ta.addedDateAction DESC) as seqnum
FROM t_actionTicket ta
) ta
ON t.ticketId = ta.ticketId_FK and ta.seqnum = 1
WHERE t.supporterID_FK IN (SELECT supporterID
FROM t_Supporter
WHERE userID_FK = #userid
);
Note that table aliases make the query easier to write and to read.
Try this query
SELECT t_ticket.ticketID, t_ticket.addedDate, t_ticket.question,
t_ticket.code, t_ticket.priority, t_actionTicket.addedDateAction, t_actionTicket.title
FROM t_actionTicket
INNER JOIN t_ticket ON t_actionTicket.ticketID_FK = t_ticket.ticketID
INNER JOIN (SELECT ticketID_FK, MAX(addedDateAction) AS maxDate
FROM t_actionTicket AS t_actionTicket_1
WHERE (t_actionTicket_1.userID_FK <> #userid)
GROUP BY ticketID_FK) AS b ON t_actionTicket.ticketID_FK = b.ticketID_FK AND t_actionTicket.addedDateAction = b.maxDate
WHERE (t_ticket.supporterID_FK IN
(SELECT supporterID
FROM t_Supporter
WHERE (userID_FK = #userid)))

SQL - Sorting within an OVER clause

I'm able to perform the following operation in SQL:
SELECT ROW_NUMBER() OVER (ORDER BY c.SomeField2 ASC) AS r, c.cID
FROM
(
SELECT c.SomeField1, c.SomeField2, c.SomeField3, t.SomeField1Text, p.SomeField2Text
FROM MyTable c
JOIN #TempTable1 t ON c.SomeField1 = t.SomeField1
JOIN #TempTable2 p ON c.SomeField2 = p.SomeField2
) c
However, when I try sorting on a column from one of my temp tables like so…
SELECT ROW_NUMBER() OVER (ORDER BY p.SomeField2Text ASC) AS r, c.cID
FROM
(
SELECT c.SomeField1, c.SomeField2, c.SomeField3, t.SomeField1Text, p.SomeField2Text
FROM MyTable c
JOIN #TempTable1 t ON c.SomeField1 = t.SomeField1
JOIN #TempTable2 p ON c.SomeField2 = p.SomeField2
) c
… I get the following error:
The multi-part identifier "p.SomeFieldText2" could not be bound.
Do you know why I’m getting this error? I'm confused, since that column is in my SELECT clause.
The field you are querying is called SomeField2Text, not SomeFieldText2:
SELECT ROW_NUMBER() OVER (ORDER BY p.SomeField2Text ASC) AS r, c.cID
FROM
(
SELECT c.SomeField1, c.SomeField2, c.SomeField3, t.SomeField1Text, p.SomeField2Text
FROM MyTable c
JOIN #TempTable1 t ON c.SomeField1 = t.SomeField1
JOIN #TempTable2 p ON c.SomeField2 = p.SomeField2
) c
You should consider your subquery like a table with alias C.
That is why you need to order by c.SomeField2 column
SELECT ROW_NUMBER() OVER (ORDER BY c.SomeFieldText ASC) AS r, c.cID
FROM
(
SELECT c.SomeField1, c.SomeField2, c.SomeField3, t.SomeField1Text, p.SomeField2Text, p.SomeField2
FROM MyTable c
JOIN #TempTable1 t ON c.SomeField1 = t.SomeField1
JOIN #TempTable2 p ON c.SomeField2 = p.SomeField2
) c

Window function issue - max over partition

I try to rewrite such SQL statements (with many subqueries) to more efficient form using outer join and max/count/... over partition. Old statements:
select a.ID,
(select max(b.valA) from something b where a.ID = b.ID_T and b.status != 0),
(select max(b.valB) from something b where a.ID = b.ID_T and b.status != 0),
(select max(b.valC) from something b where a.ID = b.ID_T and b.status != 0),
(select max(b.valD) from something b where a.ID = b.ID_T)
from tool a;
What is important here - there is different condition for max(b.valD). Firstly I didn't noticed this difference and write something like this:
select distinct a.ID,
max(b.valA) over (partition by b.ID_T),
max(b.valB) over (partition by b.ID_T),
max(b.valC) over (partition by b.ID_T),
max(b.valD) over (partition by b.ID_T),
from tool a,
(select * from something
where status != 0) b
where a.ID = b.ID_T(+);
Could I use somewhere in max over partition this condition of b.status != 0 ? Or should I better add 3rd table to join like this:
select distinct a.ID,
max(b.valA) over (partition by b.ID_T),
max(b.valB) over (partition by b.ID_T),
max(b.valC) over (partition by b.ID_T),
max(c.valD) over (partition by c.ID_T),
from tool a,
(select * from something
where status != 0) b,
something c
where a.ID = b.ID_T(+)
and a.ID = c.ID_T(+);
The issue is with selecting and joining millions of rows, my example is just simplification of my query. Could anyone help me to achieve more efficient sql?
You could try to do this using CASE:
select a.ID,
max(CASE WHEN b.status=0 THEN b.valA END),
max(CASE WHEN b.status=0 THEN b.valB END),
max(CASE WHEN b.status=0 THEN b.valC END),
max(b.valD)
from tool a
left join something b ON( b.ID_T = a.ID )
group by a.ID;
Note that I replaced your implicit join by the "new" join-syntax for better readability.
One more way is to use JOIN and group by subquery:
select a.ID,
b.MAX_A,
b.MAX_B,
b.MAX_C,
b2.MAX_D
from tool a
LEFT JOIN
(
SELECT ID_T,max(valA) MAX_A, max(valB) MAX_B, max(valC) MAX_C
FROM something
WHERE status != 0
GROUP BY ID_T
) b
ON a.ID=b.ID_T
LEFT JOIN
(
SELECT ID_T, max(valD) MAX_D
FROM something
GROUP BY ID_T
) b2
ON a.ID=b2.ID_T

Select from Many-to-Many with GroupBy

I have three entities:
Cue(id, name)
Reaction(id, name)
Freqs(id, cue_id FK, reaction_id FK, some_other_data)
I want to count number of (cue, reaction) pairs like (cue.name, reaction.name, count)
I already wrote a query
SELECT
a.cue_id,
a.reaction_id,
Count(*) as freq
FROM
rdb_freqs a
JOIN rdb_reaction b ON a.cue_id=b.id
JOIN rdb_cue c ON a.reaction_id=c.id
GROUP BY a.cue_id, a.reaction_id
ORDER BY freq DESC;
But how should I replace 'id' with 'name'?
SELECT distinct
c.name cue_name,
b.name reaction_name,
(SELECT
Count(*)
FROM
rdb_freqs a1
where
a1.cue_id = a.cue_id and
a1.reaction_id = a.reaction_id
) as count
FROM
rdb_freqs a
inner JOIN rdb_reaction b ON a.reaction_id = b.id
inner JOIN rdb_cue c ON a.cue_id = c.id
order by count desc
SQLfiddle sample (written in oracle)
SELECT
c.name as cue_name,
b.name as reacion_name,
Count(*) as freq
FROM
rdb_freqs a
JOIN rdb_reaction b ON a.cue_id=b.id
JOIN rdb_cue c ON a.reaction_id=c.id
GROUP BY c.name, b.name
ORDER BY freq DESC;
SELECT
FROM rdb_freq f
INNER JOIN (
SELECT
a.cue_id,
a.reaction_id,
Count(*) as freq
FROM
rdb_freqs a
JOIN rdb_reaction b ON a.cue_id=b.id
JOIN rdb_cue c ON a.reaction_id=c.id
GROUP BY a.cue_id, a.reaction_id
) AS tot ON f.cue_id = tot.cue_id
INNER JOIN reaction

Using MAX for date but adding column to group on 'breaks' the query - sub query?

I Have a table which holds date but I need to know the latest date where a condition is true per location, only issue is once I add a column called 'notes' it breaks the query and returns too many rows, current query is ...
SELECT
Location,
MAX(date) AS date,
type,
notes
FROM NotesTable a
INNER JOIN Location b on a.LocationID = b.LocationID
INNER JOIN Type c on a.typeid = c.typeid
WHERE typeid <> 8
GROUP BY Location, type, notes
If I comment out the notes column then it works fine but as soon as I add that to the grouping it then returns more rows than required.
Have tried using a subquery but still cant get it working, subquery below
SELECT
r.location,
r.date,
r.type,
t.notes
FROM (SELECT Location, MAX(date), type
FROM NotesTable a INNER JOIN Location b on a.LocationID = b.LocationID
INNER JOIN Type c on a.typeid = c.typeid
WHERE typeid <> 8
GROUP BY location,type
) r
INNER JOIN NotesTable t ON t.date = r.date
Anyone got any other suggestions?
select * from
(
SELECT Location,Date, Type, Notes, Row_Number() Over (Partition By Location, Type order by date desc) RN
FROM
NotesTable a
INNER JOIN Location b on a.LocationID = b.LocationID
INNER JOIN Type c on a.typeid = c.typeid
WHERE typeid <> 8
) v
WHERE rn = 1
Your query is almost correct, you need to add this additional condition in ON clause
AND
t.location = r.location AND
t.type = r.type
full query,
SELECT r.location
, r.DATE
, r.type
, t.notes
FROM (
SELECT Location
, MAX(DATE) maxDate
, type
FROM NotesTable a
INNER JOIN Location b
ON a.LocationID = b.LocationID
INNER JOIN Type c
ON a.typeid = c.typeid
WHERE typeid <> 8
GROUP BY location
, type
) r
INNER JOIN NotesTable t
ON t.DATE = r.maxDate AND
t.location = r.location AND
t.type = r.type