How do I JOIN another table to this code in SQL? - sql

I need to JOIN a table named IB to the code below. I need to pull in the following fields from IB: QOO, QOH, QCM and AVG. The JOIN conditions are IJ.IJITEM = IB.IBITEM and IJ.IJLOC = IB.IBLOC
;WITH cte AS
(
SELECT IJLOC, IJITEM, IJDATE, IJLCGT,
rn = ROW_NUMBER() OVER (PARTITION BY IJITEM, IJLOC ORDER BY IJDATE DESC)
FROM dbo.IJ
)
SELECT IJLOC, IJITEM, IJDATE, IJLCGT
FROM cte WHERE rn = 1;

One method, which allows for a little more complexity than just JOINing the IB table to "cte" in your final SELECT is to nest another CTE using the current one as the table. For example:
;WITH cte AS
(
SELECT IJLOC, IJITEM, IJDATE, IJLCGT,
rn = ROW_NUMBER() OVER (PARTITION BY IJITEM, IJLOC ORDER BY IJDATE DESC)
FROM dbo.IJ
),
filtered AS (
SELECT IJLOC, IJITEM, IJDATE, IJLCGT
FROM cte
WHERE rn = 1
)
SELECT ib.QOO, ib.QOH, ib.QCM, ib.[AVG]
FROM ib
INNER JOIN filtered
ON filtered.IJITEM = IB.IBITEM
AND filtered.IJLOC = IB.IBLOC
Another option, depending on how the query optimizer handles the JOINs between all the tables, and if you don't need to return any of the fields from the IJ table, is to insert the results of your CTE into a temp table and then JOIN to that. For example:
CREATE TABLE #Temp (IJITEM DataType, IJLOC DataType)
;WITH cte AS
(
SELECT IJLOC, IJITEM, IJDATE, IJLCGT,
rn = ROW_NUMBER() OVER (PARTITION BY IJITEM, IJLOC ORDER BY IJDATE DESC)
FROM dbo.IJ
)
INSERT INTO #Temp (IJITEM, IJLOC)
SELECT IJITEM, IJLOC
FROM cte
WHERE rn = 1;
SELECT ib.QOO, ib.QOH, ib.QCM, ib.[AVG]
FROM ib
INNER JOIN #Temp tmp
ON tmp.IJITEM = IB.IBITEM
AND tmp.IJLOC = IB.IBLOC

;
WITH cte
AS ( SELECT IJLOC ,
IJITEM ,
IJDATE ,
IJLCGT ,
rn = ROW_NUMBER() OVER ( PARTITION BY IJITEM, IJLOC ORDER BY IJDATE DESC )
FROM dbo.IJ
)
SELECT IJLOC ,
IJITEM ,
IJDATE ,
IJLCGT ,
IB.QOO ,
IB.QOH ,
IB.QCM ,
IB.[AVG]
FROM cte
INNER JOIN IB ON cte.IJITEM = IB.IBITEM
AND cte.IJLOC = IB.IBLOC
WHERE cte.rn = 1 ;

Related

Results of a CTE inside a subquery and row_number with a couple order by

I have a query that runs as follows:
WITH teste1 as (
SELECT
CONCAT(a.pid, a.num_ordenado) as id_despacho,
a.pid,
a.created_at,
a.nota,
a.from_id,
a.from_nome
FROM (
SELECT pid, id,
(ROW_NUMBER() over (partition by pid order by created_at)) as num_ordenado,
from_id, from_nome, nota, created_at
FROM mytable_a) as a
),
teste2 as (
SELECT
CONCAT(t.pid, t.ordenado) as id_despacho,
t.ordenado,
t.pid as id_doc,
t.data as diahora,
CONCAT
(
'Evento: ', t.evento
) as conteudo2,
'' as pasta,
t.from_id,
t.from_nome,
t.to_id,
t.to_nome
FROM
(
SELECT pid, data,
(ROW_NUMBER() over (partition by pid order by data)) as ordenado,
from_id, from_nome, to_id, to_nome, evento
FROM mytable_t) as t
)
SELECT *
FROM teste2 as t2
LEFT JOIN teste1 as t1
ON t2.id_despacho = t1.id_despacho
WHERE t2.conteudo2 <> 'Evento: Campo bloqueado' AND t2.conteudo2 <> 'Evento: Campo desbloqueado'
In each CTE, I order the ID's by datetime and then create a new ID structure on which I join by that new ID at the last query. I'm wondering how could I do to now order them again by datetime.
My questions then would be:
Can I use the results of a CTE (teste1 and teste2 tables) inside a subquery? Something like this (not working)
SELECT
t2.id_despacho,
t2.id_doc,
t2.diahora,
t2.conteudo2,
t1.id_despacho,
t1.created_at,
t1.nota,
(ROW_NUMBER() OVER (PARTITION BY id_doc ORDER BY diahora, created_at)) AS ordenado_final
FROM
(SELECT *
FROM teste2 AS t2
LEFT JOIN teste1 AS t1 ON t2.id_despacho = t1.id_despacho
WHERE t2.conteudo2 <> 'Evento: Campo bloqueado'
AND t2.conteudo2 <> 'Evento: Campo desbloqueado')
Does that ROW_NUMBER() work like that? Can I order by two different columns?
(ROW_NUMBER() OVER (PARTITION BY id_doc
ORDER BY diahora, created_at)) AS ordenado_final

