Table not updating in single select query - sql

i have a temporary table which i need to update, the first row is updated but the second row updates as null , please help
declare #T Table
(
ID int,
Name nvarchar(20),
rownum int
)
insert into #T(ID,rownum)
select ID, rownum = ROW_NUMBER() OVER(order by id) from testtabel4
select * from testtabel4
update #t
set Name=case when rownum>1 then (select top 1 Name from #T x where x.rownum=(y.rownum-1))
else 'first' end
from #t y
select * from #T
and here the definition of testtabel4
CREATE TABLE [dbo].[testtabel4](
[ID] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](80) NULL,
PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
and here is the output
ID Name
1 first
2 NULL

I think your update would be better written with lag() and an updateable CTE.
with cte as (
select name, lag(name, 1, 'first') over(order by rownum) lag_name
from #t
)
update cte set name = lag_name
With this technique at hand, it is plain to see that don't actually need to feed the table first, then insert into it. You can do both at once, like so:
insert into #t (id, name, rownum)
select
id,
lag(name, 1, 'first') over(order by id),
row_number() over(order by id)
from testtabel4
I am not sure that you even need rownum column anymore, unless it is needed for some other purpose.

You are only inserting two columns in the #T:
insert into #T (ID, rownum)
select ID, ROW_NUMBER() OVER (order by id)
from testtabel4;
You are not inserting name so it is NULL on all rows. Hence, the then part of the case expression will always be NULL.

Related

How to convert Rows to Columns in Sql

I've a table Columns
and a second table Response in which all data is saved.
Now I want to create a SQL View in which the result should be like this
I tried using pivot
select UserId ,FromDate, ToDate, Project, Comment
from
(
select R.UserId ,R.Text , C.ColumnName
from [Columns] C
INNER JOIN Response R ON C.Id=R.ColumnId
) d
pivot
(
max(Text)
for ColumnName in (FromDate, ToDate, Project, Comment)
) piv;
but that didn't worked for me, I also referred this Efficiently convert rows to columns in sql server but was not able to implement it. Any ideas how to achieve the same in SQL View?
Scripts for Tables:
CREATE TABLE [dbo].[Columns](
[Id] [bigint] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](1000) NULL,
[IsActive] [bit] NULL,
CONSTRAINT [PK_Columns] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
insert into [Columns] values('FromDate',1)
insert into [Columns] values('ToDate',1)
insert into [Columns] values('Project',1)
insert into [Columns] values('Comment',1)
CREATE TABLE [dbo].[Response](
[Id] [bigint] IDENTITY(1,1) NOT NULL,
[UserId] [bigint] NOT NULL,
[ColumnId] [bigint] NOT NULL,
[Text] [nvarchar](max) NULL,
[IsActive] [bit] NULL,
CONSTRAINT [PK_Response] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
insert into [Response] values(1,1,'1/1/2012',1)
insert into [Response] values(1,2,'1/2/2012',1)
insert into [Response] values(1,3,'p1',1)
insert into [Response] values(1,4,'c1',1)
insert into [Response] values(2,1,'1/1/2013',1)
insert into [Response] values(2,2,'1/2/2013',1)
insert into [Response] values(2,3,'p2',1)
insert into [Response] values(2,4,'c2',1)
insert into [Response] values(2,1,'1/1/2014',1)
insert into [Response] values(2,2,'1/2/2014',1)
insert into [Response] values(2,3,'p3',1)
insert into [Response] values(2,4,'c3',1)
insert into [Response] values(3,1,'1/1/2015',1)
insert into [Response] values(3,2,'1/2/2015',1)
insert into [Response] values(3,3,'p4',1)
insert into [Response] values(3,4,'c4',1)
Honestly, if the column types aren't going to change, or you only need a subset of them, you could just filter them out and then join on them rather than write a pivot. I wrote it using a cte, but they could just as easily be sub-queries:
;with fd as
(
select
UserID,
[Text] as FromDate,
row_number() over (partition by userID order by ID) as DEDUP
from response
where ColumnID = 1
),
td as
(
select
UserID,
[Text] as ToDate,
row_number() over (partition by userID order by ID) as DEDUP
from response
where ColumnID = 2
),
p as
(
select
UserID,
[Text] as Project,
row_number() over (partition by userID order by ID) as DEDUP
from response
where ColumnID = 3
),
c as
(
select
UserID,
[Text] as Comment,
row_number() over (partition by userID order by ID) as DEDUP
from response
where ColumnID = 4
)
select
fd.*,
td.ToDate,
p.Project,
c.Comment
from fd
inner join td
on fd.UserId = td.UserId
and fd.DEDUP = td.DEDUP
inner join p
on fd.UserId = p.UserId
and fd.DEDUP = p.DEDUP
inner join c
on fd.UserId = c.UserId
and fd.DEDUP = c.DEDUP
Try this. I worked on your answer.
select UserId ,FromDate, ToDate, Project, Comment
from
(
select R.UserId ,R.RText , C.ColumnName
from [Columns] C
INNER JOIN Response R ON C.Id=R.ColumnId
) d
pivot
(
Min(Rtext)
for ColumnName in (FromDate, ToDate, Project, Comment)
) piv
UNION
select UserId ,FromDate, ToDate, Project, Comment
from
(
select R.UserId ,R.RText , C.ColumnName
from [Columns] C
INNER JOIN Response R ON C.Id=R.ColumnId
) d
pivot
(
Max(Rtext)
for ColumnName in (FromDate, ToDate, Project, Comment)
) piv;
You can query like this
;with cte as
(
select r.*,
c.name
from Response r
inner join Columns c
on r.columnid = c.id
)
select
Userid,
max([FromDate]) as [FromDate],
max([ToDate]) as [ToDate],
max([Project]) as [Project],
max([Comment]) as [Comment]
from cte
pivot
(
max(Text) for name in ([FromDate], [ToDate], [Project], [Comment])
) p
group by userid

Select Data with Order By Respecting Ancestor

I have a table MyStackFiles that has 3 columns:
FileID (The primary key)
FileName
OriginalFileID (This can be either 0 if there is no original file or one of the other file IDs)
My goal is to select the whole data sorted by name. In addition, I need to always have the original files appear before their children. In other words, the desired result will start with the first alphabetical file whose OriginalFileID is 0 followed by all its children (if available) alphabetically. The following SQL script creates the sample data and illustrates exactly what I'm trying to achieve. Notice that the last select command is the desired output.
What is the query that can return the desired result?
The Script:
-------------------------- Creating the Example Schema --------------------------
IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.Tables WHERE Table_Name = 'MyStackFiles')
Drop table MyStackFiles
GO
CREATE TABLE [dbo].[MyStackFiles](
[FileID] [int] IDENTITY(1,1) NOT NULL,
[FileName] [varchar](50) NULL,
[OriginalFileID] [int] NOT NULL DEFAULT (0),
CONSTRAINT [PK_MyStackFiles] PRIMARY KEY CLUSTERED
(
[FileID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
------------------------------------------------------------------------------
GO
-------------------------- Insert Into the Sample Data --------------------------
INSERT INTO MyStackFiles(FileName) values ('S')
INSERT INTO MyStackFiles(FileName) values ('G')
INSERT INTO MyStackFiles(FileName, OriginalFileID) values ('E', 1)
INSERT INTO MyStackFiles(FileName) values ('F')
INSERT INTO MyStackFiles(FileName, OriginalFileID) values ('Q', 2)
INSERT INTO MyStackFiles(FileName, OriginalFileID) values ('N', 3)
INSERT INTO MyStackFiles(FileName) values ('A')
INSERT INTO MyStackFiles(FileName, OriginalFileID) values ('X', 1)
INSERT INTO MyStackFiles(FileName) values ('W')
------------------------------------------------------------------------------
GO
-------------------------- Simple select sorted by FileName --------------------------
SELECT * From MyStackFiles ORDER BY FileName
-------------------------- A representation of the desired result --------------------------
SELECT * FROM MyStackFiles WHERE FileID = 7 UNION ALL -- We insert "A" (respecting the alphabetical order) since its OriginalFileID is 0
SELECT * FROM MyStackFiles WHERE FileID = 4 UNION ALL -- Then we insert F.
SELECT * FROM MyStackFiles WHERE FileID = 2 UNION ALL -- Then we insert G. G has children so we insert them
SELECT * FROM MyStackFiles WHERE FileID = 5 UNION ALL -- Q is the only child of G. We insert it
SELECT * FROM MyStackFiles WHERE FileID = 1 UNION ALL -- Now we insert S. Notice that S has two children (E and X)
SELECT * FROM MyStackFiles WHERE FileID = 3 UNION ALL -- E is before X alphabetically so it gets inserted first
SELECT * FROM MyStackFiles WHERE FileID = 6 UNION ALL -- E happens to have children so we insert them right away (in a depth first fashion)
SELECT * FROM MyStackFiles WHERE FileID = 8 UNION ALL -- Now we insert the other child of S which is X
SELECT * FROM MyStackFiles WHERE FileID = 9 -- Finally we insert W the only file left
--Drop Table MyStackFiles
I'm open to any schema modification if that helps find an efficient query.
I'm using the technique called Recursive CTE to try to solve your problem:
with t (RowID, FileID, FileName, OriginalFileID)
as (
select convert(varchar(max), row_number() over (order by s.FileName)), s.*
from MyStackFiles s
where s.OriginalFileID = 0
union all
select t.RowID + '.' + convert(varchar(max), row_number() over (order by s.FileName)), s.*
from MyStackFiles s
inner join t on t.FileID = s.OriginalFileID
)
select FileID, FileName, OriginalFileID from t
order by RowID
A temporary column RowID is created on-the-fly to chain up the ancestor's RowID to the row's row_number, so that for instance the file "N" will have RowID = '4.1.1', the file "X" will have RowID = '4.2', and this is the column to sort that fits your sorting requirement.

How to get result from parent child table

Work on SQL-Server. My table structure is below
CREATE TABLE [dbo].[AgentInfo](
[AgentID] [int] NOT NULL,
[ParentID] [int] NULL,
CONSTRAINT [PK_AgentInfo] PRIMARY KEY CLUSTERED
(
[AgentID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
INSERT [dbo].[AgentInfo] ([AgentID], [ParentID]) VALUES (1, -1)
INSERT [dbo].[AgentInfo] ([AgentID], [ParentID]) VALUES (2, -1)
INSERT [dbo].[AgentInfo] ([AgentID], [ParentID]) VALUES (3, 1)
INSERT [dbo].[AgentInfo] ([AgentID], [ParentID]) VALUES (4, 2)
Required output
Use my below syntax get required output but not satisfied. Is there any better way to get the required output
--get parent child list
---step--1
SELECT *
INTO #temp1
FROM ( SELECT a.AgentID ,
a.ParentID,
a.AgentID AS BaseAgent
FROM dbo.AgentInfo a WHERE ParentID=-1
UNION ALL
SELECT a.ParentID ,
0 as AgentID,
a.AgentID AS BaseAgent
FROM dbo.AgentInfo a WHERE ParentID!=-1
UNION ALL
SELECT a.AgentID ,
a.ParentID,
a.AgentID AS BaseAgent
FROM dbo.AgentInfo a
WHERE ParentID!=-1
) AS d
SELECT * FROM #temp1
DROP TABLE #temp1
Help me to improve my syntax. If you have any questions please ask.
You could use a recursive SELECT, see the examples in the documentation for WITH, starting with example D.
The general idea within the recursive WITH is: You have a first select that is the starting point, and then a UNION ALL and a second SELECT which describes the step from on level to the next, where the previous level can either be the result of the first select or the result of the previous run of the second SELECT.
You can try this, to get a tree of the elements:
WITH CTE_AgentInfo(AgentID, ParentID, BaseAgent)
AS(
SELECT
AgentID,
ParentID,
AgentID AS BaseAgent
FROM AgentInfo
WHERE ParentID = -1
UNION ALL
SELECT
a.AgentID,
a.ParentID,
a.AgentID AS BaseAgent
FROM AgentInfo a
INNER JOIN CTE_AgentInfo c ON
c.AgentID = a.ParentID
)
SELECT * FROM CTE_AgentInfo
And here is an SQLFiddle demo to see it.
Try something like this:
WITH Merged (AgentId, ParentId) AS (
SELECT AgentId, ParentId FROM AgentInfo WHERE ParentId = -1
UNION ALL
SELECT AgentInfo.AgentId, AgentInfo.ParentId FROM AgentInfo INNER JOIN Merged ON AgentInfo.AgentId = Merged.ParentId
)
SELECT * FROM Merged
You can use a Common Table Expression to do this.
The sql statement will then look like this:
WITH [Parents]([AgentID], [ParentID], [BaseAgent])
AS
(
SELECT
[AgentID],
[ParentID],
[AgentID] AS [BaseAgent]
FROM [AgentInfo]
WHERE [ParentID] = -1
UNION ALL
SELECT
[ai].[AgentID],
[ai].[ParentID],
[p].[BaseAgent]
FROM [AgentInfo] [ai]
INNER JOIN [Parents] [p]
ON [ai].[ParentID] = [p].[AgentID]
)
SELECT *
FROM [Parents]
ORDER BY
[BaseAgent] ASC,
[AgentID] ASC
But, the results are different from your desired output, since every Agent is only listed once.
The output is:
AGENTID PARENTID BASEAGENT
1 -1 1
3 1 1
2 -1 2
4 2 2
The Fiddle is over here.
And here is a nice post on working with hierarchies: What are the options for storing hierarchical data in a relational database?

How To Get A Hierarchical CTE In SQL Server To Filter With Parent and Child Logic

I'm having a vexing problem with a hierarchical CTE and some strange logic that we need to address that I really hope someone could assist with pointing out what I'm doing wrong to address this scenario with a CTE.
Here is the hierarchical data we're dealing with in this example:
This is the problematic SQL followed by the description of the problem and SQL statements to create a test table with data:
DECLARE #UserId nvarchar(50);
SET #UserId = 'A';
DECLARE #StatusType int;
SET #StatusType = '2';
;WITH recursiveItems (Id, Depth)
AS
(
SELECT Id, 0 AS Depth
FROM dbo.CteTest
WHERE UserId = #UserId
--AND StatusType = #StatusType
-- This would also be incorrect for the issue
AND ParentId IS NULL
UNION ALL
SELECT dbo.CteTest.Id, Depth + 1
FROM dbo.CteTest
INNER JOIN recursiveItems
ON dbo.CteTest.ParentId = recursiveItems.Id
WHERE UserId = #UserId
AND StatusType = #StatusType
)
SELECT A.*, recursiveItems.Depth
FROM recursiveItems
INNER JOIN dbo.CteTest A WITH(NOLOCK) ON
recursiveItems.Id = A.Id
ORDER BY A.Id
This is not returning the desired data. The data that is currently returned is in the NOT CORRECT section of the image below. The row with the Id of 10 is the row that we want to omit.
Essentially the logic should be that any parent record (record with children) where the status type of any of its children is equal to 2 should be returned along with its children. In the example this is the rows with Ids: 1, 5, 6, 7, 9.
Currently the CTE/SQL/Code is returning ALL parent records no matter what,
The record with the Id 1 should be returned, even though it's status type is 1 because at least one of its children, their children, grandchildren, etc. have a status type that is equal to 2.
The record with the Id of 10 should not be returned because it does not have a status that is equal to 2 or any children. If the record had a status type of 2 when it has no child records it should also be returned.
This is the DDL to create a test table that helps to show the problem:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[CteTest](
[Id] [int] IDENTITY(1,1) NOT NULL,
[StatusType] [int] NOT NULL,
[UserId] [nvarchar](50) NOT NULL,
[ParentId] [int] NULL,
CONSTRAINT [PK_CteTest] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
This is the seed data for the table, that can demonstrate the issue:
INSERT INTO [dbo].[CteTest]([StatusType],[UserId],[ParentId]) VALUES (1,'A',NULL)
INSERT INTO [dbo].[CteTest]([StatusType],[UserId],[ParentId]) VALUES (1,'B',NULL)
INSERT INTO [dbo].[CteTest]([StatusType],[UserId],[ParentId]) VALUES (2,'B',NULL)
INSERT INTO [dbo].[CteTest]([StatusType],[UserId],[ParentId]) VALUES (1,'A',1)
INSERT INTO [dbo].[CteTest]([StatusType],[UserId],[ParentId]) VALUES (2,'A',1)
INSERT INTO [dbo].[CteTest]([StatusType],[UserId],[ParentId]) VALUES (2,'A',5)
INSERT INTO [dbo].[CteTest]([StatusType],[UserId],[ParentId]) VALUES (2,'A',6)
INSERT INTO [dbo].[CteTest]([StatusType],[UserId],[ParentId]) VALUES (3,'A',6)
INSERT INTO [dbo].[CteTest]([StatusType],[UserId],[ParentId]) VALUES (2,'A',NULL)
INSERT INTO [dbo].[CteTest]([StatusType],[UserId],[ParentId]) VALUES (4,'A',NULL)
INSERT INTO [dbo].[CteTest]([StatusType],[UserId],[ParentId]) VALUES (3,'A',10)
The issue is that your base case includes all null (parentless) items, and there is no way to filter them out later.
Because you are looking for only items with a particular statustype, you may want to refactor the CTE; Instead of having a base case be the root values, you can have it be all items with the given statustype, and then recursively find the parents. In the solution below, I have depth be a negative number, for distance from the item with a value of 2 in the given tree (so negative height, instead of depth.).
DECLARE #UserId nvarchar(50);
SET #UserId = 'A';
DECLARE #StatusType int;
SET #StatusType = '2';
WITH recursiveItems (Id, ParentID, Depth)
AS
(
SELECT Id, ParentID, 0 AS Depth
FROM dbo.CteTest
WHERE UserId = #UserId AND StatusType = #StatusType
UNION ALL
SELECT dbo.CteTest.Id, CteTest.ParentID, Depth - 1
FROM dbo.CteTest
INNER JOIN recursiveItems
ON dbo.CteTest.Id = recursiveItems.ParentId
WHERE UserId = #UserId
)
SELECT A.Id, A.StatusType, A.UserId, A.ParentId, min(recursiveItems.Depth)
FROM recursiveItems
INNER JOIN dbo.CteTest A WITH(NOLOCK) ON
recursiveItems.Id = A.Id
group by A.Id, A.StatusType, A.UserId, A.ParentId
ORDER BY A.Id

SQL close close Gaps in data over time

I have a table of play data that I'm using for a prototype. I'm generating the data while I'm at work, but when I leave and my machine goes to sleep, the data generation stops. This has cause large gaps in my collection of items.
I would like to be able to shift the values of each item in the DateTimeCreated collumn of my table so that there isn't a gap of more than 10 minutes between any item and the next generated item.
The structure of the table is like this:
CREATE TABLE [dbo].[Items](
[Id] [uniqueidentifier] NOT NULL,
[DateTimeCreated] [datetimeoffset](7) NOT NULL,
[AuthorId] [uniqueidentifier] NOT NULL,
[Source] [varchar](max) NOT NULL,
[FullText] [varchar](max) NOT NULL,
CONSTRAINT [PK_Items] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
I was thinking about doing this in L2S, but I have over 1 million records, so IDK if that is the best solution (iterating over each item). I know there has to be some way to do this in SQL that will be much faster.
An alternative Ranking-Functions Approach (not 100% tested):
DECLARE #tenMinutes AS INT = 600;
WITH StartingPoints AS
(
SELECT DateTimeCreated, ROW_NUMBER() OVER(ORDER BY DateTimeCreated) AS rownum
FROM dbo.Items AS A
WHERE NOT EXISTS(
SELECT * FROM dbo.Items AS B
WHERE B.DateTimeCreated < A.DateTimeCreated
AND DATEDIFF(SECOND,B.DateTimeCreated, A.DateTimeCreated) BETWEEN 0 AND #tenMinutes
)
),
EndingPoints AS
(
SELECT DateTimeCreated, ROW_NUMBER() OVER(ORDER BY DateTimeCreated) AS rownum
FROM dbo.Items AS A
WHERE NOT EXISTS(
SELECT * FROM dbo.Items AS B
WHERE A.DateTimeCreated < B.DateTimeCreated
AND DATEDIFF(SECOND,A.DateTimeCreated, B.DateTimeCreated) BETWEEN 0 AND #tenMinutes
)
),
Islands AS
(
SELECT S.DateTimeCreated AS start_range,
E.DateTimeCreated AS end_range,
ROW_NUMBER() OVER(ORDER BY S.DateTimeCreated) AS row_num
FROM StartingPoints AS S
JOIN EndingPoints AS E on E.rownum = S.rownum
),
Ofs AS
(
SELECT I2.start_range,
I2.end_range,
I1.end_range AS prev,
DATEDIFF(SECOND, I1.end_range, I2.start_range) AS offset
FROM Islands AS I1
JOIN Islands AS I2 ON I2.row_num = I1.row_num + 1 OR I2.row_num IS NULL
),
CmlOfs AS
(
SELECT O1.start_range,
O1.end_range,
O1.prev,
O1.offset,
(SELECT SUM(O2.offset) FROM Ofs AS O2
WHERE O2.start_range <= O1.start_range) AS cum_offset
FROM Ofs AS O1
),
UpdateQ AS
(
SELECT Items.*, DATEADD(SECOND, -1 * CmlOfs.cum_offset, Items.DateTimeCreated) AS new_value
FROM Items
JOIN CmlOfs ON Items.DateTimeCreated BETWEEN CmlOfs.start_range AND CmlOfs.end_range
)
UPDATE UpdateQ
SET DateTimeCreated = new_value;
Make sure to have an index on DateTimeCreated if you want this to be anything other than a pig.
It also assumes (as you said in your comment) there are few gaps compared to total number of records.
WITH
gap (Start,Finish)
AS
(
SELECT
DateTimeCreated,
(SELECT MIN(DateTimeCreated) FROM items AS lookup WHERE DateTimeCreated > DateTimeCreated)
FROM
items
WHERE
DATEADD(second, 600, DateTimeCreated) < (SELECT MIN(DateTimeCreated) FROM items AS lookup WHERE DateTimeCreated > DateTimeCreated)
UNION ALL
SELECT
MAX(DateTimeCreated),
MAX(DateTimeCreated)
FROM
items
)
,
offset (Start,Finish,Offset)
AS
(
SELECT
[current].Start,
(SELECT MIN(Start) FROM gap WHERE Start > [current].Start),
DATEDIFF(second, Start, Finish) - 600
FROM
gap AS [current]
)
,
cumulative_offset (Start,Finish,Offset)
AS
(
SELECT
[current].Start,
[current].Finish,
SUM([cumulative].Offset)
FROM
offset AS [current]
INNER JOIN
offset AS [cumulative]
ON [cumulative].Start <= [current].Start
)
UPDATE
items
FROM
cumulative_offset
SET
DateTimeCreated = DATEADD(second, -Offset, DateTimeCreated)
INNER JOIN
items
ON items.DateTimeCreated > cumulative.Start
AND items.DateTimeCreated <= cumulative.Finish