Max date in SQL Server consultation - sql

I need to get the row with the maximum date by the ItemKey.
I need the whole row.
I have this table:
num | ItemKey | Serial | Qty | ItemName | Tdate
----+---------+--------+-----+----------+-------------------------
1 | 111 | 5 | 10 | AAA | 2010-03-25 00:00:00.000
2 | 111 | 0 | 12 | AAA | 2010-03-26 00:00:00.000
3 | 222 | 6 | 13 | BBB | 2010-03-25 00:00:00.000
4 | 222 | 2 | 11 | BBB | 2010-03-28 00:00:00.000
5 | 333 | 3 | 15 | CCC | 2010-03-25 00:00:00.000
6 | 333 | 4 | 16 | CCC | 2010-03-26 00:00:00.000
7 | 333 | 0 | 17 | CCC | 2010-03-27 00:00:00.000
I need to get this:
num | ItemKey | Serial | Qty | ItemName | Tdate
----+---------+--------+-----+----------+--------------------------
2 | 111 | 0 | 12 | AAA | 2010-03-26 00:00:00.000
4 | 222 | 2 | 11 | BBB | 2010-03-28 00:00:00.000
7 | 333 | 0 | 17 | CCC | 2010-03-27 00:00:00.000
I tried this SQL statement:
select *
from MyTBL
where Tdate = (select MAX(Tdate) from MyTBL)
But unfortunately it does not work
Thanks

you can use ROW_NUMBER to achieve this
SELECT * FROM (
select *,
ROW_NUMBER() OVER (PARTITION BY ItemKey ORDER BY Tdate DESC) as rn from MyTBL) AS T1
WHERE rn = 1
or in another way (using common table expressions)
WITH CTE_1 AS (
select *,ROW_NUMBER() OVER (PARTITION BY ItemKey ORDER BY Tdate DESC) as rn from MyTBL)
SELECT * FROM CTE_1 WHERE rn = 1

Just try like this;
select * from MyTBL M1 inner join
(select ItemName,max(Tdate) as Tdate from MyTBL group by ItemName) M2
ON M1.ItemName = M2.ItemName and M1.Tdate = M2.Tdate

SQL HERE
You can use this :
select t1.* from table_name t1
join (select ItemKey, max(Tdate) Tdate from table_name group by ItemKey) as t2
on t1.ItemKey=t2.ItemKey and t1.Tdate=t2.Tdate
order by t1.ItemKey

Try this
WITH t AS ( SELECT *,
RANK() OVER (PARTITION BY ItemName ORDER BY TDate DESC ) as myRank
from MyTBL)
SELECT [num], [ItemKey], [Serial], [Qty], [ItemName], [TDate] FROM t
WHERE t.myRank = 1
SQL fiddle

Related

Filtering out the data grouping by id and some condition

I have a requirement where I am getting data with Sql like below
someid | passengertype | somename |
--------+----------------+-----------
123 | 3 | abc |
123 | 6 | zxc |
111 | 4 | qwe |
111 | 6 | poi |
222 | 2 | lkj |
563 | 1 | uyt |
563 | 2 | mnb |
563 | 6 | oiu |
I want to select only records grouping by someid where passengertype not either 3 and 6. ie whenever for someid if passengertype contains only 3 or 6 then don't select that id, if 3 or 6 exists with other passengerid's then select. The required output should be:
someid | passengertype | somename |
--------+----------------+-----------
111 | 4 | qwe |
111 | 6 | poi |
222 | 2 | lkj |
563 | 1 | uyt |
563 | 2 | mnb |
563 | 6 | oiu |
You can use not exists . . . twice:
select t.*
from t
where not exists (select 1
from t t2
where t2.someid = t.someid and t2.passengertype = 3
) or
not exists (select 1
from t t2
where t2.someid = t.someid and t2.passengertype = 6
) ;
If you only wanted the someid values that meet this condition, then aggregation would be appropriate:
select someid
from t
group by someid
having sum(case when passengertype = 3 then 1 else 0 end) = 0 or
sum(case when passengertype = 6 then 1 else 0 end) = 0;
You can use the analytical function as dollows:
Select * from
(Select t.*,
Count(*) over (partition by id) as total_cnt,
Count(case when passenger_type in (3,6) then 1 end) over(partirion by id) as target_cnt
From your_table t) t
Where total_cnt != target_cnt

