I have the follow sql statement. I'm trying to get the highest version. My query is returning multiple results, although sorted by verison desc. How can I just get the highest one?
SELECT pv.version, pv.vin, pv.policyid, pv.segeffdate, pv.segexpdate, pv.changenum from
nsa_al.polvehicle pv
WHERE pv.vin = '2GTEC19T011201788'
AND pv.changenum > 0
AND pv.VERSION = (SELECT MAX(PV.VERSION) FROM NSA_AL.POLVERSION)
ORDER BY pv.version DESC
I've tried to use the rownum = 1 but I kept getting missing ")" error.
Thanks
There are a couple of ways to do this. Here is one with a subquery and ROWNUM:
SELECT *
FROM (
SELECT pv.version, pv.vin, pv.policyid, pv.segeffdate, pv.segexpdate, pv.changenum
FROM nsa_al.polvehicle pv
WHERE pv.vin = '2GTEC19T011201788'
AND pv.changenum > 0
ORDER BY pv.version DESC
) t
WHERE ROWNUM = 1
SQL Fiddle Demo
This will only return a single record. If you need ties, you can use the analytic function RANK() instead.
SELECT *
FROM (
SELECT RANK() OVER (ORDER BY version DESC) rnk, pv.version, pv.vin, pv.changenum
FROM pv
WHERE pv.vin = '2GTEC19T011201788'
AND pv.changenum > 0
ORDER BY pv.version DESC
) t
WHERE rnk = 1
If you prefer to use a MAX aggregate, then it's easiest to do that with a common table expression and JOIN the table back on itself. This could yield multiple results if there are multiple records with the same version:
WITH CTE AS (
SELECT pv.version, pv.vin, pv.changenum
FROM pv
WHERE pv.vin = '2GTEC19T011201788'
AND pv.changenum > 0
)
SELECT *
FROM CTE C
JOIN (
SELECT MAX(version) maxVersion
FROM CTE) C2 ON C.version = C2.maxVersion
More Fiddle
Related
Can I rewrite this select without using aggregate function to retrieve the highest value
Select *
From A
Where Id= 123
and value = (
select max(value)
from A inner
where inner.id = 123 )
If you are certain that only one record would have the max value, or, if there are ties you don't care which gets returned, then you may use this limit query:
SELECT *
FROM A
WHERE Id = 123
ORDER BY value DESC
LIMIT 1;
If this doesn't meet your expectations, then stick with your current approach. Note that you could also use RANK() here:
WITH cte AS (
SELECT *, RANK() OVER (ORDER BY value DESC) rnk
FROM A
WHERE Id = 123
)
SELECT *
FROM cte
WHERE rnk = 1;
But like your version, the above rank query also requires a subquery.
SELECT * FROM
(
SELECT DISTINCT(TRUNC(receipt_dstamp))
FROM inventory
WHERE substr(location_id,1,3) = 'GI-'
ORDER BY 1 ASC
)
WHERE ROWNUM <= 5
Output:
Hi all, i've got this subeqery and in this case my oldest date is in row 1, i want to retrive only second from the last(from the top in this case) which is gonna be 01-SEP-21.
I was trying to play with ROWNUM and OVER but without any results, im getting blank output.
Thank you.
Full query:
SELECT TRUNC(receipt_dstamp) as old_putaway_date, COUNT(tag_id) as tag_old_putaway
FROM inventory
WHERE substr(location_id,1,3) = 'GI-'
AND TRUNC(receipt_dstamp) IN (
SELECT * FROM
(
SELECT DISTINCT(TRUNC(receipt_dstamp))
FROM inventory
WHERE substr(location_id,1,3) = 'GI-'
ORDER BY 1 ASC
)
WHERE ROWNUM = 1
)
GROUP BY TRUNC(receipt_dstamp);
You should be able to simplify the entire query to:
SELECT old_putaway_date,
COUNT(tag_id) as tag_old_putaway
FROM (
SELECT TRUNC(receipt_dstamp) as old_putaway_date,
tag_id,
DENSE_RANK() OVER (ORDER BY TRUNC(receipt_dstamp)) AS rnk
FROM inventory
WHERE substr(location_id,1,3) = 'GI-'
)
WHERE rnk = 3
GROUP BY
old_putaway_date;
You can use dense_rank() :
SELECT * FROM (
SELECT L.*,DENSE_RANK()
OVER (PARTITION BY L.TAG_OLD_PUTAWAY ORDER BY L.OLD_PUTAWAY_DATE DESC) RNK
FROM
(
SELECT TRUNC(receipt_dstamp) as old_putaway_date, COUNT(tag_id) as tag_old_putaway
FROM inventory
WHERE substr(location_id,1,3) = 'GI-'
AND TRUNC(receipt_dstamp) IN (
SELECT * FROM
(
SELECT DISTINCT(TRUNC(receipt_dstamp))
FROM inventory
WHERE substr(location_id,1,3) = 'GI-'
ORDER BY 1 ASC
)
WHERE ROWNUM = 1
)
GROUP BY TRUNC(receipt_dstamp)
) L
) WHERE RNK = 2
You are using an old Oracle syntax that is not standard compliant in the regard that it relies on a subquery result order. (Sub)query results are unordered data sets by definition, but Oracle lets this pass in order to make their ROWNUM work with it.
Oracle now supports the standard SQL FETCH clause, which you should use instead.
SELECT DISTINCT TRUNC(receipt_dstamp) AS receipt_date
FROM inventory
WHERE SUBSTR(location_id, 1, 3) = 'GI-'
ORDER BY receipt_date
OFFSET 2 ROWS
FETCH NEXT 1 ROW ONLY;
https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/SELECT.html#GUID-CFA006CA-6FF1-4972-821E-6996142A51C6
This query gives me invalid identifier error, and i know it is because subquery will only be able to access data that is one layer higher.
select *
from t2_callerid_plan cp
where cp.subsrefnum in (
select *
from (
select vsap.subsrefnum
from prv_internet_responses_vsap vsap
where vsap.subsrefnum = cp.subsrefnum
order by vsap.id desc
)
where rownum = 1
);
Now, i was wandering if there is way i can create query that would be able to return only the newest row while using the data from query in subquery?
You can use ROW_NUMBER() :
SELECT * FROM (
SELECT cp.*,
ROW_NUMBER() OVER(PARTITION BY cp.subsrefnum ORDER BY vsap.id desc) as rnk
from t2_callerid_plan cp
JOIN prv_internet_responses_vsap vsap
ON vsap.subsrefnum = cp.subsrefnum) p
WHERE p.rnk = 1
you can try this:
select *
from t2_callerid_plan cp
inner join
(
select vsap.subsrefnum,ROW_NUMBER() OVER (PARTITION BY subsrefnum ORDER BY vsap.id desc) rn
from prv_internet_responses_vsap vsap
)vsap
on vsap.subsrefnum = cp.subsrefnum and vsap.rn=1
I am using SQL Server 2008 R2.
I found duplicate rows with this script:
SELECT CLDest, CdClient,
COUNT(CLDest) AS NumOccurrences
FROM DEST
GROUP BY CLDest,CdClient
HAVING ( COUNT(CLDest) > 1 )
It return 48 entries
Before I delete I have to make sure that I delete the doubles:
SELECT DEST.CdClient
,DEST.CLDest
FROM [Soft8Exp_Client_WEB].[dbo].[DEST]
WHERE DEST.CdClient IN (SELECT CdClient
FROM DEST
GROUP BY CdClient
HAVING (COUNT(CLDest) > 1) )
AND DEST.CLDest IN (SELECT CLDest
FROM DEST
GROUP BY CLDest
HAVING (COUNT(CLDest) > 1) )
This query returns 64628 entries
So I suppose my select is wrong.
SQL Server has the nice property of updatable CTEs. When combined with the function row_number(), this does what you want:
with todelete as (
select d.*,
row_number() over (partition by CLDest, CdClient order by newid()) as seqnum
from dest d
)
delete from todelete
where seqnum > 1;
This version will randomly delete one of the duplicates. What it does is assign a sequential number to the rows with the same value and delete all but the first one found. If you want to keep something by date, then use a different expression in the order by.
;WITH Duplicates
AS
(
SELECT CLDest
, CdClient
, ROW_NUMBER() OVER (PARTITION BY CLDest, CdClient ORDER BY CdClient) AS Rn
FROM DEST
)
DELETE FROM Duplicates
WHERE RN > 1
SELECT DEST.CdClient,DEST.CLDest
FROM [Soft8Exp_Client_WEB].[dbo].[DEST]
WHERE DEST.CdClient+DEST.CLDest
IN (
SELECT CdClient+CLDest FROM DEST GROUP BY CLDest HAVING ( COUNT(CLDest) > 1 )
)
My query is as follows
BEGIN
WITH MyCTE
AS (
SELECT T.MusicAlbumTitle
,D.musicTitle
,D.mVideoID
,D.musicFileName
,T.ReleaseDate AS ReleasedDate
,D.MusicLength
,D.musicSinger
,D.MusicVideoID
,D.ExternalLink
,D.CoverImg
,ROW_NUMBER() OVER (
PARTITION BY D.MusicVideoID ORDER BY D.mVideoID
) AS row_num
FROM dbo.Music_Video T
JOIN dbo.Music_Video_Details D ON T.MusicVideoID = D.MusicVideoID
WHERE T.PortalID = #PortalID
AND T.CultureCode = #CultureCode
AND T.ComingSoon <> 1
GROUP BY T.MusicAlbumTitle
,D.musicTitle
,D.mVideoID
,T.ReleaseDate
,D.musicFileName
,D.MusicLength
,D.musicSinger
,D.MusicVideoID
,D.ExternalLink
,D.CoverImg
)
SELECT a.mVideoID
,a.MusicVideoID
,a.musicFileName
,a.MusicAlbumTitle
,a.ReleasedDate
,a.row_num
,a.CoverImg
,a.ExternalLink
,a.musicTitle
,a.MusicLength
FROM MyCTE a
WHERE row_num = 1
ORDER BY MusicVideoID DESC
END
I need to achieve total row count from last select statement.
which mean total row count that is being selected.
or any idea that might be use in this condition
How can i do this ..
Please add COUNT(*) OVER() in your select, which returns total rows selected as a new column.
Ex:
SELECT
*,
COUNT(*) OVER() AS [Total_Rows]
FROM YourTable
Just to be clear, you need to add the count to the CTE, not the outer query. The outer select is returning only one row, so the count would always be one.
The CTE should start:
WITH MyCTE
AS (
SELECT T.MusicAlbumTitle
,D.musicTitle
,D.mVideoID
,D.musicFileName
,T.ReleaseDate AS ReleasedDate
,D.MusicLength
,D.musicSinger
,D.MusicVideoID
,D.ExternalLink
,D.CoverImg
,ROW_NUMBER() OVER (
PARTITION BY D.MusicVideoID ORDER BY D.mVideoID
) AS row_num,
COUNT(*) over () as total_count