SQL Select latest row by date - sql

I have a large amount of data that updates every 10 minutes or so.
There are 128 unique ID's that need to be returned but with only there latest values
CURRENT CODE
SELECT DISTINCT
id,
MAX(extractdate) AS [extractdate],
total,
used,
free
FROM
maintable
INNER JOIN datatable ON maintable.unkey = datatable.dataunkey
GROUP BY id, total, used, free
ORDER BY id
CURRENT OUTPUT
id extractdate total used free
1 2014-08-28 00:20:00.000 50 20 30
1 2014-08-28 00:30:00.000 50 30 20
1 2014-08-28 00:40:00.000 50 10 40
2 2014-08-28 00:20:00.000 50 20 30
2 2014-08-28 00:30:00.000 50 30 20
2 2014-08-28 00:40:00.000 50 25 25
etc etc
**DESIRED OUTPUT**
id extractdate total used free
1 2014-08-28 00:40:00.000 50 10 40
2 2014-08-28 00:40:00.000 50 25 25
etc etc

Try:
SELECT
a.id,
a.extractdate,
a.total,
a.used,
a.free
FROM(
SELECT
id,
MAX(extractdate) AS [extractdate],
total,
used,
free,
ROW_NUMBER()OVER(partition by id ORDER BY MAX(extractdate) desc) AS rnk
FROM maintable
INNER JOIN datatable ON maintable.unkey = datatable.dataunkey
GROUP BY id, total, used, free )a
WHERE a.rnk = 1

Should work, i've just tested it on the similar fall, only without join:
SELECT id, extractdate,total,used,free
FROM maintable m INNER JOIN datatable ON m.unkey = datatable.dataunkey
where extractdate = (select max(extractdate) from manitable m1 where m1.id = m.id)
ORDER BY id

Related

Getting latest price of different products from control table

I have a control table, where Prices with Item number are tracked date wise.
id ItemNo Price Date
---------------------------
1 a001 100 1/1/2003
2 a001 105 1/2/2003
3 a001 110 1/3/2003
4 b100 50 1/1/2003
5 b100 55 1/2/2003
6 b100 60 1/3/2003
7 c501 35 1/1/2003
8 c501 38 1/2/2003
9 c501 42 1/3/2003
10 a001 95 1/1/2004
This is the query I am running.
SELECT pr.*
FROM prices pr
INNER JOIN
(
SELECT ItemNo, max(date) max_date
FROM prices
GROUP BY ItemNo
) p ON pr.ItemNo = p.ItemNo AND
pr.date = p.max_date
order by ItemNo ASC
I am getting below values
id ItemNo Price Date
------------------------------
10 a001 95 2004-01-01
6 b100 60 2003-01-03
9 c501 42 2003-01-03
Question is, is my query right or wrong? though I am getting my desired result.
Your query does what you want, and is a valid approach to solve your problem.
An alternative option would be to use a correlated subquery for filtering:
select p.*
from prices p
where p.date = (select max(p1.date) from prices where p1.itemno = p.itemno)
The upside of this query is that it can take advantage of an index on (itemno, date).
You can also use window functions:
select *
from (
select p.*, rank() over(partition by itemno order by date desc) rn
from prices p
) p
where rn = 1
I would recommend benchmarking the three options against your real data to assess which one performs better.

How to get latest records based on two columns of max

I have a table called Inventory with the below columns
item warehouse date sequence number value
111 100 2019-09-25 12:29:41.000 1 10
111 100 2019-09-26 12:29:41.000 1 20
222 200 2019-09-21 16:07:10.000 1 5
222 200 2019-09-21 16:07:10.000 2 10
333 300 2020-01-19 12:05:23.000 1 4
333 300 2020-01-20 12:05:23.000 1 5
Expected Output:
item warehouse date sequence number value
111 100 2019-09-26 12:29:41.000 1 20
222 200 2019-09-21 16:07:10.000 2 10
333 300 2020-01-20 12:05:23.000 1 5
Based on item and warehouse, i need to pick latest date and latest sequence number of value.
I tried with below code
select item,warehouse,sequencenumber,sum(value),max(date) as date1
from Inventory t1
where
t1.date IN (select max(date) from Inventory t2
where t1.warehouse=t2.warehouse
and t1.item = t2.item
group by t2.item,t2.warehouse)
group by t1.item,t1.warehouse,t1.sequencenumber
Its working for latest date but not for latest sequence number.
Can you please suggest how to write a query to get my expected output.
You can use row_number() for this:
select *
from (
select
t.*,
row_number() over(
partition by item, warehouse
order by date desc, sequence_number desc, value desc
) rn
from mytable t
) t
where rn = 1

Find out per day the first trip duration and last trip duration of a bike

