SQL update last occurrence - sql

I have a simple SELECT query that works fine and returns one row, which is the last occurrence of a specific value in order_id column. I want to update this row. However, I cannot combine this SELECT query with the UPDATE query.
This is the working query that returns one row, which I want to update:
SELECT *
FROM (
SELECT *,
ROW_NUMBER() OVER(PARTITION BY order_id
ORDER BY start_hour DESC) rn
FROM general_report
WHERE order_id = 16836
) q
WHERE rn = 1
And I tried many combinations to update the row returned by this statement. For example, I tried to remove SELECT *, and update the table q as in the following, but it didn't work telling me that relation q does not exist.
UPDATE q
SET q.cost = 550.01685
FROM (
SELECT *,
ROW_NUMBER() OVER(PARTITION BY order_id
ORDER BY start_hour DESC) rn
FROM general_report
WHERE order_id = 16836
) q
WHERE rn = 1
How can I combine these codes with a correct UPDATE syntax? In case needed, I test my codes at SQL Manager for PostgreSQL.

Try something like this. I am not sure on PostgreSQL syntax:
UPDATE general_report AS d
SET cost = 550.01685
FROM (
SELECT *
FROM (
SELECT *,
ROW_NUMBER() OVER(PARTITION BY order_id
ORDER BY start_hour DESC) rn
FROM general_report
WHERE order_id = 16836
) q
WHERE rn = 1
) s
WHERE d.id = s.id

Ana alternative method for update the most recent record is to use NOT EXISTS (even more recent):
UPDATE general_report dst
SET cost = 550.01685
WHERE order_id = 16836
AND NOT EXISTS (
SELECT *
FROM general_report nx
WHERE nx.order_id = dst.order_id
AND nx.start_hour > dst.start_hour
);

Test below query
UPDATE q
SET q.cost = 550.01685
where id in
(select id from
(
SELECT *
ROW_NUMBER() OVER(PARTITION BY order_id
ORDER BY start_hour DESC) rn
FROM general_report
WHERE order_id = 16836
) q
WHERE rn = 1)

Related

Return second from the last oracle sql

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

Selecting the latest order

I need to select the data of all my customers with the records displayed in the image. But I need to get the most recent record only, for example I need to get the order # E987 for John and E888 for Adam. As you can see from the example, when I do the select statement, I get all the order records.
You don't mention the specific database, so I'll answer with a generic solution.
You can do:
select *
from (
select t.*,
row_number() over(partition by name order by order_date desc) as rn
from t
) x
where rn = 1
You can use analytical function row_number.
Select * from
(Select t.*,
Row_number() over (partition by customer_id order by order_date desc) as rn
From your_table t) t
Where rn = 1
Or you can use not exists as follows:
Select *
From yoir_table t
Where not exists
(Select 1 from your_table tt
Where t.customer_id = tt.custome_id
And tt.order_date > t.order_date)
You can do it with a subquery that finds the last order date.
SELECT t.*
FROM yoir_table t
JOIN (SELECT tt.custome_id,
MAX(tt.order_date) MaxOrderDate
FROM yoir_table tt
GROUP BY tt.custome_id) AS tt
ON t.custome_id = tt.custome_id
AND t.order_date = tt.MaxOrderDate

Select every second record then determine earliest date

