REtrieveing the atest record in oracle using rank/ group by - sql

I have the following Query which is giving me the results i have attached with this post. I want to bring only the records where most recent status is updated. Please note that there is no date column to identify the updated status. The only way we can so it is group by (IDK,IDFK,STATUS). Please note that one CODE can be updated number of times. I want to get the most latest status updated (so basically for every code for every status update the max IDFK) . so from the below screen shots i should get three records (i.e. wehre IDFK is 1418853,1418939,1419017)
NOTE: IDK and IDFK may/may not be in sorted order.
SELECT ID.ISS_CD CODE,
IF.ISS_DIM_KY IDK,
IF.LOAD_TS,
IE.ISS_FACT_DIM_KY IFDK,
IE.SUSPN_STS
FROM ccm_mi_rds_owner.iss_fact if
INNER JOIN ccm_mi_rds_owner.iss_dim id ON (IF.ISS_DIM_KY = ID.ISS_DIM_KY)
LEFT OUTER JOIN ccm_mi_rds_owner.iss_fact_ext ie ON (IF.ISS_FACT_DIM_KY = IE.ISS_FACT_DIM_KY)
WHERE IF.SRC_DIM_KY = 20
and IE.SUSPN_STS is not null
and iss_cd in ('C0000182087' , 'C0000182142','C0000182999')``

Oracle's analytical functions are a good fit for this.
Try the below:
select
*
from
(
SELECT ID.ISS_CD CODE,
IF.ISS_DIM_KY IDK,
IF.LOAD_TS,
IE.ISS_FACT_DIM_KY IFDK,
IE.SUSPN_STS,
row_number() over (partition by idk order by idfk desc ) as rn
FROM ccm_mi_rds_owner.iss_fact if
INNER JOIN ccm_mi_rds_owner.iss_dim id ON (IF.ISS_DIM_KY = ID.ISS_DIM_KY)
LEFT OUTER JOIN ccm_mi_rds_owner.iss_fact_ext ie ON (IF.ISS_FACT_DIM_KY = IE.ISS_FACT_DIM_KY)
WHERE IF.SRC_DIM_KY = 20
and IE.SUSPN_STS is not null
and iss_cd in ('C0000182087' , 'C0000182142','C0000182999')
)
where
rn = 1

Related

SQL Selecting data from 3 tables using GROUP BY

I am trying to write a formula to pull data from 3 tables and struggling to get it working.
I need to use the InventoryNbr from table s and do a group by, because there is many of the same InventoryNbr's, and I just want the MAX IndexListID Returned. The IndexListID is a Unique Key, so when I search on table il, I should only return 1 row. I want to then pull the end year from that row as well as the modelnm, and use those 2 values to get the CarlineNm. Here is my code:
SELECT s.InventoryNbr, MAX(s.IndexListID) AS IndexListID, il.EndYear, c.CarlineNm
FROM sysidla as s
INNER JOIN IndexList as il
ON s.IndexListID = il.IndexListID
INNER JOIN Carline as c
ON il.EndYear = c.CarlineYear
AND il.ModelNm = c.ModelNm
GROUP BY InventoryNbr
ORDER BY InventoryNbr ASC;
The error I keep getting is:
Column 'IndexList.EndYear' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
Here is some sample data:
sysidla
InventoryNbr|IndexListID|Junk|Junk2
12345|1|x|y
12345|2|c|r
12345|3|c|e
12346|4|e|w
IndexList
ModelNm|Junk|Junk1|Junk3|EndYear|IndexListID
name1|c|f|r|2004|1
name2|c|f|r|2008|2
name3|c|f|r|2012|3
name4|c|f|r|2004|4
name5|c|f|r|2018|5
Carline
CarlineYear|CarlineNm|Junk9|ModelNm
2005|NAME|d|name1
2012|NAME22|d|name3
2005|NAME354|d|name4
2005|NAME1|d|name5
So for instance, this is an incomplete data sample because every IndexListID will have a match in IndexList, but I want to be able match InventoryNbr 12345 and select the max INDEXLISTID which is 3, then use 3 on IndexList to grab name3 and 2012. Then I want to use 2012 and name3 to get NAME22 From Carine.
Use window functions in a subquery:
SELECT s.InventoryNbr, s.IndexListID, il.EndYear, c.CarlineNm
FROM (SELECT s.*,
ROW_NUMBER() OVER (PARTITION BY il.IndexListID ORDER BY il.IndexListID DESC) as seqnum
FROM sysidla s
) s INNER JOIN
IndexList il
ON s.IndexListID = il.IndexListID INNER JOIN
Carline c
ON il.EndYear = c.CarlineYear AND
il.ModelNm = c.ModelNm
WHERE seqnum = 1
ORDER BY InventoryNbr ASC;
No aggregation is needed.
Your are getting this error because, there is a problem with your group by and SELECT section . You can not select column while using group by like this. Either you have to use an aggregate function or your column should in the group by to select like this.
So,Here is a solution you can check =>
SELECT T.*,il.EndYear, c.CarlineNm FROM
(SELECT s.InventoryNbr, MAX(s.IndexListID) AS IndexListID
FROM sysidla as s
GROUP BY InventoryNbr) T
INNER JOIN IndexList as il ON T.IndexListID = il.IndexListID
INNER JOIN Carline as c ON il.EndYear = c.CarlineYear AND il.ModelNm = c.ModelNm
ORDER BY T.InventoryNbr ASC;
Note: This code is not optimized. Sub-query is little slow however, you can optimize that using window function (CTE). Please check and let me know.