Fill table with last result

I have a table that contains the following information:
id | amount | date | customer_id
1 | 0.00 | 11/12/17 | 1
2 | 54.00 | 11/12/17 | 1
3 | 60.00 | 02/12/18 | 1
4 | 0.00 | 01/18/17 | 2
5 | 14.00 | 03/12/17 | 2
6 | 24.00 | 02/22/18 | 2
7 | 0.00 | 09/12/16 | 3
8 | 74.00 | 10/01/17 | 3
What I need it to look like is the following:
ranked_id | id | amount | date | customer_id
1 | 1 | 0.00 | 11/12/17 | 1
2 | 2 | 54.00 | 11/12/17 | 1
3 | 3 | 60.00 | 02/12/18 | 1
4 | 3 | 60.00 | 02/12/18 | 1
5 | 3 | 60.00 | 02/12/18 | 1
6 | 3 | 60.00 | 02/12/18 | 1
7 | 3 | 60.00 | 02/12/18 | 1
8 | 4 | 0.00 | 01/18/17 | 2
9 | 5 | 14.00 | 03/12/17 | 2
10 | 6 | 24.00 | 02/22/18 | 2
11 | 6 | 24.00 | 02/22/18 | 2
12 | 6 | 24.00 | 02/22/18 | 2
13 | 6 | 24.00 | 02/22/18 | 2
14 | 6 | 24.00 | 02/22/18 | 2
15 | 7 | 0.00 | 09/12/16 | 3
16 | 8 | 74.00 | 10/01/17 | 3
17 | 8 | 74.00 | 10/01/17 | 3
18 | 8 | 74.00 | 10/01/17 | 3
19 | 8 | 74.00 | 10/01/17 | 3
20 | 8 | 74.00 | 10/01/17 | 3
21 | 8 | 74.00 | 10/01/17 | 3
I know that there's something with partitioning and ranking (on the ranked_id), but I can't figure out how to repeat the last row 7 times.
As #Gordon Linoff suggested you can use the generate_series() function crossed with the distinct customer_ids to generate all the rows needed as in T1 below. Then in T2 (also below) the row_number function is used to generate a sequential value to outer join to from t1 along with the customer_id.
From there it's just a matter of being able to get at the last value per customer_id when there is no original data to join to which is where the case statement and analytic first_value functions come in. I couldn't get the last_value analytic function to work likely due to postgresql's lack of an ignore nulls directive, so I used first_Value with a descending sort order, and only return the analytic value when no other data exists.
with t1 as (
select distinct
dense_rank() over (order by customer_id, generate_series) ranked_id
, customer_id
, generate_series
from table1
cross join generate_series(1,7)
), t2 as (
select row_number() over (partition by customer_id order by id) rn
, table1.*
from table1
)
select t1.ranked_id
, case when t2.customer_id is not null
then t2.id
else first_value(t2.id)
over (partition by t1.customer_id
order by id desc nulls last)
end id
, case when t2.customer_id is not null
then t2.amount
else first_value(t2.amount)
over (partition by t1.customer_id
order by id desc nulls last)
end amount
, case when t2.customer_id is not null
then t2.date
else first_value(t2.date)
over (partition by t1.customer_id
order by id desc nulls last)
end date
, t1.customer_id
from t1
left join t2
on t2.customer_id = t1.customer_id
and t2.id = t1.generate_series
order by ranked_id;
Here's a SQL Fiddle demonstrating the code.
In Postgres, you can use generate_series() and a cross join to generate all the rows. Then you can pick the one you want:
select row_number() over (order by customer_id, id) as ranking_id,
coalesce(t.id, cid) as id, coalesce(t.amount, c.amount) as amount
coalesce(t.date, c.date) as date, t.customer_id
from (select distinct on (customer_id) t.*
from t
order by customer_id, date desc
) c cross join
generate_series(1, 7) g(i) left join
(select t.*, row_number() over (partition by customer_id order by date) as i
from t
) t
on t.customer_id = c.customer_id and t.i = g.i;

Select most recent inspection