I have table that looks like the following
I have to select every second record per PatientID that would give the following result (my last query returns this result)
I then have to select the record with the oldest date which would be the following (this is the end result I want)
What I have done so far: I have a CTE that gets all the data I need
WITH cte
AS
(
SELECT visit.PatientTreatmentVisitID, mat.PatientMatchID,pat.PatientID,visit.RegimenDate AS VisitDate,
ROW_NUMBER() OVER(PARTITION BY mat.PatientMatchID, pat.PatientID ORDER BY visit.VisitDate ASC) AS RowNumber
FROM tblPatient pat INNER JOIN tblPatientMatch mat ON mat.PatientID = pat.PatientID
LEFT JOIN tblPatientTreatmentVisit visit ON visit.PatientID = pat.PatientID
)
I then write a query against the CTE but so far I can only return the second row for each patientID
SELECT *
FROM
(
SELECT PatientTreatmentVisitID,PatientMatchID,PatientID, VisitDate, RowNumber FROM cte
) as X
WHERE RowNumber = 2
How do I return the record with the oldest date only? Is there perhaps a MIN() function that I could be including somewhere?
If I follow you correctly, you can just order your existing resultset and retain the top row only.
In standard SQL, you would write this using a FETCH clause:
SELECT *
FROM (
SELECT
visit.PatientTreatmentVisitID,
mat.PatientMatchID,
pat.PatientID,
visit.RegimenDate AS VisitDate,
ROW_NUMBER() OVER(PARTITION BY mat.PatientMatchID, pat.PatientID ORDER BY visit.VisitDate ASC) AS rn
FROM tblPatient pat
INNER JOIN tblPatientMatch mat ON mat.PatientID = pat.PatientID
LEFT JOIN tblPatientTreatmentVisit visit ON visit.PatientID = pat.PatientID
) t
WHERE rn = 2
ORDER BY VisitDate
OFFSET 0 ROWS FETCH FIRST 1 ROW ONLY
This syntax is supported in Postgres, Oracle, SQL Server (and possibly other databases).
If you need to get oldest date from all selected dates (every second row for each patient ID) then you can try window function Min:
SELECT * FROM
(
SELECT *, MIN(VisitDate) OVER (Order By VisitDate) MinDate
FROM
(
SELECT PatientTreatmentVisitID,PatientMatchID,PatientID, VisitDate,
RowNumber FROM cte
) as X
WHERE RowNumber = 2
) Y
WHERE VisitDate=MinDate
Or you can use SELECT TOP statement. The SELECT TOP clause allows you to limit the number of rows returned in a query result set:
SELECT TOP 1 PatientTreatmentVisitID,PatientMatchID,PatientID, VisitDate FROM
(
SELECT *
FROM
(
SELECT PatientTreatmentVisitID,PatientMatchID,PatientID, VisitDate,
RowNumber FROM cte
) as X
WHERE RowNumber = 2
) Y
ORDER BY VisitDate
For simplicity add order desc on date column and use TOP to get the first row only
SELECT TOP 1 *
FROM
(
SELECT PatientTreatmentVisitID,PatientMatchID,PatientID, VisitDate, RowNumber FROM cte
) as X
WHERE RowNumber = 2
order by VisitDate desc

Include join in a subquery

I trying to make a query to obtain the last date time when a records repeat.
select * from OCCONTROLMERCADERIA om
join OCCONTROLMERCADERIALINEAS oml on om.occontrolid=oml.occontrolid
where om.OCControlNroId=5519337
This return this:
Result Query 1
The query that i want should return the register are in the blue box.
I have this query that found (without the join):
with
p as (select * from OCCONTROLMERCADERIA om where om.OCControlNroId=5519337),
p_rnk as (
select *, row_number() over (partition by OCControlNroId order by OCControlFecha desc) as rn
from p
)
select * from p_rnk where rn = 1 order by OCControlNroId;
This return this:
Result Query 2
That its ok, if see the box blue in the first image, the last date corresponds to the record id 13756.
But I need that the query return the 3 records that corresponds to id 13756, and not only one, so i trying to apply the join.
with
p as (select * from OCCONTROLMERCADERIA om
join OCCONTROLMERCADERIALINEAS oml on om.occontrolid=oml.occontrolid
where om.OCControlNroId=5519337),
p_rnk as (
select *, row_number() over (partition by OCControlNroId order by OCControlFecha desc) as rn
from p
)
select * from p_rnk where rn = 1 order by OCControlNroId;
But this return:
The column 'OCControlId' was specified multiple times for 'p'.
I´m trying this (select om.*):
with
p as (select om.* from OCCONTROLMERCADERIA om
join OCCONTROLMERCADERIALINEAS oml on om.occontrolid=oml.occontrolid
where om.OCControlNroId=5519337),
p_rnk as (
select *, row_number() over (partition by OCControlNroId order by OCControlFecha desc) as rn
from p
)
select * from p_rnk where rn = 1 order by OCControlNroId;
And the error disappears but only return one records, no the three. Which could the problem ?
Thanks for your help!

Oracle, get top row using order by desc and rownum

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