SQL Server 2012 - updating a column based on row to row comparison - sql

I have a table that contains dates and times. For example columns are Date, ExTime, NewTime, Status. I am ordering them based on a expkey column that makes them show in the right order.
I want to do a row by row comparison and compare the second row column of extime to the first row column NewTime. If extime < Newtime then I want to update status with a "1". And then traverse through the table row by row where second row in the above example becomes the first and a new second is pull and used. Here is a sample of what I have now - but it is not hitting and working all all of the rows for some reason.
UPDATE t
SET t.Status = 1
FROM MyTable t
CROSS APPLY (SELECT TOP 1 NewTime
FROM MyTable
WHERE ID = t.ID AND [Date] = t.[Date]
ORDER BY ExpKey) t1
WHERE t.Extime < t1.NewTime
This is not hitting all the rows like I want it to. I have the where clause comparing fields ID and Date to insure that the rows are attached to the same person. If the ID or Dates are not the same it is not attached to the same person so I would not want to update the status. So basically if the ID of Row 2 = ID of Row 1 and Date of Row 2 = Date of Row 1 I want to compare extime of row 2 and see if it is less than newtime of Row 1 - if so then update the status field of row 2.
Any help in figuring out why this sort of works but not on all would be appreciated.
Ad.

On SQL Server 2012 you can easily update status with window function lag():
with cte as (
select
extime,
lag(newtime) over(partition by id, date order by expKey) as newtime,
status
from table1
)
update cte set status = 1 where extime < newtime;
sql fiddle demo

I haven't tested this, but I've dealt with similar issues of comparing adjacent rows. I put this together off-the-cuff, so it may need tweaking, but give it a try.
;WITH CTE AS
( SELECT ID,[Date],ExpKey,ExTime,NewTime,
ROW_NUMBER()OVER(PARTITION BY ID,[Date] ORDER BY ExpKey) AS Sort
FROM MyTable
)
UPDATE row2
SET row2.[Status] = 2
WHERE row2.ExTime < row1.NewTime
FROM CTE row2
CROSS JOIN CTE row1
ON row1.ID = row2.ID
AND row1.[Date] = row2.[Date]
AND row1.Sort = row2.Sort-1 --Join to prior row

Related

Need help in sql Query.neo

In this table there are three colum and in need the value for of data which are lesser than code = 28,this is my query
SELECT value,code,date
FROM table
order by date,vchcode
but when i ad where clouse like
SELECT value,code,date
FROM table
where code < 28
order by date,vchcode
is only shows 2 row with code 26 and 27... i need 26,27 and 32.. and table colums are variable its not fix..
I think you wnat to take the date into account -- what you really want are all rows before the date of the row with code 28.
One method uses a subquery:
SELECT t.value, t.code, t.date
FROM table t
WHERE date < (SELECT date FROM table t2 WHERE t2.code = 28)
ORDER BY t.date, t.vchcode

Get top 1 row for every ID

There is a few posts about it but i can't make it work...
I just want to select just one row per ID, something like row_number() over Partition in oracle but in access.
ty
SELECT a.*
FROM DATA as a
WHERE a.a_sku = (SELECT top 1 b.a_sku
FROM DATA as b
WHERE a.a_sku = b.a_sku)
but i get the same table Data out of it
Sample of table DATA
https://ibb.co/X4492fY
You should try below query -
SELECT a.*
FROM DATA as a
WHERE a.Active = (SELECT b.Active
FROM DATA as b
WHERE a.a_sku = b.a_sku
AND a.Active < b.Active)
If you don't care which record within each group of records with a matching a_sku values is returned, you can use the First or Last functions, e.g.:
select t.a_sku, first(t.field2), first(t.field3), ..., first(t.fieldN)
from data t
group by t.a_sku

How to PARTITION every 2nd record based on similar data?

