Find out the last updated record in my DB using MAX in CASE statement - sql

I have APPLICATIONSTATUSLOG_ID primary key field on my table.
In order to find out the last updated record in my DB and the MAX(APPLICATIONSTATUSLOG_ID) is presumed to be the most recent record.
I tried this code :
SELECT
MAX(CASE WHEN MAX(d.ApplicationStatusLog_ID) = d.ApplicationStatusLog_ID THEN d.ApplicationStatusID END) AS StatusID,
FROM
ApplicationStatusLog d
But I get error:
Msg 130, Level 15, State 1, Line 53 Cannot perform an aggregate function on an expression containing an aggregate or a subquery.
My table looks like
ApplicationID - ApplicationStatusID - ApplicationStatusLogID
10000 17 100
10000 08 101
10000 10 102
10001 06 103
10001 10 104
10002 06 105
10002 07 106
My output should be:
10000 10
10001 10
10002 07
Please help me understand and resolve my problem.

If you want to just find the last updated row, given that it has max value in APPLICATIONSTATUSLOG_ID column. The query would be:
SELECT *
FROM ApplicationStatusLog
WHERE ApplicationStatusLog_ID = (SELECT MAX(ApplicationStatusLog_ID) FROM ApplicationStatusLog )
EDIT
So as you stated in comment, the query for it will be:
DECLARE #statusId INT
SELECT #statusId = STATUSID
FROM ApplicationStatusLog
WHERE ApplicationStatusLog_ID = (SELECT MAX(ApplicationStatusLog_ID) FROM ApplicationStatusLog )
EDIT 2:
The query as per your edit in question will be:
WITH C AS
(
SELECT ApplicationID,ApplicationStatusID,ApplicationStatusLogID, ROW_NUMBER() OVER (PARTITION BY ApplicationID ORDER BY ApplicationStatusLogID DESC) AS ranking
FROM ApplicationStatusLog
)
SELECT ApplicationID,ApplicationStatusID
FROM C
WHERE ranking = 1

You can join same table twice like this:
select IT.JoiningID, JT.MAXAPPLICATIONSTATUSID FROM dbo.[Table] IT
INNER JOIN (
Select JoiningID, MAX (APPLICATIONSTATUSID) MAXAPPLICATIONSTATUSID
FROM dbo.[Table]
GROUP BY JoiningID
) JT ON IT.JoiningID = JT.JoiningID
Now you have MAXAPPLICATIONSTATUSID per ID so you can write what you wand based on MAXAPPLICATIONSTATUSID.

Without full query
SELECT
x.StatusId
...
FROM <Table> a
CROSS APPLY
(
SELECT x.APPLICATIONSTATUSID as StatusId
FROM <Table> x
HAVING MAX(APPLICATIONSTATUSLOG_ID) = a.APPLICATIONSTATUSLOG_ID
GROUP BY x.APPLICATIONSTATUSID
)

Related

How can I select rows where number went down as date went up

If I have a program at a repair shop and I want to select all of the cars in my RepairOrder table where the mileage of the later repair order is less than the mileage of the prior repair order, how can I build that select statement?
ID VehicleID Mileage RepairDate
01 1 18425 2013-08-13
02 1 28952 2013-02-26
03 2 22318 2012-08-27
04 3 21309 2012-08-07
05 3 16311 2012-02-27
06 3 16310 2012-02-11
07 4 11098 2011-03-23
08 5 21309 2012-08-07
09 5 16309 2012-02-27
10 5 16310 2012-02-11
In this case I should only be selecting VehicleID 1 because it has a RepairDate that is greater then the previous row, but a Mileage that is less than the previous row. There could also be 3 rows with the same vehicle and the middle date has a mileage of 3 or 5000000, and I will need to select those VehicleID's as well.
Results from using the LEAD() function
ID RepairDate Mileage
25 2011-12-23 45934
48 2009-02-26 13
48 2009-04-24 10
71 2011-07-26 31163
71 2015-01-13 65656
This is a great place to use LEAD() function for sql 2014+
SQL FIDDLE DEMO
WITH NextM as (
SELECT
* ,
LEAD(Mileage, 1, null) over (partition by VehicleID order by RepairDate) NextMileage
FROM RepairOrder
)
SELECT *
FROM NextM
WHERE Mileage > NextMileage
My solution show all columns so you can check what row have the problem.
Also I avoid using distinct because as OP suggest there may be several mistake for same car and this way you can see it all.
It's not terribly efficient, but you could do a pairwise selection
select t1.VehicleID
from table t1, table t2
where t1.VehicleId = t2.VehicleId
AND t1.Mileage > t2.Mileage
AND t1.RepairDate < t2.RepairDate
There is likely a better solution as pair-wise selections get EXTREMELY SLOW, but this should work as-is.
select distinct RO.VehicleID
from RepairOrder RO
where exists(select *
from RepairOrder
where ID != RO.ID
and VehicleID = RO.VehicleID and RepairDate > RO.RepairDate
and Mileage < RO.Mileage);
WITH RepairSeqs AS(
SELECT
DateSeq = Row_Number OVER (PARTITION BY VehicleID ORDER BY RepairDate),
MileageSeq = Row_Number OVER (PARTITION BY VehicleID ORDER BY Mileage),
*
FROM
dbo.RepairOrder
)
SELECT *
FROM RepairSeqs
WHERE DateSeq <> MileageSeq;
select distinct t.VehicleId
from (
select t.*, LEAD(Mileage) OVER (Partition by VehicleId ORDER BY RepairDate) LeadMileageValue
from RepairOrder t
) t
where t.Mileage > t.LeadMileageValue