Compare Column A of Row 1 with Column B of Row 2 in Same table

I have a table name 'Table A' where I need to get the all values based on two columns 'AdviserBusinessId' and 'ClientcontactGuid' having count > 1. I am able to achieve this using self join as below query.
select gc.AdviserBusinessId,gc.ClientContactGuid,gc.PlanStartDate,gc.PlanEndDate,gc.ClientEngagementGuid, gc.RenewalGuid,
ROW_NUMBER() over(partition by gc.adviserbusinessid,gc.clientcontactguid order by gc.planenddate asc) as rownum from GENIUS_ClientEngagement gc
inner join(
select AdviserBusinessId,ClientContactGuid from GENIUS_ClientEngagement
group by AdviserBusinessId,ClientContactGuid having count(*) > 1) B
on gc.AdviserBusinessId = b.AdviserBusinessId and gc.ClientContactGuid = b.ClientContactGuid
And this is what the table looks like:
[![enter image description here][1]][1]
Now my main point is that, I want to compare PlanEndDate of row 1 with PlanStartDate of row 2 and get the rows if PlanEndDate > PlanStartDate. Let's take an example of above two rows, if suppose the planstartdate was < planenddate then I just want to populate those above two rows.
Will cursor or loop be helpful in this ?
Thanks in advance. Any suggestions will be appreciated.
Use analytic functions:
SELECT AdviserBusinessId,
ClientContactGuid,
PlanStartDate,
PlanEndDate,
ClientEngagementGuid,
RenewalGuid,
rn
FROM (
SELECT AdviserBusinessId,
ClientContactGuid,
PlanStartDate,
PlanEndDate,
ClientEngagementGuid,
RenewalGuid,
ROW_NUMBER() OVER (
PARTITION BY adviserbusinessid, clientcontactguid
ORDER BY planEndDate asc
) AS rn,
COUNT(*) OVER (
partition by adviserbusinessid, clientcontactguid
) AS num_rows,
LEAD(planStartDate) OVER (
PARTITION BY adviserbusinessid, clientcontactguid
ORDER BY planEndDate asc
) AS next_start,
LAG(planEndDate) OVER (
PARTITION BY adviserbusinessid, clientcontactguid
ORDER BY planEndDate asc
) AS prev_end
FROM GENIUS_ClientEngagement
) gce
WHERE num_rows > 1
AND ( (rn = 1 AND planEndDate > next_start)
OR (rn = 2 AND prev_end > planStartDate) )
You can use self join to achieve this. Something like this:
SELECT * FROM TableA A
LEFT JOIN TableA B ON A.ClientContactGuid = B.ClientContactGuid AND (A.RowNum+1) = B.RowNum
WHERE A.PlanEndDate>B.PlanStartDate OR B.PlanStartDate IS NULL
This was what I wanted, thanks to #MTO for the direction.
with cte
as(
select gc.AdviserBusinessId,gc.ClientContactGuid,gc.PlanStartDate,gc.PlanEndDate,gc.ClientEngagementGuid, gc.RenewalGuid,
ROW_NUMBER() over(partition by gc.adviserbusinessid,gc.clientcontactguid order by planenddate desc) as rownum
from GENIUS_ClientEngagement gc
inner join(
select AdviserBusinessId,ClientContactGuid from GENIUS_ClientEngagement
group by AdviserBusinessId,ClientContactGuid having count(*) > 1
) B
on gc.AdviserBusinessId = b.AdviserBusinessId and gc.ClientContactGuid = b.ClientContactGuid
)
select *,ROW_NUMBER() over(partition by adviserbusinessid,clientcontactguid order by planenddate asc) as rn,
LEAD(PlanStartDate) OVER (
PARTITION BY adviserbusinessid, clientcontactguid
ORDER BY planEndDate asc
) AS next_start,
LAG(planEndDate) OVER (
PARTITION BY adviserbusinessid, clientcontactguid
ORDER BY planEndDate asc
) AS prev_ends into #temp2 from cte
where rownum <=2
select AdviserBusinessId,ClientContactGuid,PlanStartDate,PlanEndDate,ClientEngagementGuid,RenewalGuid from #temp2 where
( (rn = 1 AND planEndDate > next_start)
OR (rn = 2 AND prev_ends > planStartDate) )
drop table #temp2

Records apart form max date

