Getting latest data from SQL - sql

I'm having trouble getting the latest data out of this.
I have a table with these data:
ItemId, ShipmentId, Date
Items can be shipped many times and a shipment can contain multiple items.
I need to get the latest shipment for every item.
Table looks like this:
11 12 2011-05-13
11 2 2011-07-01
12 2 2000-03-02
...
The result should be
11 2 2011-07-01
12 2 2000-03-02
I can't find a solution to be exclusive.
How can I get the latest shipment for every item?

Assuming you're working with a database engine that supports ranking functions, use a CTE or subquery to order the results:
;With OrderedItems as (
select ItemId,ShipmentId,Date,
ROW_NUMBER() OVER (PARTITION BY ItemId ORDER By Date desc) as rn
from ItemsTable
)
select * from OrderedItems where rn = 1

select t1.ItemId, t1.ShipmentId, t1.Date
from tab t1
join (
select ItemId, max(Date) as Date
from tab
group by ItemId
) t on t1.ItemId = t.ItemId and t1.Date = t.Date

Didn't test it, but this general idea should work:
SELECT * FROM YOUR_TABLE T1
WHERE
NOT EXISTS (
SELECT * FROM YOUR_TABLE T2
WHERE T1.ItemId = T2.ItemId AND T1.Date < T2.Date
)
In plain English: select rows such that there is no other row with the same ItemId but later Date.

you can use rank() also in CTE
;With Ordered as (
select ItemId,ShipmentId,dates,
rank() OVER ( PARTITION by itemID ORDER By dates desc) as DateRank
from ItemsTable
)
select * from Ordered where DateRank = 1

Related

Can I nest a select statement within an IF function in SQL?

Using Teradata..
I want to write a query that joins table 1 and table 2 on item code to the location in table 2.
There are multiple locations per item code and potentially multiple item code entries per location depending on date. I'm only interested in the most recent item per location. To achieve this I've used a nested query to select the max date per both location and item number. I'm still returning more rows of data than anticipated and suspect it is due to some duplicate locations slipping through, potentially with two different item numbers.
I'm wondering if its possible to use the IF operator to say "If there are duplicate locations, choose the location with the more recent date"
Is this possible?
Here is what I have written so far:
SELECT t1.item_no, t1.date, t2.location, t2.date
FROM table 1 t1
JOIN table 2 t2 ON t1.item_no = t2.item_no
WHERE (t1.item_no, t1.date) IN
(
SELECT item_no, MAX(date)
FROM table 1
GROUP BY item_no
)
AND (t2.location, t2.date) IN
(
SELECT location, MAX(date)
FROM table 2
GROUP BY location
)
Change your query and use Subquery
SELECT t1.item_no, t1.date, t2.location, t2.date FROM
(
SELECT item_no, MAX(date) date
FROM table 1
GROUP BY item_no
) T1
JOIN
(
SELECT location, MAX(date) date
FROM table 2
GROUP BY location
) T2
ON t1.item_no = t2.location
Without knowing DBMS, a solution could be to use ROW_NUMBER(). I'm not sure if there's a preference for nested queries over say CTE but a solution w/ CTE could be:
WITH items AS (
SELECT
item_no
,date AS item_date
,row_number() OVER (PARTITION BY item_no ORDER BY date desc) as rn
FROM table1
),
locations AS (
SELECT
location
,item_no
,date AS location_date
,ROW_NUMBER() OVER(PARTITION BY item_no, location ORDER BY date desc) as rn
from table2
)
SELECT
t1.item_no
,t1.item_date
,t2.location
,t2.location_date
FROM items AS t1
JOIN locations AS t2 on t1.item_no = t2.item_no
AND t2.rn = 1
WHERE t1.rn = 1

sql query to get latest record for each id

I have one table. From that I need to get latest "Date" for each "id". I wrote query for One id. But I don't know how to apply for multiple ids.(I mean for each id)
My query for one id is (say table name is tt):
select * from (
SELECT DISTINCT id ,date FROM tt
WHERE Trim(id) ='1000082'
ORDER BY date desc
) where rownum<=1;
If you have just two columns, aggregation is good enough:
select id, max(date) max_date
from mytable
group by id
If you have more columns and you want the entire row that has the latest date for each id, then one option uses a correlated subquery for filtering:
select t.*
from mytable t
where t.date = (select max(t1.date) from mytable t1 where t1.id = t.id)
Or you can use window functions, if your database supports them:
select *
from (select t.*, row_number() over(partition by id order by date desc) rn from mytable t) t
where rn = 1

