Max() not filtering out MIN() - sql

when I use run the query below, it returns duplicate StockNo's because some of them have duplicate WorkInProgress codes (FiWipStatus Code).
Is there a way to exclude the record based on the the MIN() on rowlastupdated?
as always, appreciate any help!
SELECT dbo.InventoryVehicle.StockNo, dbo.VehicleSales.FiWipStatusCode,
MAX(dbo.VehicleSales.RowLastUpdated) AS Expr1
FROM dbo.VehicleSales RIGHT OUTER JOIN
dbo.InventoryVehicle ON dbo.VehicleSales.StockNo = dbo.InventoryVehicle.StockNo
GROUP BY dbo.InventoryVehicle.StockNo, dbo.VehicleSales.FiWipStatusCode,
dbo.VehicleSales.RowLastUpdated

If I got it correctly, you need to get the records based on their last update date and time (which is RowLastUpdated). if so, you can do something like this :
SELECT
iv.StockNo
, vs.FiWipStatusCode
, vs.RowLastUpdated
FROM (
SELECT
iv.StockNo
, vs.FiWipStatusCode
, vs.RowLastUpdated
, ROW_NUMBER() OVER(PARTITION BY iv.StockNo ORDER BY vs.RowLastUpdated DESC) AS RN
FROM
VehicleSales vs
LEFT JOIN InventoryVehicle iv ON vs.StockNo = iv.StockNo
) D
WHERE
RN = 1
where ROW_NUMBER() will number the rows based on StockNo and order them based on RowLastUpdated in DESC. So, the first row of each distinct StockNo will be the MAX() datetime in your aggregation query. if you want to get the MIN() just change the order to ASC

Related

SQL Max or empty value grouped by conditions

I have a table like this
and i want my output to look like this
I need to look at the ID and then take max created date and max completed date for that ID. There is also some cases where completed date is still empty so in that case i just need to look at the max created date. Im not sure how to tackle this, doing a group by doesnt account for my multiple scenarios
Use ROW_NUMBER:
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY QUOTE_NUMBER
ORDER BY WORKBOOK_CREATED_DATE DESC) rn
FROM yourTable
)
SELECT *
FROM yourTable
WHERE rn = 1;

Find the second largest value with Groupings

