SQL - Sorting within an OVER clause - sql

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

Related

Performing a JOIN with the results of a WITH clause

I have one query that uses one join already, call it query1. I would like to join query1 to the results of a WITH clause. I don't know how to merge the two data sets.
Query 1:
SELECT
p.NetObjectID
, n.Caption, n.ObjectSubType
FROM Pollers p
LEFT JOIN NodesData n ON n.NodeID = p.NetObjectID
The next query is a WITH clause. I don't know how to obtain the results without a WITH because I need to do what is outlined in this post.
Query 2:
WITH ranked_DateStamp AS
(
SELECT c.NodeID, c.DateTime
, ROW_NUMBER() OVER (PARTITION BY NodeID ORDER BY DateTime DESC) AS rn
FROM CPULoad AS c
)
SELECT *
FROM ranked_DateStamp
WHERE rn = 1;
I thought I could just JOIN ranked_DateStamp ON ranked_DateStamp.NodeID = p.NodeID but it won't allow it.
You don't really need a with clause here, you can use a subquery. I would just phrase this as:
SELECT
p.NetObjectID,
n.Caption,
n.ObjectSubType,
c.DateTime
FROM Pollers p
LEFT JOIN NodesData n ON n.NodeID = p.NetObjectID
LEFT JOIN (
SELECT
NodeID,
DateTime,
ROW_NUMBER() OVER (PARTITION BY NodeID ORDER BY DateTime DESC) AS rn
FROM CPULoad AS c
) c ON c.rn = 1 and c.NodeID = p.NetObjectID
However, if you were to use a common table expression, that would look like:
WITH ranked_DateStamp AS (
SELECT
NodeID,
DateTime,
ROW_NUMBER() OVER (PARTITION BY NodeID ORDER BY DateTime DESC) AS rn
FROM CPULoad AS c
)
SELECT
p.NetObjectID,
n.Caption,
n.ObjectSubType,
c.DateTime
FROM Pollers p
LEFT JOIN NodesData n ON n.NodeID = p.NetObjectID
LEFT JOIN ranked_DateStamp c ON c.rn = 1 and c.NodeID = p.NetObjectID
Actually, a lateral join might perform equally well, or better:
SELECT
p.NetObjectID,
n.Caption,
n.ObjectSubType,
c.DateTime
FROM Pollers p
LEFT JOIN NodesData n ON n.NodeID = p.NetObjectID
OUTER APPLY (SELECT TOP (1) * FROM CPULOad c WHERE c.NodeID = p.NetObjectID ORDER BY DateTime DESC) c
Actually, I would suggest a different approach -- a lateral join:
SELECT p.NetObjectID, n.Caption, n.ObjectSubType,c.DateTime
FROM Pollers p LEFT JOIN
NodesData n
ON n.NodeID = p.NetObjectID OUTER APPLY
(SELECT TOP (1) NodeID, DateTime,
ROW_NUMBER() OVER (PARTITION BY NodeID ORDER BY DateTime DESC) AS rn
FROM CPULoad c
WHERE c.NodeId = p.NetObjectID
ORDER BY DateTime DESC
) c;
Lateral joins are very powerful and worth learning about. They are also often a bit faster than the ROW_NUMBER() approach.

What will be the query for this?

JOIN public.match m ON (s.stadium_id = m.stadium_id)
group
AS (
)
SELECT round_number
,stadium_name
,spectators
FROM (
SELECT round_number
,stadium_name
,spectators
,RANK() OVER (
PARTITION BY round_number ORDER BY spectators DESC
) AS rank1
FROM t1
) AS s1
WHERE rank1 = 1
<br>
Any smaller query than this?
I think you can just use window functions:
select ms.*
from (select m.round_number, s.stadium_name, m.no_spectators,
row_number() over (partition by m.round_number order by m.no_spectators desc) as seqnum
from public.stadium s join
public.match m
on s.stadium_id = m.stadium_id
) ms
where seqnum = 1
order by m.round_number;
I don't see why aggregation would be needed for the inner query.
You can use a subquery to get the max first
select m.round_number, s.stadium_name, MaxSpec
from public.stadium s
JOIN public.match m ON (s.stadium_id = m.stadium_id)
JOIN
(
select m.round_number, MAX(m.no_spectators) as MaxSpec
from public.stadium s
JOIN public.match m ON (s.stadium_id = m.stadium_id)
group by m.round_number
)a on m.no_spectators = a.MaxSpec
Just one more way to skin this cat. Throw your MAX(no_spectators) into a WHERE clause.
SELECT
m.round_number,
s.stadium_name,
m.no_spectators
FROM
PUBLIC.stadium s
JOIN
PUBLIC.match m
ON s.stadium_id = m.stadium_id
WHERE
m.no_spectators = (SELECT MAX(no_spectators) FROM PUBLIC.match);
That should do for an intro class.

TSQL Subquery in from

I am attempting to do a subquery which should work but I am missing something in the syntex.
I am trying:
select *
from (select * from (select *, row_number() over (partition by number,system order by number,system) as rc from [dbo].[info]) tk0 where tk0.rc =1) tkt
inner join [dbo].[QUEUES] pq
on pq.[QUEUE_NAME] = tkt.[QueueName] inner join [dbo].PLATFORMS] pl
on pl.id = pq.platform_id
and I get incorrect syntax near inner.
This works:
select *, row_number() over (partition by number,system order by number,system) as rc from [dbo].[info]) tk0 where tk0.rc =1
just missing a [ in platforms line .The below should work:
select *
from
(
select *
from
(
select
*, row_number() over (partition by number,system order by number,system) as rc
from [dbo].[info]
) tk0
where tk0.rc =1
) tkt
inner join [dbo].[QUEUES] pq
on pq.[QUEUE_NAME] = tkt.[QueueName]
inner join [dbo].[PLATFORMS] pl --correction done here
on pl.id = pq.platform_id
also you can write your where clause in join too:
select *
from
(
select
*, row_number() over (partition by number,system order by number,system) as rc
from [dbo].[info]
) tkt
inner join [dbo].[QUEUES] pq
on pq.[QUEUE_NAME] = tkt.[QueueName] and tkt.rc =1
inner join [dbo].[PLATFORMS] pl
on pl.id = pq.platform_id

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)))

Join Using Maximum Date

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