I have a table like this...
What I am after is a way in SQL to achieve this...
The red line I don't need as I've effectively shifted the dates in 'end_date' column up by 1. ie: I want the row discarded or ignored
The dates are based on Start and End date - of the 2nd row or the next row with the FROMCODE and TOCODE opposite each other. So to explain better, what I am trying to do is GROUP BY every two rows there the FROMCODE = the TOCODE of the next row and for consistency, I want to make sure the TOCODE of the first row = the FROMCODE of the 2nd row, and so on.
I hope I am making myself clear.
I've tried using a recursive JOIN, to link the next row using the FROMCODE = TOCODE of the sub JOIN and TOCODE = FROMCODE of the subjoin, plus making sure the record has the same VOYAGE_ID and the RANK is greater than the 1st row's RANK. But all I get is gibberish.
You can use outer apply :
select t.*, tt.end_date as new_end_date
from table t outer apply (
select top 1 t1.end_date
from table t1
where t1.voyage_id = t.voyage_id and
t1.rank > t.rank
order by t1.rank
) tt
where tt.end_date is not null;
You can solve this using a left join -- assuming the ranks have no gaps:
select t.*,
tnext.end_date as new_end_date
from t join
t tnext
on tnext.voyage_id = t.voyage_id and tnext.rank = t.rank + 1;
Note that the join removes the last row as well as finds the next end date.

TSQL syntax to feed results into subquery

I'm after some help on how best to write a query that does the following. I think I need a subquery but I don't know how to use the data returned in the row to feed back into the subquery without hardcoding values? A subquery may not be the right thing here?
Ideally I only want 1 variable ...WHERE t_Date = '2018-01-01'
Desired Output:
The COUNT Criteria column has the following rules
Date < current row
Area = current row
Name = current row
Value = 1
For example, the first row indicates there are 2 records with Date < '2018-01-01' AND Area = 'Area6' AND Name = 'Name1' AND Value = 1
Example Data:
SQLFiddle: http://sqlfiddle.com/#!18/92ba3/4
Effectively I only want to return the first 2 rows but summarise the historic data into a column based on the output in that column.
The right way to do this is to use the cumulative sum functionality in ANSI SQL and SQL Server since 2012:
select t.*,
sum(case when t.value = 1 then 1 else 0 end) over (partition by t_area, t_name order by t_date)
from t;
This actually includes the current row. If you have only one row per date (for the area/name combo), then you can just subtract it or use a windowing clause:
select t.*,
sum(case when t.value = 1 then 1 else 0 end) over
(partition by t_area, t_name
order by t_date
rows between unbounded preceding and 1 preceding
)
from t;
Use a self join to find records in the same table that are related to a particular record:
SELECT t1.t_Date, t1.t_Area, t1.t_Name, t1.t_Value,
COUNT(t2.t_Name) AS COUNTCriteria
FROM Table1 as t1
LEFT OUTER JOIN Table1 as t2
ON t1.t_Area=t2.t_Area
AND t1.t_Name=t2.T_Name
AND t2.t_Date<t1.t_Date
AND t2.t_Value=1
GROUP BY t1.t_Date, t1.t_Area, t1.t_Name, t1.t_Value

SQL: Query new rows of a new date

i have table as shown here in this picture --> http://www.directupload.net/file/d/3710/lj7etq5j_png.htm
I need the correct Query to get only data_id 10.
The query should be like this: Compare the latest date rows (2014-08-08) with the earliest date rows (2014-08-06). If there is a row on 2014-08-08 which is NOT at 2014-08-06, this row should returned.
I already tried it with self-joins and Sub-Selects, but i did't get it work.
Thx for any help!
Maybe something like this is what you're looking for?
select * from Table1
where
data not in (
select data from Table1
where dataOfDate = (select min(dataofdate) from Table1)
)
and dataOfDate = (select max(dataofdate) from Table1)
The first where clause compares the data field of the returned rows to the data field in the set of oldest rows and the second where clause limits the set of rows the the newest.
Note that I'm only comparing rows based on thedatafield, so you might have to change the query if you want to includenextTableIdin the comparison.
Here is a sample SQL Fiddle.
How about something like this:
SELECT d1.* FROM Dates d1 LEFT JOIN Dates d2 ON d1.nextTableId = d2.nextTableId WHERE d1.dataofDate = '2014-08-08' AND d2.dataofDate = '2014-08-06' AND d2.data_id IS NULL;
SELECT `data_id`
FROM `my_table`
WHERE `dataOfDate` = (SELECT MAX(`dataOfDate`) FROM `my_table`)
AND `nextTableId` NOT IN (
SELECT `nextTableId` FROM `my_table` WHERE `dataOfDate` = (SELECT MIN(`dataOfDate`) FROM `my_table`)
)
select all rows with max date
that don't have values amongst rows with min date
edit ops, too late