In SQL Server, I am attempting to pull the second latest NOTE_ENTRY_DT_TIME (items highlighted in screenshot). With the query written below it still pulls the latest date (I believe it's because of the grouping but the grouping is required to join later). What is the best method to achieve this?
SELECT
hop.ACCOUNT_ID,
MAX(hop.NOTE_ENTRY_DT_TIME) AS latest_noteid
FROM
NOTES hop
WHERE
hop.GEN_YN IS NULL
AND hop.NOTE_ENTRY_DT_TIME < (SELECT MAX(hope.NOTE_ENTRY_DT_TIME)
FROM NOTES hope
WHERE hop.GEN_YN IS NULL)
GROUP BY
hop.ACCOUNT_ID
Data sample in the table:
One of the "easier" ways to get the Nth row in a group is to use a CTE and ROW_NUMBER:
WITH CTE AS(
SELECT Account_ID,
Note_Entry_Dt_Time,
ROW_NUMBER() OVER (PARTITION BY AccountID ORDER BY Note_Entry_Dt_Time DESC) AS RN
FROM dbo.YourTable)
SELECT Account_ID,
Note_Entry_Dt_Time
FROM CTE
WHERE RN = 2;
Of course, if an ACCOUNT_ID only has 1 row, then it will not be returned in the result set.
The OP's statement "The row will not always be 2." from the comments conflicts with their statement "I am attempting to pull the second latest NOTE_ENTRY_DT_TIME" in the question. At a best guess, this means that the OP has rows with the same date, that could be the "latest" date. If so, then would simply need to replace ROW_NUMBER with DENSE_RANK. Their sampple data, however, doesn't suggest this is the case.
You can use window functions:
select *
from (
select
n.*,
row_number() over(partition by account_id order by note_entry_dt_time desc) rn
from notes n
) t
where rn = 2

Using row_number() in subquery results in ORA-00913: too many values

In Oracle, I wish to do something like the SQL below. For each row in "criteria," I want to find the latest row in another table (by last_modified_date) for the same location_id, and use that value to set default_start_interval. Or, if there is no such value, then use 30. However, as you can see, the subquery must have two values in the select statement to use row_number(). That causes an error. How do I reformat it so that it works?
update criteria pc set default_start_interval =
COALESCE(
(SELECT start_interval,
row_number() over(partition by aday.location_id
order by atime.last_modified_date desc
) as rn
FROM available_time atime
JOIN available_day aday ON aday.available_day_id = atime.available_day_id
WHERE aday.location_id = pc.location_id
and rn = 1)
, 30)
There are two issues in your update query:
The update expects only one value per row for default_start_interval, however, you have two columns in the select list.
The row number should be assigned before in the inner query, and then apply filter where rn = 1 in outer query.
Your update query should look like:
UPDATE criteria pc
SET default_start_interval = NVL(
(
SELECT start_interval FROM(
SELECT
start_interval, ROW_NUMBER() OVER(
PARTITION BY aday.location_id
ORDER BY atime.last_modified_date DESC
) AS rn
FROM
available_time atime
JOIN available_day aday ON aday.available_day_id = atime.available_day_id
WHERE
aday.location_id = pc.location_id
)
WHERE rn = 1)
, 30)
Note: You could simply use NVL instead of COALESCE as you only have one value to check for NULL. COALESCE is useful when you have multiple expressions.
I think a simpler method uses aggregation and keep to get the value you want:
update criteria pc
set default_start_interval =
(select coalesce(max(start_interval) keep (dense_rank first order by atime.last_modified_date desc), 30)
from available_time atime join
available_day aday
on aday.available_day_id = atime.available_day_id
where aday.location_id = pc.location_id
);
An aggregation query with no GROUP always returns one row. If no rows match, then the returned value is NULL -- the COALESCE() captures this case.

Duration between 2 dates based on another column

I currently have a table of data that shows different steps in a process, with a date/time each step was carried out.
enter image description here
What I'm looking to do is add a column that calculates the time in minutes between each step, however it has to relate to the claimID, so in the image shown I would be looking for difference between each step for the top 4 results (as they share the same claimID), then the following 6 results, etc.
Can anyone help? I'm using SQL Server
Depending on what version of SQL Server you are using you can either use a self join or the lag window function (this should work in SQL Server 2012+):
select
claimid
, statusid
, statussetdate
, coalesce(datediff(minute,
lag(statussetdate) over (partition by claimid order by statussetdate),
statussetdate
),0) as diff_in_minutes
from
your_table
order by
ClaimID
, StatusSetDate;
You can self join the table to itself using the Row_number to get the previous date and do a DateDiff on the 2 values..
;WITH cte AS
(
SELECT *, ROW_NUMBER() OVER (PARTITION BY ClaimID ORDER BY StatusSetDate) Rn
FROM ClaimStatus
)
SELECT curr.*,
ISNULL(DATEDIFF(minute, prev.StatusSetDate, curr.StatusSetDate),0)
FROM cte curr
LEFT JOIN cte prev ON curr.ClaimID = prev.ClaimID AND curr.Rn = prev.Rn + 1
ORDER BY curr.ClaimID, curr.StatusSetDate

One row of data for a max date only - transact SQL

I am trying to select the max dates on a field with other tables, to only give me one distinct row for the max date and not other rows with other dates. the code i have for max is
SELECT DISTINCT
Cust.CustId,
LastDate=(Select Max(Convert(Date,TreatmentFieldHstry.TreatmentDateTime))
FROM TreatmentFieldHstry
WHERE Cust.CustSer = Course.CustSer
AND Course.CourseSer = Session.CourseSer
AND Session.SessionSer = TreatmentFieldHstry.SessionSer)
This gives multiple rows depending on how many dates - i just want one for the max - can anyone help with this?
Thanks
You didn't specify exactly what database and version you're using - but if you're on SQL Server 2005 or newer, you can use something like this (a CTE with the ROW_NUMBER ranking function) - I've simplified it a bit, since I don't know what those other tables are that you have in your select, that don't ever show up in any of the SELECT column lists.....
;WITH TopData AS
(
SELECT c.CustId, t.TreatmentDateTime,
ROW_NUMBER() OVER(PARTITION BY c.CustId ORDER BY t.TreatmentDateTime DESC) AS 'RowNum'
FROM
dbo.TreatmentFieldHstry t
INNER JOIN
dbo.Customer c ON c.CustId = t.CustId -- or whatever JOIN condition you have
WHERE
c.CustSer = Course.CustSer
)
SELECT
*
FROM
TopData
WHERE
RowNum = 1
Basically, the CTE (Common Table Expression) partitions your data by CustId and order by TreatmentDateTime (descending - newest first) - and numbers every entry with a consecutive number - for each "partition" (e.g. for each new value of CustId). With this, the newest entry for each customer has RowNum = 1 which is what I use to select it from that CTE.