I have a ROAD_INSPECTION table:
+----+------------------------+-----------+
| ID | DATE | CONDITION |
+----+------------------------+-----------+
| 1 | 01/01/2009 | 20 |
| 1 | 05/01/2013 | 16 |
| 1 | 04/29/2016 10:02:52 AM | 15 |
+----+------------------------+-----------+
| 2 | 01/01/2009 | 8 |
| 2 | 06/06/2012 9:55:13 AM | 8 |
| 2 | 04/28/2015 | 11 |
+----+------------------------+-----------+
| 3 | 06/11/2012 | 10 |
| 3 | 04/21/2015 | 19 |
+----+------------------------+-----------+
What is the most efficient way to select the most recent inspection? The query would need to include the ID and CONDITION columns, despite the fact that they wouldn't group by cleanly:
+----+------------------------+-----------+
| ID | DATE | CONDITION |
+----+------------------------+-----------+
| 1 | 04/29/2016 10:02:52 AM | 15 |
+----+------------------------+-----------+
| 2 | 04/28/2015 | 11 |
+----+------------------------+-----------+
| 3 | 04/21/2015 | 19 |
+----+------------------------+-----------+
One way could be to retrieve id and date column in derived table and join the output to the main table to retrieve corresponding data from condition column as below.
SELECT t1.id,
t1.date1,
t2.CONDITION1
FROM
(SELECT id,
max(date1) AS date1
FROM table1
GROUP BY id) t1
JOIN table1 t2 ON t1.id = t2.id
AND t1.date1 = t2.date1;
Result:
id date1 CONDITION1
-------------------------------------
1 29.04.2016 10:02:52 15
2 28.04.2015 00:00:00 11
3 21.04.2015 00:00:00 19
DEMO
OR if your rdbms supports windows function, use below.
SELECT id,
date1,
condition1
FROM
(SELECT id,
date1,
condition1,
row_number() over(PARTITION BY id
ORDER BY date1 DESC) AS rn
FROM table1 ) t1
WHERE rn = 1;
DEMO

SQL Row_Number() not sorting dates