I have been helped by Metal to write a SQL as below
select id
, OrderDate
, RejectDate
, max(case when RejectDate = '1900-01-01' then '9999-12-31' else RejectDate end) as rSum
from tableA
group by id, OrderDate, RejectDate
Now, I would like to find out all the records for a partcular id below the max reject date to delete them from a transformation table
An option is to use row_number():
select
id,
OrderDate,
RejectDate
from (
select
t.*,
row_number() over(
partition by id
order by case when RejectDate = '1900-01-01' then '9999-12-31' else RejectDate end desc
) rn
from tableA t
) t
where rn > 1
The advantage of this technique is that it avoids aggregation, which may lead to better performance. Also, you can easily turn this into a delete statement by leveraging the concept of updateable CTE, as follows:
with cte as (
select
row_number() over(
partition by id
order by case when RejectDate = '1900-01-01' then '9999-12-31' else RejectDate end desc
) rn
from tableA t
)
delete from cte where rn > 1
This should work...
SELECT *
FROM tableA t1
INNER JOIN (
SELECT ID, MAX(RejectDate) as MaxRejectDate
FROM tableA) t2 ON t1.ID = t2.ID
WHERE t1.RejectDate < t2.MaxRejectDate

ORA-00933: SQL command not properly ended on Table Alias

Having issues getting this to work. Each query works individually however when I try to alias each Subquery to work the Join I get the error:
SQL Command not properly ended. Any suggestions would be extremely appreciated.
Select C.*
From
(
(
Select
a.*,
Row_Number() Over(Partition By referral_id Order By start_date,line) as rn
from hcclsc.referral_Bed_Day a
) A
Inner Join (
Select
a.referral_id,
max(rn) as vn
From (
Select
referral_id,
line,
bed_day_type_id,
start_date,
end_date,
Row_Number() Over(Partition by referral_id Order By start_date, line) as rn
From HCCLSC.referral_Bed_Day
) a
Group by referral_id
) B
On A.referral_ID = B.referral_id and a.rn = b.vn
) C
You're joining A to B, but then not selecting a anything from those joined subqueries.
This part:
Select C.*
From
(
(
would need to specify columns to select from the join; if you want all of them from both subqueries then:
Select C.*
From
(
Select *
From
(
but then that extra level of subquery isn't really adding anything, and you can remove the C level:
Select *
From
(
Select
a.*,
Row_Number() Over(Partition By referral_id Order By start_date,line) as rn
from hcclsc.referral_Bed_Day a
) A
Inner Join (
Select
a.referral_id,
max(rn) as vn
From (
Select
referral_id,
line,
bed_day_type_id,
start_date,
end_date,
Row_Number() Over(Partition by referral_id Order By start_date, line) as rn
From HCCLSC.referral_Bed_Day
) a
Group by referral_id
) B
On A.referral_ID = B.referral_id and a.rn = b.vn
try like below by using cte
with cte as
(
Select
a.referral_id
max(rn) as vn
From
(Select
referral_id
,line
,bed_day_type_id
,start_date
,end_date
,Row_Number() Over(Partition by referral_id Order By start_date, line) as rn
From
HCCLSC.referral_Bed_Day
) a Group by referral_id
), cte2 as
(
Select
a.*
,Row_Number() Over(Partition By referral_id Order By start_date,line) as rn
from
hcclsc.referral_Bed_Day a
) select A.*,B.* from cte A join cte2 B
on A.referral_ID = B.referral_id and A.vn= B.rn

Oracle: select values only from row with min(id)

SELECT
ass.assessmentAmount -- want to fetch assessmentAmount of min(ass.assessmentId)
ass.assessmentId
FROM
--bunch of joins
WHERE
ass.assessmentId = (SELECT min(ass2.assessmentId) FROM Assessment ass2
--same bunch of joins
It looks very confusing because I have 6 joins with conditions and I don't want to repeat it two times. Is there another way of doing this?
Use the MIN( ass.assessmentId ) OVER () analytic function:
SELECT *
FROM (
SELECT ass.assessmentAmount,
ass.assessmentId,
MIN( ass.assessmentId ) OVER () AS min_assessmentId
FROM --bunch of joins
)
WHERE assessmentId = min_assessmentId;
You can also use RANK():
SELECT *
FROM (
SELECT ass.assessmentAmount,
ass.assessmentId,
RANK() OVER ( ORDER BY ass.assessmentId ) AS rnk
FROM --bunch of joins
)
WHERE rnk = 1;
If assessmentId is UNIQUE and can only have a single row as a minimum then you could replace RANK with ROW_NUMBER; however, you could also then get the desired result using the ROWNUM pseudocolumn:
SELECT *
FROM (
SELECT ass.assessmentAmount,
ass.assessmentId
FROM --bunch of joins
ORDER BY ass.assessmentId ASC
)
WHERE ROWNUM = 1;
Use a CTE with a row_number
with CTE as
(
select assessmentId,
assessmentAmount ,
row_number() over (order by assessmentid asc) as rn
from --bunch of joins
)
select *
from CTE
where rn = 1