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

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

Related

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

Creating column and filtering it in one select statement

Wondering if it is possible to creating a new column and filter on that column. The following is an example:
SELECT row_number() over (partition by ID order by date asc) row# FROM table1 where row# = 1
Thanks!
Some databases support a QUALIFY clause which you might be able to use:
SELECT *
FROM table1
QUALIFY ROW_NUMBER() OVER (PARTITION BY ID ORDER BY date) = 1;
On SQL Server, you may use a TOP 1 WITH TIES trick:
SELECT TOP 1 WITH TIES *
FROM table1
ORDER BY ROW_NUMBER() OVER (PARTITION BY ID ORDER BY date);
More generally, you would have to use a subquery:
WITH cte AS (
SELECT t.*, ROW_NUMBER() OVER (PARTITION BY ID ORDER BY date) rn
FROM table1 t
)
SELECT *
FROM cte
WHERE rn = 1;
The WHERE clause is evaluated before the SELECT so your column has to exist before you can use a WHERE clause. You could achieve this by making a subquery of the original query.
SELECT *
FROM
(
SELECT row_number() over (partition by ID order by date asc) row#
FROM table1
) a
WHERE a.row# = 1

How to remove duplicate rows using CTE?

I would like to remove duplicate rows from my table. So that I have used ROW_NUMBER() function in order to find the duplicate values. After that I wanted to add WHERE claues to my query and so that I modify my query and used "CTE" but it gives me an error
ORA-00928: missing SELECT keyword
This is the query which runs successfully for my use case :
WITH RowNumCTE as
(
SELECT ID,parcelid,propertyaddress,saledate,saleprice,legalreference,
ROW_NUMBER() OVER
( PARTITION BY parcelid,propertyaddress,saledate,saleprice,legalreference
ORDER BY id ) AS rn
FROM housedata
)
SELECT *
FROM RowNumCTE
To delete duplicates:
delete housedata where rowid in
( select lead(rowid) over (partition by parcelid, propertyaddress, saledate, saleprice, legalreference order by id)
from housedata );
To delete duplicates using a CTE:
delete housedata where id in
( with cte as
( select id
, row_number() over(partition by parcelid, propertyaddress, saledate, saleprice, legalreference order by id) as rn
from housedata )
select id from cte
where rn > 1 );
I think you need
BEGIN
FOR d IN
(
SELECT ROW_NUMBER() OVER
( PARTITION BY parcelid,propertyaddress,saledate,saleprice,legalreference
ORDER BY id ) AS rn,
h.*
FROM housedata h
)
LOOP
IF d.rn > 1 THEN
DELETE housedata WHERE id = d.id;
END IF;
END LOOP;
COMMIT;
END;
/
considering those five columns compose the grouping criteria for the desired deletion and id is a primary key column.

Efficient way to write this query

I am trying to order the records by 3 columns and then select a particular ID and the record before that plus the row after that. Here is my query:
;With Cte As
(
SELECT ROW_NUMBER() Over(Order By Book, PageINT, [IDAuto]) as RowNum, [IdAuto]
FROM CCWiseInstr2
)
Select * From Cte
Where RowNum = (Select RowNum From Cte
Where IdAuto = 211079)
UNION
Select * From Cte
Where RowNum = (Select RowNum - 1 From Cte
Where IdAuto = 211079)
UNION
Select * From Cte
Where RowNum = (Select RowNum + 1 From Cte
Where IdAuto = 211079)
What could the other efficient way to write this query. At the moment the query takes about 336 ms after creating all indexes which looks like a bit higher to me.
Here is the plan for the query:
http://gyazo.com/9a7f1c37d4433665d0949acf03c4561c
Any help is appreciated.
How about this query:
;With Cte As
(
SELECT ROW_NUMBER() Over(Order By Book, PageINT, [IDAuto]) as RowNum, [IdAuto]
FROM CCWiseInstr2
)
Select RowNum, IDAuto From Cte
Where RowNum IN (
Select RowNumber From
(
Select RowNum - 1 as RowNumPrev,
RowNum as RowNum,
RowNum + 1 as RowNumNext
From Cte
Where IdAuto = 211079
) vw unpivot (
RowNumber For
IdAuto IN (RowNumPrev, RowNum, RowNumNext )
) unpw )
Instead of UNION just use UNPIVOT which will convert your columns into rows which you could then use in IN. Let me know how it goes.
You can use the LEAD and LAG functions with SQL Server. Here's a great article on Simple Talk covering all of the options. (Code below is untested)
https://www.simple-talk.com/sql/t-sql-programming/sql-server-2012-window-function-basics/
SELECT
[IdAuto],
LAG([IDAuto], 1) OVER(Order By Book, PageINT, [IDAuto]) AS PreviousSale,
LEAD([IDAuto], 1) OVER(Order By Book, PageINT, [IDAuto]) AS NextSale
FROM
CCWiseInstr2
WHERE [IdAuto] = 211079;

How do I create a temp table using this snippet?

how do i produce this SQL snippet as a temp table so I can join some other stuff into it?
with MyCTE AS
(
select *, RANK() OVER (PARTITION BY workplace ORDER BY Total DESC) AS Rank
from [dbo].[OriginDestination]
)
select * from MyCTE where Rank <= 5
Like this:
with MyCTE AS
(
select *, RANK() OVER (PARTITION BY workplace ORDER BY Total DESC) AS Rank
from [dbo].[OriginDestination]
)
select *
into #yourTempTable
from MyCTE
where Rank <= 5