select id with max date and keep all same max date SQL - sql

I have a sample dataset
id category date value
1 a 2013-01-02 7
2 a 2013-01-02 2
3 a 2013-01-01 3
4 b 2013-01-01 1
5 b 2013-01-02 4
6 b 2013-01-03 5
7 c 2013-01-03 4
8 c 2013-01-03 8
I would like to return the following table as output
id date
1 2013-01-02
2 2013-01-02
6 2013-01-03
7 2013-01-03
8 2013-01-03
I use the following code to get result,but date only return once. I would like to keep both.
SELECT id,date
FROM order t1
INNER JOIN
(
SELECT id, MAX(date) as maxdate
FROM order
GROUP BY category
) t2
ON t1.id = t2.id
AND t1.date = t2.maxdate
Please advice if I have something wrong.

From your example - you seem to want a query that gives you all the rows that match the max date in each category?
If so, you should group across the category (don't grab the ID from your t2). The subselect should give you the category and the maximum date, the outer correlated join will give you all the rows that match that category and date.
SELECT category,id,date
FROM order t1
INNER JOIN
(
SELECT category, MAX(date) as maxdate
FROM order
GROUP BY category
) t2
ON t1.category = t2.category
AND t1.date = t2.maxdate

If you are using sql-server-2012 and above you can also use this.
DECLARE #T TABLE (id INT, category VARCHAR(5), [date] date, value int)
INSERT INTO #T VALUES
(1, 'a', '2013-01-02', 7),
(2, 'a', '2013-01-02', 2),
(3, 'a', '2013-01-01', 3),
(4, 'b', '2013-01-01', 1),
(5, 'b', '2013-01-02', 4),
(6, 'b', '2013-01-03', 5),
(7, 'c', '2013-01-03', 4),
(8, 'c', '2013-01-03', 8)
SELECT id, [date] FROM (
SELECT id, [date], RANK() OVER( PARTITION BY category order by [date] desc) RNK from #T
) AS t
WHERE RNK = 1
Result:
id date
----------- ----------
1 2013-01-02
2 2013-01-02
6 2013-01-03
7 2013-01-03
8 2013-01-03

I would do this as by using subquery only :
select o.*
from order o
where date = (select max(o1.date)
from order o1
where o1.category = o.category
);

Related

Value in column to equal other column with conditions

Using SQL Server
The output I want: For the same values in column ID1, if there is a “null” in column ‘Value’ than make it equal to minimum(value) of that ID1.
I previously had a question relating to the following, although have still been unable to solve this!
Table 1
ID1
ID2
Value
1
1
0.1
1
2
2
1
3
null
2
5
0.2
2
5
null
3
7
6
Output I want
ID1
ID2
Value
1
1
0.1
1
2
2
1
3
0.1
2
5
0.2
2
5
0.2
3
7
6
you can use min() with window function
select ID1, ID2,
[Value] = coalesce(Value,
min(Value) over (partition by ID1))
from yourTable
WITH minimumValues AS (SELECT ID1, MIN(value) as value FROM table GROUP BY ID1)
SELECT
ID1,
ID2,
COALESCE( table1.Value, minimumValues.value) AS value
FROM table INNER JOIN
MinimumValues ON MinimumValues.ID1 = table.ID1
You can try the below to get the desired output -
Sample Table:
CREATE TABLE SampleData (
ID1 INT,
ID2 INT,
Value FLOAT
);
Sample Data:
INSERT INTO SampleData
(ID1, ID2, Value)
VALUES
(1, 1, 0.1),
(1, 2, 2),
(1, 3, NULL),
(2, 5, 0.2),
(2, 5, NULL),
(3, 7, 6);
Query:
WITH cte AS (
SELECT ID1, MIN(Value) AS MinValue
FROM SampleData
WHERE Value IS NOT NULL
GROUP BY ID1
)
SELECT t.ID1, t.ID2, COALESCE(t.Value, cte.MinValue) AS Value
FROM SampleData t
JOIN cte ON t.ID1 = cte.ID1

change data format from rows to columns

I have a SQL table in the below format. Every ID has 2 entries in the table for a particular date.
Input:
ID date rownum subid value1 value2
A 200911 1 X 10 20
A 200911 2 Y 15 25
B 201001 2 S 60 35
B 201001 1 R 40 50
I want to write a SQL query to change this to the below format, so that every ID/date combination has only 1 entry as shown below. The rownum is already included and the values should be represented so that rownnum 1 is displayed first and then the value with rownum second as shown below.
Output:
ID date row1subid row1value1 row1value2 row2subid row2value1 row2value2
A 200911 X 10 20 Y 15 25
B 201001 R 40 50 S 60 35
Let me know if something is not clear.
Thanks for all your help!
Here is what you need to do as a SQL Fiddle.
And for reference:
CREATE TABLE TestData
([ID] varchar(1),
[date] int,
[rownum] int,
[subid] varchar(1),
[value1] int,
[value2] int)
;
INSERT INTO TestData
([ID], [date], [rownum], [subid], [value1], [value2])
VALUES
('A', 200911, 1, 'X', 10, 20),
('A', 200911, 2, 'Y', 15, 25),
('B', 201001, 2, 'S', 60, 35),
('B', 201001, 1, 'R', 40, 50)
;
SELECT A.ID, A.date, A.rownum, A.subid, A.value1, A.value2, B.value1 AS r2value1, B.value2 AS r2value2
FROM TestData AS A
INNER JOIN TestData B ON A.id = B.id AND B.rownum = 2
WHERE A.rownum = 1

SQL sort and last record

this is my first post so pardon me if my question is not in it's appropriate places or tittle
I have a table like this
ID DATE Cat VALUE
-------------------------
1 07/07/2018 A 100
2 07/07/2018 A 200
3 07/07/2018 B 300
4 07/07/2018 B 400
5 07/07/2018 C 500
6 07/07/2018 C 600
7 08/07/2018 A 700
8 08/07/2018 A 800
9 08/07/2018 B 900
10 08/07/2018 B 110
11 08/07/2018 C 120
I would like to return
distinct category, sum of value, last record of the category
something like this
Cat sumValue lastrecord
--------------------------
A 1800 800
B 1710 110
C 1220 120
is it possible to do it in a single query
thanks
I am able to find the SUM
SELECT cat, SUM(value) FROM table GROUP BY cat;
and
find the last ID (autonumber key) using MAX
SELECT MAX(ID), cat FROM table GROUP BY cat;
but i just can't get the value for the last record
SQLFiddle
SELECT
t.cat,
SUM(t.value) as sumValue,
(
SELECT
t3.value
FROM
`table` t3
WHERE
t3.id = MAX(t2.id)
) as lastrecord
FROM
`table` t
JOIN
`table` t2 ON t.id = t2.id
GROUP BY
cat
EDIT shorter Version:
SELECT
t.cat,
SUM(t.value) as sumValue,
(SELECT value FROM `table` t2 WHERE t2.id = MAX(t.id)) lastValue
FROM
`table` t
GROUP BY
t.cat
This should do it
declare #t table (id int, cat char, value int);
insert into #t values
(1, 'A', 100),
(2, 'A', 200),
(3, 'B', 300),
(4, 'B', 400),
(5, 'C', 500),
(6, 'C', 600),
(7, 'A', 700),
(8, 'A', 800),
(9, 'B', 900),
(10, 'B', 110),
(11, 'C', 120);
select cat, value, sum
from
( select *
, sum(value) over (partition by cat) as sum
, ROW_NUMBER() over (partition by cat order by id desc) as rn
from #t
) tt
where tt.rn = 1
I hope you're looking for something like this,
Please replace the table name with your table name.
SELECT A.id,
A.cat,
A.date,
A.total_value,
A1.value
FROM (SELECT Max(id) AS id,
cat,
Max(date) AS Date,
Sum(value) AS Total_Value
FROM tbl_sof
GROUP BY cat) AS A
INNER JOIN tbl_sof A1
ON A.id = A1.id

Fluently adding values in t-sql

I have a table like this:
Items Date Price
1 2016-01-01 10
1 2016-01-02 15
1 2016-01-03 null
1 2016-01-04 null
1 2016-01-05 8
1 2016-01-06 null
1 2016-01-07 null
1 2016-01-08 null
2 2016-01-01 14
2 2016-01-02 7
2 2016-01-03 null
2 2016-01-04 null
2 2016-01-05 16
2 2016-01-06 null
2 2016-01-07 null
2 2016-01-08 5
Now I want to update the null values. The difference between the price before and after null values must be evenly added.
Example:
1 2016-01-02 15 to
1 2016-01-05 8
15 to 8 = -7
-7 / 3 = -2,333333
1 2016-01-02 15
1 2016-01-03 12,6666
1 2016-01-04 10,3333
1 2016-01-05 8
Shouldn't be made with cursors. Helptables would be OK.
This is really where you want the ignore nulls option on lag() and lead(). Alas.
An alternative is to use outer apply:
select t.*,
coalesce(t.price,
tprev.price +
datediff(day, tprev.date, t.date) * (tnext.price - tprev.price) / datediff(day, tprev.date, tnext.date)
) as est_price
from t outer apply
(select top 1 t2.*
from t t2
where t2.item = t.item and
t2.date <= t.date and
t2.price is not null
order by t2.date desc
) tprev outer apply
(select top 1 t2.*
from t t2
where t2.item = t.item and
t2.date >= t.date and
t2.price is not null
order by t2.date asc
) tnext ;
The complex arithmetic is just calculating the difference, dividing by the number of days, and then allocating the days to the current day.
WITH T1 AS
(
SELECT *,
ROW_NUMBER() OVER (PARTITION BY Items ORDER BY Date) AS RN,
FORMAT(ROW_NUMBER() OVER (PARTITION BY Items ORDER BY Date),'D10') + FORMAT(Price,'0000000000.000000') AS RnPr
FROM YourTable
), T2 AS
(
SELECT *,
MAX(RnPr) OVER (PARTITION BY Items ORDER BY Date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS prev,
MIN(RnPr) OVER (PARTITION BY Items ORDER BY Date ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) AS next
FROM T1
), T3 AS
(
SELECT Items,
Date,
Price,
RnPr,
InterpolatedPrice = IIF(Price IS NOT NULL,prevPrice,prevPrice + (RN - prevRN) * (nextPrice - prevPrice)/NULLIF(nextRN - prevRN,0))
FROM T2
CROSS APPLY (VALUES(CAST(SUBSTRING(prev,11,17) AS decimal(16,6)),
CAST(LEFT(prev, 10) AS INT),
CAST(SUBSTRING(next,11,17) AS decimal(16,6)),
CAST(LEFT(next, 10) AS INT)
)) V(prevPrice,prevRN,nextPrice,nextRN)
)
--UPDATE T3 SET Price = InterpolatedPrice
SELECT *
FROM T3
ORDER BY Items,
Date
Which returns
the row_number and price are bundled together in a single column (RnPr above). The order of RnPr is the same as the order by row_number. MIN and MAX both ignore NULLS. So finding the MAX(RnPr) between UNBOUNDED PRECEDING AND CURRENT ROW will include the value of the previous NOT NULL price if the price in the current row is null. And similarly MIN(RnPr) will find the next with a frame between CURRENT ROW AND UNBOUNDED FOLLOWING.
This can then be cracked apart to get the price and row number as above.
If happy with the results the final SELECT can be removed and the UPDATE uncommented as in this demo.
Just replace "YourTable" (4 of them) with your actual table name.
If you are happy with the results, then comment out the select and un-comment the UPDATE and WHERE.
Select A.Items,A.Date,
--Update YourTable Set
Price = IsNull(A.Price,((DateDiff(DD,B.Date,A.Date)/(DateDiff(DD,B.Date,C.Date)+0.0))*(C.Price - B.Price)) + B.Price)
From YourTable A
Outer Apply (Select Top 1 Date,Price from YourTable Where Items=A.Items and Date<A.Date and Price is not Null and A.Price is null Order by Price Desc) B
Outer Apply (Select Top 1 Date,Price from YourTable Where Items=A.Items and Date>A.Date and Price is not Null and A.Price is null Order by Price) C
--Where Price is NULL
Returns
Now, you'll notice nulls between 01/06 and 01/08 for Items 1. This is because there is no cap to interpolate with.
You can do this by using a series of window functions in common table expressions.
T1 assigns a row number to each row (rn)
T2 finds the first non null Price row number before and after the current row (rnb / rna)
T3 calculates the adjusted Price by looking up the prices before and after
declare #T table (Items int, Date date, Price float)
insert into #T (Items, Date, Price) values
(1, '2016-01-01', 10), (1, '2016-01-02', 15), (1, '2016-01-03', null), (1, '2016-01-04', null), (1, '2016-01-05', 8), (1, '2016-01-06', null), (1, '2016-01-07', null), (1, '2016-01-08', null), (2, '2016-01-01', 14), (2, '2016-01-02', 7), (2, '2016-01-03', null), (2, '2016-01-04', null), (2, '2016-01-05', 16), (2, '2016-01-06', null), (2, '2016-01-07', null), (2, '2016-01-08', 5)
;with T1 as
(
select *,
row_number() over (order by Items, Date) as rn
from #T
),
T2 as
(
select *,
max(case when price is null then null else rn end) over (partition by Items order by Date) as rnb,
min(case when price is null then null else rn end) over (partition by Items order by Date desc) as rna
from T1
)
select Items, Date,
isnull(price,
lag(Price, rn-rnb, Price) over (order by rn) -
(
lag(Price, rn-rnb, Price) over (order by rn) -
lead(Price, rna-rn, Price) over (order by rn)
) / (rna-rnb) * (rn-rnb)
) as Price
from T2
order by Items, Date

Get the latest records per Group By SQL

I have the following table:
CREATE TABLE orders (
id INT PRIMARY KEY IDENTITY,
oDate DATE NOT NULL,
oName VARCHAR(32) NOT NULL,
oItem INT,
oQty INT
-- ...
);
INSERT INTO orders
VALUES
(1, '2016-01-01', 'A', 1, 2),
(2, '2016-01-01', 'A', 2, 1),
(3, '2016-01-01', 'B', 1, 3),
(4, '2016-01-02', 'B', 1, 2),
(5, '2016-01-02', 'C', 1, 2),
(6, '2016-01-03', 'B', 2, 1),
(7, '2016-01-03', 'B', 1, 4),
(8, '2016-01-04', 'A', 1, 3)
;
I want to get the most recent rows (of which there might be multiple) for each name. For the sample data, the results should be:
id
oDate
oName
oItem
oQty
...
5
2016-01-02
C
1
2
6
2016-01-03
B
2
1
7
2016-01-03
B
1
4
8
2016-01-04
A
1
3
The query might be something like:
SELECT oDate, oName, oItem, oQty, ...
FROM orders
WHERE oDate = ???
GROUP BY oName
ORDER BY oDate, id
Besides missing the expression (represented by ???) to calculate the desired values for oDate, this statement is invalid as it selects columns that are neither grouped nor aggregates.
Does anyone know how to do get this result?
The rank window clause allows you to, well, rank rows according to some partitioning, and then you could just select the top ones:
SELECT oDate, oName, oItem, oQty, oRemarks
FROM (SELECT oDate, oName, oItem, oQty, oRemarks,
RANK() OVER (PARTITION BY oName ORDER BY oDate DESC) AS rk
FROM my_table) t
WHERE rk = 1
This is a generic query without using analytical function.
SQLFiddle Demo
SELECT a.*
FROM table1 a
INNER JOIN
(SELECT max(odate) modate,
oname,
oItem
FROM table1
GROUP BY oName,
oItem
)
b ON a.oname=b.oname
AND a.oitem=b.oitem
AND a.odate=b.modate
Add a primary key suppose id field to the table and make it auto increment,. Then order by id you will get it. It is the traditional way. By using your table you can only order by oDate. But is is having same date multiple times, so it also won't solve your problem.
I think you need a query like this:
SELECT *
FROM (SELECT *,
ROW_NUMBER() OVER (PARTITION BY oName ORDER BY oDate DESC) seq
FROM yourTable) t
WHERE (seq <= 2)
ORDER BY oDate;
You have to use ROW_NUMBER in following:
select oDate, oName, oItem, oQty, oRemarks
from (
select *, row_number() over(partition by oName, oItem order by oDate desc) rn
from #t
)x
where rn = 1
order by oDate
OUTPUT
oDate oName oItem oQty oRemarks
2016-01-01 A 001 2
2016-01-01 A 002 1 test
2016-01-02 C 001 2
2016-01-03 B 001 4
2016-01-03 B 002 1