I have a query in which I am trying to get the most recent date from my ROW_NUMBER() selection. I have tried both MAX() and DESC in my ORDER BY clause. It does not show the most recent date as RowNum 1.
This is my query:
;WITH cte3 AS
(
SELECT
o.PartNo,
o.JobNo,
MAX(tt.TicketDate) as rawr,
ROW_NUMBER() OVER (PARTITION BY o.JobNo, o.PartNo
ORDER BY tt.TicketDate DESC) as RowNum
FROM
OrderDet AS o
INNER JOIN
TimeTicketDet AS tt ON o.JobNo = tt.JobNo
WHERE
o.Status = 'Open'
GROUP BY
tt.TicketDate, o.JobNo, o.PartNo
)
SELECT *
FROM cte3
When I get it giving me the correct results, I will add a WHERE RowNum = 1 in the cte query.
With my current query, this is the result:
+--------+-------+-----------+--------+
| PartNo | JobNo | rawr | RowNum |
+--------+-------+-----------+--------+
| 1234 | 20 | 5/30/2012 | 1 |
| 1234 | 20 | 5/29/2012 | 2 |
| 1234 | 20 | 5/25/2012 | 3 |
| 1234 | 20 | 5/24/2012 | 4 |
| 1234 | 20 | 5/23/2012 | 5 |
| 1234 | 20 | 5/22/2012 | 6 |
| 1234 | 20 | 5/16/2012 | 7 |
| 1234 | 20 | 5/15/2012 | 8 |
| 1234 | 20 | 5/14/2012 | 9 |
| 1234 | 20 | 5/11/2012 | 10 |
| 1234 | 20 | 5/10/2012 | 11 |
| 1234 | 20 | 5/9/2012 | 12 |
| 1234 | 20 | 3/27/2015 | 13 |
| 1234 | 20 | 1/3/2013 | 14 |
| 1234 | 20 | 1/2/2013 | 15 |
+--------+-------+-----------+--------+
RowNum = 13 is the most recent date. Am I organizing my sorts incorrectly or incorrectly converting my dates?
EDIT:
TimeTicketDet Table Sample Data:
+------------+-------+
| TicketDate | JobNo |
+------------+-------+
| 5/9/2012 | 20 |
| 5/10/2012 | 20 |
| 5/24/2012 | 20 |
| 3/27/2015 | 20 |
| 5/22/2012 | 20 |
| 5/10/2012 | 20 |
| 5/11/2012 | 20 |
| 5/9/2012 | 100 |
| 5/10/2012 | 100 |
| 5/24/2012 | 100 |
| 3/27/2015 | 100 |
| 5/22/2012 | 100 |
| 5/10/2012 | 100 |
| 5/11/2012 | 100 |
+------------+-------+
OrderDet Table Sample Data:
+--------+--------+-------+
| PartNo | Status | JobNo |
+--------+--------+-------+
| 1234 | Open | 20 |
| 1234 | Open | 100 |
+--------+--------+-------+
Desired Result:
+--------+------------+-------+--------+
| PartNo | TicketDate | JobNo | RowNum |
+--------+------------+-------+--------+
| 1234 | 3/27/2015 | 20 | 1 |
| 1234 | 3/27/2015 | 100 | 1 |
+--------+------------+-------+--------+
As I mentioned in my comment, since your TicketDate column is a char, you need to convert it to a datetime in order to sort it by actual date. Right now, you are sorting it by string value which isn't correct.
I'd recommend changing your query to something like this:
;WITH cte3 AS
(
SELECT
o.PartNo,
o.JobNo,
MAX(tt.TicketDate) as rawr,
ROW_NUMBER() OVER (PARTITION BY o.JobNo, o.PartNo
ORDER BY cast(tt.TicketDate as datetime) DESC) as RowNum
FROM
OrderDet AS o
INNER JOIN
TimeTicketDet AS tt ON o.JobNo = tt.JobNo
WHERE
o.Status = 'Open'
GROUP BY
cast(tt.TicketDate as datetime), o.JobNo, o.PartNo
)
SELECT *
FROM cte3
where RowNum = 1;
Here is a demo. By casting your char to a datetime in your row_number you will be sorting the data by date instead of string.
Additionally, you don't really need the max() and the GROUP BY since by casting the TicketDate to a datetime you will return the correct row:
;WITH cte3 AS
(
SELECT
o.PartNo,
o.JobNo,
tt.TicketDate as rawr,
ROW_NUMBER() OVER (PARTITION BY o.JobNo, o.PartNo
ORDER BY cast(tt.TicketDate as datetime) DESC) as RowNum
FROM
#OrderDet AS o
INNER JOIN
#TimeTicketDet AS tt ON o.JobNo = tt.JobNo
WHERE
o.Status = 'Open'
)
SELECT *
FROM cte3
where RowNum =1;
As Ollie suggest you can CAST your string to DATETIME And you dont need the additional Group By
SQL DEMO
;WITH cte3 AS
(
SELECT
o.PartNo,
o.JobNo,
tt.TicketDate as rawr,
ROW_NUMBER() OVER (PARTITION BY o.JobNo, o.PartNo
ORDER BY cast(tt.TicketDate as datetime) DESC) as RowNum
FROM OrderDet AS o
JOIN TimeTicketDet AS tt
ON o.JobNo = tt.JobNo
WHERE
o.Status = 'Open'
)
SELECT *
FROM cte3
WHERE RowNum = 1
OUTPUT

SQL select values sum same ID

This is my Table called "SAM"
ID | S_Date | S_MK | TID | Value |
===============================================
1 | 2012-12-11 | 1 | 112 | 23 |
2 | 2012-12-11 | 2 | 112 | 3 |
3 | 2012-12-11 | 1 | 113 | 22 |
4 | 2012-12-11 | 3 | 114 | 2 |
This should be my expected result: sum of column "Value" with the same T_ID:
S_Date | TID | sum(Value)|
===============================
2012-12-11 | 112 | 26 |
2012-12-11 | 113 | 22 |
2012-12-11 | 114 | 2 |
select S_Date, TID, sum(Value)
from SAM
group by S_Date, TID
If you really need this result set, with grouping only by T_ID, you can use this query:
SELECT (SELECT top 1 S_Date FROM SAM as t1 WHERE t1.TID = t2.TID) as S_Date,
TID,
SUM(Value)
FROM SAM as t2
GROUP BY TID
You have to use aggregate function "sum" for the sum of value column.
select S_Date ,TID, Sum(Value) from Sam group by S_Date, TID
Further more you should include all the column in group by clause that you used in select statement.
SELECT *, SUM(Value) AS Value From SAM GROUP BY TID
This will return the same table by summing up the Value column of the same TID column.