SQL Most Recent Register FROM Second Table by Id

I have 2 tables (Opportunity and Stage). I need to get each opportunity with the most recent stage by StageTypeId.
Opportunity: Id, etc
Stage: Id, CreatedOn, OpportunityId, StageTypeId.
Let's suppose I have "opportunity1" and "opportunity2" each one with many Stages added.
By passing the StageTypeId I need to get the opportunity which has this StageTypeId as most recent.
I'm trying the following query but it´s replicating the same Stage for all the Opportunities.
It seems that it's ignoring this line: "AND {Stage}.[OpportunityId] = ID"
SELECT {Opportunity}.[Id] ID,
{Opportunity}.[Name],
{Opportunity}.[PotentialAmount],
{Contact}.[FirstName],
{Contact}.[LastName],
(SELECT * FROM
(
SELECT {Stage}.[StageTypeId]
FROM {Stage}
WHERE {Stage}.[StageTypeId] = #StageTypeId
AND {Stage}.[OpportunityId] = ID
ORDER BY {Stage}.[CreatedOn] DESC
)
WHERE ROWNUM = 1) AS StageTypeId
FROM {Opportunity}
LEFT JOIN {Contact}
ON {Opportunity}.[ContactId] = {Contact}.[Id]
Thank you
Most of DBMS support fetch first clause So, you can do :
select o.*
from Opportunity o
where o.StageTypeId = (select s.StageTypeId
from Stage s
where s.OpportunityId = o.id
order by s.CreatedOn desc
fetch first 1 rows only
);
you can try below way all dbms will support
select TT*. ,o*. from
(
select s1.OpportunityId,t.StageTypeId from Stage s1 inner join
(select StageTypeId,max(CreatedOn) as createdate Stage s
group by StageTypeId
) t
on s1.StageTypeId=t.StageTypeId and s1.CreatedOn=t.createdate
) as TT inner join Opportunity o on TT.OpportunityId=o.id

Update JOINED Table with Most Recent Date

So I'm stumped. I have two tables I'm joining together and updating one of them. Now, I want to update it with the MOST RECENT record of data.
So I want this to occur first (this ordering):
select * from APUL
order by UIMth desc
Followed by this update:
UPDATE APUI
SET APUI.udTempReviewer = APUL.ReviewerGroup
FROM APUI
INNER JOIN APUL ON APUI.UISeq = APUL.UISeq
AND APUI.APCo = APUL.APCo
So basically I want to update table APUI with the most recent record from APUL, as APUL is an invoice record table.
use Row_Number window function
;WITH CTE
AS (SELECT Row_number() OVER(partition BY uiseq, apco ORDER BY uimth DESC ) AS rn,
reviewergroup,
uiseq,
apco
FROM apul)
UPDATE A
SET A.udtempreviewer = L.reviewergroup
FROM apui A
INNER JOIN CTE L
ON A.uiseq = L.uiseq
AND A.apco = L.apco
Where L.Rn = 1

How to speed up a slow update query in SQL Server 2012