How to get newest record by date using Microsoft Access

I am trying to get the newest record by date, but am running into a hiccup. This "works" but the price amount I am receiving is incorrect.
I have tried the following and know that Last(price) is incorrect.
SELECT sku, Last(price), Max(start_date)
FROM myTable
WHERE price_id="LEV001"
GROUP BY sku;
Sample Data
sku start_date price_id price
ABC 1/1/2015 LEV001 124.99
ABC 11/2/2018 LEV001 121.99
ABC 3/7/2016 LEV001 112.99
ABC 12/2/2016 LEV002 134.99
Desired Result
ABC 11/2/2018 121.99
If you want the latest record across the whole table, just use ORDER BY and TOP 1:
SELECT TOP 1 *
FROM mytable
WHERE price_id="LEV001"
ORDER BY start_date DESC
If you want the latest record per SKU, then there are various options. One method is to use the anti-left join:
select t.*
from mytable t
left join mytable t1 on t1.sku = t.sku and t1.price_id = t.Price_id and t1.start_date > t.start_date
where t.price_id = 'LEV001' and t1.sku is null
order by sku
Use order by and top if you only want one row:
SELECT TOP 1 t.*
FROM myTable as t
WHERE price_id = "LEV001"
ORDER BY start_date DESC;
If you want this per sku -- which is suggested by your code -- then use a correlated subquery:
SELECT TOP 1 t.*
FROM myTable as t
WHERE t.price_id = "LEV001" AND
t.start_date = (SELECT MAX(t2.start_date)
FROM myTable as t2
WHERE t2.price_id = t.price_id AND
t2.sky = t.sku
);
With NOT EXISTS:
SELECT t.sku, t.price, t.start_date
FROM myTable AS t
WHERE t.price_id = "LEV001"
AND NOT EXISTS (
SELECT 1 FROM myTable
WHERE sku = t.sku AND price_id = t.price_id AND start_date > t.start_date
)

Random records in Oracle table based on conditions

I have a Oracle table with the following columns
Table Structure
In a query I need to return all the records with CPER>=40 which is trivial. However, apart from CPER>=40 I need to list 5 random records for each CPID.
I have attached a sample list of records. However, in my table I have around 50,000 records.
Appreciate if you can help.
Oracle solution:
with CTE as
(
select t1.*,
row_number() over(order by DBMS_RANDOM.VALUE) as rn -- random order assigned
from MyTable t1
where CPID <40
)
select *
from CTE
where rn <=5 -- pick 5 at random
union all
select t2.*, null
from my_table t2
where CPID >= 40
SQL Server:
with CTE as
(
select t1.*,
row_number() over(order by newid()) as rn -- random order assigned
from MyTable t1
where CPID <40
)
select *
from CTE
where rn <=5 -- pick 5 at random
union all
select t2.*, null
from my_table t2
where CPID >= 40
How about something like this...
SELECT *
FROM (SELECT CID,
CVAL,
CPID,
CPER,
Row_number() OVER (partition BY CPID ORDER BY CPID ASC ) AS RN
FROM Table) tmp
WHERE CPER>=40 OR pids <= 5
However, this is not random.
Assuming that you want five additional random records, you can do:
select t.*
from (select t.*,
row_number() over (partition by cpid,
(case when cper >= 40 then 1 else 2 end)
order by dbms_random.value
) as seqnum
from t
) t
where seqnum <= 5 or cper >= 40;
The row_number() is enumerating the rows for each cpid in two groups -- based on the cper value. The outer where is taking all cper values in the range you want as well as five from the other group.

Maximum date row postgresql

I want to find out a rows which have maximum date by product,
I want to find out a maximum date of rows by product_id
I have tried a DISTINCT but can't succeed!
One canonical way of doing this is to use a subquery to identify the records corresponding to the maximum dates for each product ID, and then restrict the original table via an INNER JOIN.
SELECT t1.*
FROM yourTable t1
INNER JOIN
(
SELECT PRODUCT_ID, MAX(DATE) AS DATE
FROM yourTable
GROUP BY PRODUCT_ID
) t2
ON t1.PRODUCT_ID = t2.PRODUCT_ID AND
t1.DATE = t2.DATE
Another way to do this would be via a window function.
select * from (
SELECT *, row_number() over (partition by Product_ID order by date desc) r
FROM table
) T
WHERE T.r=1