SQL query - Difference between the values from two rows and two columns

I am struggling to get this working, using T-SQL Query (SQL SERVER 2008) for the following problem:
Ky ProductID Start # End # Diff
1 100 10 12 0
2 100 14 20 2 (14 - 12)
3 100 21 25 1 (21 - 20)
4 100 30 33 5 (30 - 25)
1 110 6 16 0
2 110 20 21 4 (20 - 16)
3 110 22 38 1 (22 - 21)
as you can see I need the difference between values in two different rows and two columns.
I tried
with t1
( select ROW_NUMBER() OVER (PARTITION by ProductID ORDER BY ProductID, Start# ) as KY
, productid
, start#
, end#
from mytable)
and
select DATEDIFF(ss, T2.complete_dm, T1.start_dm)
, <Keeping it simple not including all the columns which I selected..>
FROM T1 as T2
RIGHT OUTER JOIN T1 on T2.Ky + 1 = T1.KY
and T1.ProductID = T2.ProductID
The problem with the above query is when the productID changes from 100 to 110 still it calculates the difference.
Any help in modifying the query or any simpler solution much appreciated.
Thanks
You can try below code for the required result :
select ky,Start,[End],(select [end] from table1 tt where (tt.ky)=(t.ky-1) and tt.ProductID=t.ProductID) [End_Prev_Row],
case ky when 1 then 0
else (t.start -(select [end] from table1 tt where (tt.ky)=(t.ky-1) and tt.ProductID=t.ProductID))
end as Diff
from table1 t
SQL FIDDLE
Try something like that. It should give you the difference you want. I'm getting the first row for each product in the first part and then recursively build up by using the next Ky.
with t1
as
(
select ProductID, Ky, 0 as Difference, [End#]
from mytable where ky = 1
union all
select m.ProductID, m.Ky, m.[Start#] - t1.[End#] as Difference, m.[End#]
from mytable m
inner join t1 on m.ProductID = t1.ProductID and m.Ky = t1.Ky + 1
)
select Ky, ProductID, Difference from t1
order by ProductID, Ky
As Anup has mentioned, your query seems to be working fine, I just removed DateDiff to calculate the difference, as I assume columns are not of DATE datatype from your example, I guess that was the issue, please find below the modified query
with t1
as
( select ROW_NUMBER() OVER (PARTITION by ProductID ORDER BY ProductID ) as KY
, productid
, st
, ed
from YourTable)
select T1.ProductID, t1.ST,t1.ED, ISNULL(T1.st - T2.ed,0) as Diff
FROM T1 as T2
RIGHT OUTER JOIN T1 on T2.KY+1 = T1.KY
and T1.ProductID = T2.ProductID
SELECT ROW_NUMBER() OVER (PARTITION by rc.ContractID ORDER BY rc.ID) AS ROWID,rc.ID,rc2.ID,rc.ContractID,rc2.ContractID,rc.ToDate,rc2.FromDate
FROM tbl_RenewContracts rc
LEFT OUTER JOIN tbl_RenewContracts rc2
ON rc2.ID = (SELECT MAX(ID) FROM tbl_RenewContracts rcs WHERE rcs.ID < rc.ID AND rcs.ContractID = rc.ContractID)
ORDER BY rc.ContractID
Replace your table name and columns and add calculated column to get the DATEDIFF.

Select min values for an id and for entire table in ONE query

I want to find the lowest visited value for a specific id AND the lowest for entire table.
In one query.
MyTab
ID VISITED
101 2009
102 2010
103 2011
104 2012
105 2013
Can I do it in one query?
Right now I do like:
select
min(visited)
from
mytab
where
id = 100;
and then I do the second query.
select
min(visited)
from
mytab;
What I want is something like below (but can one make it more simple?)
select
min( a.visited ),
min( b.visited )
from
(select visited from mytab where id=100) as a,
(select visited from mytab) as b;
Query run for e.g. id 103 and 100 would be:
id 103 will give 2011,2009
id 100 will give null,2009
Thanks
You can use MIN with CASE:
select
min(case when id = 100 then visited end) minbyid,
min(visited) minoverall
from mytab
SQL Fiddle Demo
select min(visited) as GlobalMin
, min(case when id = 100 then visited end) as MinForId100
from mytab

Selecting and sorting data from a single table

Correction to my question....
I'm trying to select and sort in a query from a single table. The primary key for the table is a combination of a serialized number and a time/date stamp.
The table's name in the database is "A12", the columns are defined as:
Serial2D (PK, char(25), not null)
Completed (PK, datetime, not null)
Result (smallint, null)
MachineID (FK, smallint, null)
PT_1 (float, null)
PT_2 (float, null)
PT_3 (float, null)
PT_4 (float, null)
Since the primary key for the table is a combination of the "Serial2D" and "Completed", there can be multiple "Serial2D" entries with different values in the "Completed" and "Result" columns. (I did not make this database... I have to work with what I got)
I want to write a query that will utilize the value of the "Result" column ( always a "0" or "1") and retrive only unique rows for each "Serial2D" value. If the "Result" column has a "1" for that row, I want to choose it over any entries with that Serial that has a "0" in the Result column. There should be only one entry in the table that has a Result column entry of "1" for any Serial2D value.
Ex. table
Serial2d Completed Result PT_1 PT_2 PT_3 PT_4
------- ------- ------ ---- ---- ---- ----
A1 1:00AM 0 32.5 20 26 29
A1 1:02AM 0 32.5 10 29 40
A1 1:03AM 1 10 5 4 3
B1 1:04AM 0 29 4 1 9
B1 1:05AM 0 40 3 4 9
C1 1:06AM 1 9 7 6 4
I would like to be able to retrieve would be:
Serial2d Completed Result PT_1 PT_2 PT_3 PT_4
------- ------- ------ ---- ---- ---- ----
A1 1:03AM 1 10 5 4 3
B1 1:05AM 0 40 3 4 9
C1 1:06AM 1 9 7 6 4
I'm new to SQL and I'm still learning ALL the syntax. I'm finding it difficult to search for the correct operators to use since I'm not sure what I need, so please forgive my ignorance. A post with my answer could be staring me right in the face and i wouldn't know it, please just point me to it.
I appreciate the answers to my previous post, but the answers weren't sufficient for me due to MY lack of information and ineptness with SQL. I know this is probably insanely easy for some, but try to remember when you first started SQL... that's where I'm at.
Since you are using SQL Server, you can use Windowing Functions to get this data.
Using a sub-query:
select *
from
(
select *,
row_number() over(partition by serial2d
order by result desc, completed desc) rn
from a12
) x
where rn = 1
See SQL Fiddle with Demo
Or you can use CTE for this query:
;with cte as
(
select *,
row_number() over(partition by serial2d
order by result desc, completed desc) rn
from a12
)
select *
from cte c
where rn = 1;
See SQL Fiddle With Demo
You can group by Serial to get the MAX of each Time.
SELECT Serial, MAX([Time]) AS [Time]
FROM myTable
GROUP BY Serial
HAVING MAX(Result) => 0
SELECT
t.Serial,
max_Result,
MAX([time]) AS max_time
FROM
myTable t inner join
(SELECT
Serial,
MAX([Result]) AS max_Result
FROM
myTable
GROUP BY
Serial) m on
t.serial = m.serial and
t.result = m.max_result
group by
t.serial,
max_Result
This can be solved using a correlated sub-query:
SELECT
T.serial,
T.[time],
0 AS result
FROM tablename T
WHERE
T.result = 1
OR
NOT EXISTS(
SELECT 1
FROM tablename
WHERE
serial = T.serial
AND (
[time] > T.[time]
OR
result = 1
)
)

Query to select last order (entry) of every product belonging to user that's not returned

I am stuck with rather confusing query.
Assume I have a ProductLending table that tracks what product each user has borrowed, when it was renewed, was it returned or not etc.. Given a user, I want to be able to select, all unique products that are still with the user.
table example:
userid DateRenewed ProductId isReturned
````````````````````````````````````````````````
1 2011-07-21 15 0
1 2011-08-20 16 0
1 2011-09-21 15 1
2 2011-09-21 17 0
1 2011-09-21 15 0
This is a mock up so sorry if it's not accurate.
Now, given userId = 1, I want to select just unique productId that are NOT returned, but are with the user. So this should give me 15, 16 as result, as even though 15 was returned, it was re-borrowed. If we delete the last row, then the result would just be 16, since user has only 16 with him.
I tried ordering by dateRenewed and selecting top 1 but it did totally something else.. how do I construct a query for this please?
If product is not returned by user, then the sum of bought products must be larger than sum of returned products
SELECT userid,ProductId FROM <table>
GROUP BY userid,ProductId HAVING SUM(CASE CAST(isReturned AS INT) WHEN 0 THEN 1 ELSE 0 END)-SUM(CAST(isReturned AS INT))>0
Try this:
;WITH qry AS
(
SELECT *,
ROW_NUMBER() OVER(PARTITION BY userID, ProductID ORDER BY DateRenewed DESC) rn
FROM YourTable
)
SELECT *
FROM qry
WHERE rn = 1 AND isReturned = 0;
select distinct ProductId
from TABLE_NAME t1
where UserId= #UserId
and IsReturned = 0
and not exists
(
select *
from TABLE_NAME t2
where t2.UserId = t1.UserId
and t2.ProductId = t1.ProductId
and t2.IsReturned = 1
and t2.DateRenewed > t1.DateRenewed
)