I have an update query that works fine, but it is way too slow and takes over 2 minutes to complete. Is there another way I can write this query to speed it up? Here is my code thanks:
UPDATE #tmpIMDS
SET
ModelFileName = b.ModelFileName,
SendEMail = b.SendEMail
FROM
(
SELECT DISTINCT
IMDSConversionReportData.ModelNumber,
ModelFileName,
'Send Email' AS SendEmail
FROM
IMDSConversionReportData,
(
SELECT DISTINCT
ModelNumber,
Max(DateAdded) AS DateAdded
FROM
IMDSConversionReportData
GROUP BY
ModelNumber) a
WHERE
IMDSConversionReportData.ModelNumber = a.ModelNumber
AND IMDSConversionReportData.DateAdded = a.DateAdded
) b
WHERE ModelID = b.ModelNumber
Instead of hitting IMDSConversionReportData table twice to get the maximum DateAdded per ModelNumber you can generate row_number to identify maximum DateAdded per ModelNumbercolumn.
Also remove distinct when you are selecting only one non aggregate column with group by which is meaningless
Try this
;WITH cte
AS (SELECT *,
'Send Email' AS SendEmail,
Row_number()OVER(partition BY ModelNumber ORDER BY DateAdded DESC) AS rn
FROM IMDSConversionReportData)
UPDATE t
SET ModelFileName = c.ModelFileName,
SendEMail = c.SendEMail
FROM #tmpIMDS t
INNER JOIN cte c
ON t.ModelID = c.ModelNumber
Where Rn = 1
Note : Always use proper INNER JOIN syntax to join two tables instead of Old style comma separated join. We always find INNER Join syntax is more readable. Keep the filters alone in Where clause

How to increment a column based on two tables that are joined

I am trying to increment a column on a sql server table based on the join between the initial table and the joined table. The idea is to update tblForm10Objectives, set the ObjectiveNumber column to an increment number starting with 1 based on the number of rows returned from the join of tblForm10GoalsObjectives and tblForm10Objectives where ID_Form10Goal equals a number. Example query so far:
Update tblForm10Objectives
Set ObjectiveNumber = rn
From (
Select ROW_NUMBER() over (PARTITION by OG.ID_Form10Goal) as rn
, *
From (
Select *
From tblForm10GoalsObjectives OG
Join tblForm10Objectives O On OG.ID_Form10Objective = O.ID_Form10Objective
Where OG.ID_Form10Goal = 4
Order by O.ID_Form10Objective
) as tblForm10Objectives;
If the select portion of the query is performed the columns are displayed so you can see the ObjectiveNumber is currently 0 where ID_Form10Goal = 4
Once the update runs I need for the ObjectiveNumber to show 1 , 2; since there are two rows for ID_Form10Goal = 4.
I had to introduce a new table to the logic of this update statement, the table name is tblForm10Goals. The objectives need to be pulled by ID_Agency instead of ID_Form10Goal I am getting an error message stating a "a multipart identifier 'dbo.tblForm10Objectives.ID_Form10Objective = rns.ID_Form10Objective' could not be bound. I am using the following SQL Update statement:
UPDATE dbo.tblForm10Objectives
SET ObjectiveNumber = rn
FROM tblForm10Goals As g
Left Join tblForm10GoalsObjectives gobs ON g.ID_Form10Goal = gobs.ID_Form10Goal
Right Join
(
SELECT
ROW_NUMBER() OVER (PARTITION BY g.ID_Agency
ORDER BY OB.ID_Form10Objective) AS rn,
OB.ID_Form10Objective
FROM tblForm10Goals g
LEFT JOIN dbo.tblForm10GoalsObjectives gobs ON g.ID_Form10Goal = gobs.ID_Form10Goal
RIGHT JOIN dbo.tblForm10Objectives OB ON gobs.ID_Form10Objective = OB.ID_Form10Objective
Where g.ID_Agency = 2
) rns ON dbo.tblForm10Objectives.ID_Form10Object = rns.ID_Form10Objective
Your example seems to be missing a closing parenthesis somewhere, and without the table structures to look at, I can't be certain of my answer. It seems you have two tables:
tblForm10Objectives
-------------------
ID_Form10Objective
ObjectiveNumber
...
and
tblForm10GoalsObjectives
------------------------
ID_Form10Goal
ID_Form10Objective
...
If this is the case, the following query should give you the results you desire:
UPDATE dbo.tblForm10Objectives
SET ObjectiveNumber = rn
FROM dbo.tblForm10Objectives INNER JOIN
(
SELECT
ROW_NUMBER() OVER (PARTITION BY OG.ID_Form10Goal
ORDER BY O.ID_Form10Objective) AS rn,
O.ID_Form10Objective
FROM dbo.tblForm10Objectives O INNER JOIN
dbo.tblForm10GoalsObjectives OG ON OG.ID_Form10Objective = O.ID_Form10Objective
Where OG.ID_Form10Goal = 4
) rns ON dbo.tblForm10Objectives.ID_Form10Objective = rns.ID_Form10Objective
If you run the inner SELECT statement, you will see the desired ObjectiveNumber values and the corresponding ID_Form10Objective that will get updated with those values.
If you post your table structures, I or someone else may be able to be of more help.