Find out per day first trip duration and last trip duration of a bike.
Table
trip_id bike-id trip_date trip_starttime trip_duration
1 1 2018-12-01 12:00:00.0000000 10
2 2 2018-12-01 14:00:00.0000000 25
3 1 2018-12-01 14:30:00.0000000 5
4 3 2018-12-02 05:00:00.0000000 12
5 3 2018-12-02 19:00:00.0000000 37
6 1 2018-12-02 20:30:00.0000000 20
Expected Result
trip_date bike-id first_trip_duration last_trip_duration
2018-12-01 1 10 5
2018-12-01 2 25 25
2018-12-02 1 20 20
2018-12-02 3 12 37
I tried it with below code,
select A.trip_date,A.[bike-id],A.trip_duration AS Minduration,B.trip_duration AS MaxDUrtaion from
(SELECT T1.trip_date,T1.[bike-id],T1.trip_duration FROM TRIP T1
INNER JOIN (
select trip_date,[bike-id] , min(trip_starttime) AS Mindate
from Trip group by trip_date,[bike-id] ) T2
oN T1.[bike-id]=T2.[bike-id] AND T1.trip_date=T2.trip_date AND t1.trip_starttime=t2.Mindate ) as A
inner join
(SELECT T1.trip_date,T1.[bike-id],T1.trip_duration FROM TRIP T1
INNER JOIN (
select trip_date,[bike-id] , MAX(trip_starttime) AS Maxdate
from Trip group by trip_date,[bike-id] ) T2
oN T1.[bike-id]=T2.[bike-id] AND T1.trip_date=T2.trip_date AND t1.trip_starttime=t2.Maxdate ) as B
ON A.[bike-id]=B.[bike-id] AND A.trip_date=B.trip_date
order by A.trip_date,A.[bike-id]
I want to know some other logic too, please help out.
First, determine for each date/bike the first and last trip.
Then, determine the duration of these trips.
Something like this might do it (I didn't test it though):
SELECT minmax.trip_date,
minmax.bike_id,
first.trip_duration AS first_trip_duration,
last.trip_duration AS last_trip_duration
FROM (SELECT trip_date,
bike_id,
MIN(trip_starttime) AS first_trip,
MAX(trip_starttime) AS last_trip
FROM trip_table
GROUP BY trip_date,
bike_id
) minmax
JOIN trip_table first
ON minmax.trip_date = first.trip_date
AND minmax.bike_id = first.bike_id
AND minmax.first_trip = first.trip_starttime
JOIN trip_table last
ON minmax.trip_date = last.trip_date
AND minmax.bike_id = last.bike_id
AND minmax.last_trip = last.trip_starttime
Supposing you have the necessary indexes on the table.
Preferably a unique index on (bike_id, trip_date, starttime).
select trip_date,bike_id
,first_value(trip_duration) over(partition by trip_date,bike_id order by trip_starttime) as first_trip_duration
,first_value(trip_duration) over(partition by trip_date,bike_id order by trip_starttime desc) as last_trip_duration
from trip;
Assuming window functions are supported, this can be done with first_value.
select distinct
trip_date
,bike_id
,first_value(trip_duration) over(partition by trip_date,bike_id order by trip_starttime) as first_trip_duration
,first_value(trip_duration) over(partition by trip_date,bike_id order by trip_starttime desc) as last_trip_duration
from trip

SQL group by and max and other fields

I have a table that contains:
ITEMID COSTAMOUNTPOSTED QTY DATEPHYSICAL
10001 20 20 2014-10-01
10001 30 20 2014-10-20
10005 20 20 2014-10-01
10005 20 30 2014-10-15
I want to select the last physical action with the item, the result I want to get is:
ITEMID COSTAMOUNTPOSTED QTY DATEPHYSICAL
10001 30 20 2014-10-20
10005 20 30 2014-10-15
The query I run :
SELECT itemid,costamountposted,qty,datephysical
FROM A
where datephysical =(select max(datephysical)
FROM A
But I only get result with items that have biggest physical date. Any suggestions?
You can do this using subquery,
SELECT a.*
FROM tableName a
INNER JOIN
(
SELECT ITEMID , MAX(DATEPHYSICAL) max_date
FROM tableName
GROUP BY ITEMID
) b ON a.ITEMID = b.ITEMID AND a.DATEPHYSICAL = b.max_date

Split a Table into 2 or more Tables based on Column value

I have a Table called "MIVTable" which has the following records,
MIVID Quantity Value
------ ---------- --------
14 10 3000
14 20 3500
14 15 2000
15 20 3000
15 50 7500
16 25 2000
Here, I need to store the above Table into two tables such as "HeaderTbl" and "DetailTbl" based on the MIVID as follows:
HeaderTbl:
HID MIVID TotalQuantity TotalValue
----- ------- ------------- -----------
1 14 45 8500
2 15 70 10500
3 16 25 2000
Here HID is the Primary Key with Identity Column.
DetailTbl:
HID MIVID Quantity Value
----- ------- ------------ -------
1 14 10 3000
1 14 20 3500
1 14 15 2000
2 15 20 3000
2 15 50 7500
3 16 25 2000
Suppose, if the MIVTable contains 4 different MIVID means, then 4 row should be created based on the MIVID on the HeaderTbl. How to do this?
To insert records in HeaderTbl from MIVTable use this: (HID should be auto increment)
INSERT INTO HeaderTbl
([MIVID], [TotalQuantity], [TotalValue])
SELECT MIVID, SUM(Quantity), SUM(Value) FROM MIVTable GROUP BY MIVID;
To insert records in DetailTbl from HeaderTbl and MIVTable use this:
INSERT INTO DetailTbl
([HID], [MIVID], [Quantity], [Value])
SELECT H.HID, M.*
FROM HeaderTbl H
INNER JOIN MIVTable M
ON H.MIVID = M.MIVID;
Look at this SQLFiddle
Here you need to use INSERT INTO SELECT statement to insert data from one table to another. You can also use JOIN in such statement as I did it for DetailTbl.
You would generate the HeaderTbl using RANK() SQL Server function, as follows:
SELECT RANK() OVER (ORDER BY MIVID) as HID, MIVID, TotalQuantity, TotalValue
FROM
(
SELECT
MIVID,
SUM(Quantity) as TotalQuantity,
SUM(Value) as TotalValue
FROM MIVTable GROUP BY MIVID
) AS A
and the Detail table using the ROW_NUMBER() SQL Server function, as follows:
SELECT
ROW_NUMBER() OVER (ORDER BY MIVID) AS HID,
MIVID,
Quantity,
Value
FROM MIVTable