SQL Server : nested stored procedure to update table values - sql-server

I have a table structure and its data as follows.
CREATE TABLE TestTable
(
id INT Identity(1,1) PRIMARY KEY,
creationTimestamp DATE,
indexOne INT,
indexTwo INT
);
INSERT INTO TestTable (creationTimestamp, indexOne, indexTwo)
VALUES
(2014-01-10, 100, 0),
(2014-01-11, 100, 0),
(2014-01-12, 100, 0),
(2014-01-13, 152, 2),
(2014-01-14, 152, 2),
(2014-01-15, 152, 2),
(2014-02-12, 152, 2),
(2014-02-13, 152, 2),
(2014-02-14, 333, 4),
(2014-02-15, 333, 4),
(2014-02-16, 333, 4),
(2014-03-10, 333, 4),
(2014-03-11, 333, 4),
(2014-03-12, 333, 4),
(2014-03-13, 333, 4),
(2014-03-14, 333, 4),
(2014-04-20, 500, 7),
(2014-04-21, 500, 7),
(2014-04-22, 500, 7),
(2014-04-23, 500, 7);
When you consider indexOne + indexTwo, there are duplicate rows. But I need them to be unique.
Therefore indexTwo must be properly indexed as follows
(2014-01-10, 100, 0),
(2014-01-11, 100, 1),
(2014-01-12, 100, 2),
(2014-01-13, 152, 0),
(2014-01-14, 152, 1),
(2014-01-15, 152, 2),
(2014-02-12, 152, 3),
(2014-02-13, 152, 4),
(2014-02-14, 333, 0),
(2014-02-15, 333, 1),
(2014-02-16, 333, 2),
(2014-03-10, 333, 3),
(2014-03-11, 333, 4),
(2014-03-12, 333, 5),
(2014-03-13, 333, 6),
(2014-03-14, 333, 7),
(2014-04-20, 500, 0),
(2014-04-21, 500, 1),
(2014-04-22, 500, 2),
(2014-04-23, 500, 3);
I have written the following stored procedure and it does not work properly
declare #indexOne int, #indexTwo int, #x int
declare c cursor for
select indexOne, indexTwo
from TestTable
group by indexOne, indexTwo
open c
fetch next from c into #indexOne, #indexTwo
while ##FETCH_STATUS = 0
begin
set #x = 0;
declare #id int
declare c1 cursor for
select id
from TestTable
where indexOne = #indexOne and indexTwo = #indexTwo
order by creationTimestamp asc
open c1
fetch next from c1 into #id
while ##FETCH_STATUS = 0
begin
UPDATE TestTable SET indexTwo = #x WHERE id = #id
set #x = #x + 1
fetch next from c1 into #id
end
close c1
deallocate c1
fetch next from c into #indexOne, #indexTwo
end
close c
deallocate c
Help me to find why this is not working

You don't need a cursor to do this use window function to generate the indextwo values per creationtimestamp, indexone. I hope this will do the job.
Sql Server
UPDATE A
SET indexTwo = b.indexTwo
FROM testtable a
JOIN (SELECT creationTimestamp, indexOne,
Row_number()OVER(partition BY indexone
ORDER BY creationtimestamp)-1 indexTwo
FROM testtable) B
ON a.creationtimestamp = b.creationtimestamp
AND a.indexone = b.indexone
SQLFIDDLE DEMO

Related

Alternative for this Cursor SQL

How can I do this without the cursor:
SET NOCOUNT ON;
DECLARE #VAR_A BIGINT, #VAR_B TINYINT;
DECLARE _CURSOR CURSOR FOR
SELECT A, B FROM MY_TABLE
OPEN _CURSOR
FETCH NEXT FROM _CURSOR
INTO #VAR_A, #VAR_B
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT TOP 2 A, B, C, ROW_NUMBER() OVER (ORDER BY A DESC) AS ROW_NUM
INTO #TMP FROM MY_TABLE_2
WHERE A = #VAR_A AND X = 0 ORDER BY A DESC
IF ((SELECT COUNT(*) FROM #TMP) = 1) BEGIN
UPDATE MY_TABLE
SET Y = (SELECT B FROM #TMP WHERE ROW_NUM = 1)
WHERE A = #VAR_A
END ELSE IF (#VAR_B = 7) BEGIN
UPDATE MY_TABLE
SET Y = (SELECT B FROM #TMP WHERE ROW_NUM = 2),
Z = (SELECT C FROM #TMP WHERE ROW_NUM = 2)
WHERE A = #VAR_A
END ELSE BEGIN
UPDATE MY_TABLE
SET Y = (SELECT B FROM #TMP WHERE ROW_NUM = 2)
WHERE A = #VAR_A
END
DROP TABLE #TMP
FETCH NEXT FROM _CURSOR
INTO #VAR_A, #VAR_B
END
CLOSE _CURSOR;
DEALLOCATE _CURSOR;
I have a PRODUCT table, this table has a status column, the last status of the product. I have another table, the PRODUCT_HISTORY, that have all information changed on product, including the older status. For each product, I need to get the last status and insert it on a new field on product table. Like this:
This should do the trick...
IF OBJECT_ID('tempdb..#Product', 'U') IS NOT NULL
DROP TABLE #Product;
CREATE TABLE #Product (
Id INT NOT NULL PRIMARY KEY CLUSTERED,
[Description] VARCHAR(20) NOT NULL,
[Status] INT NOT NULL,
OlderStatus INT NULL
);
INSERT #Product (Id, [Description], [Status]) VALUES
(1, 'Product A', 5),
(2, 'Product B', 7),
(3, 'Product C', 4),
(4, 'Product D', 3),
(5, 'Product E', 0);
IF OBJECT_ID('tempdb..#ProductHistory', 'U') IS NOT NULL
DROP TABLE #ProductHistory;
CREATE TABLE #ProductHistory (
Id INT NOT NULL PRIMARY KEY CLUSTERED,
[Date] DATE NOT NULL,
Status INT NOT NULL,
ProductId INT NOT NULL
);
INSERT #ProductHistory (Id, [Date], [Status], ProductId) VALUES
(1, '2017-01-01', 0, 1),
(2, '2017-01-02', 1, 1),
(3, '2017-01-03', 5, 1),
(4, '2017-01-04', 0, 2),
(5, '2017-01-05', 1, 2),
(6, '2017-01-06', 5, 2),
(7, '2017-01-07', 7, 2),
(8, '2017-01-08', 0, 3),
(9, '2017-01-09', 4, 3),
(10, '2017-01-10', 0, 4),
(11, '2017-01-11', 3, 4),
(12, '2017-01-12', 0, 5);
--===================================================
-- the actual solution...
WITH
cte_PH AS (
SELECT
ph.Id, ph.Date, ph.Status, ph.ProductId,
RN = ROW_NUMBER() OVER (PARTITION BY ph.ProductId ORDER BY ph.Date DESC)
FROM
#ProductHistory ph
)
UPDATE p SET
p.OlderStatus = ISNULL(ph.Status, 0)
FROM
#Product p
LEFT JOIN cte_PH ph
ON p.id = ph.ProductId
AND ph.RN = 2;
----------------------------------------
SELECT * FROM #Product p;
Results...
Id Description Status OlderStatus
----------- -------------------- ----------- -----------
1 Product A 5 1
2 Product B 7 5
3 Product C 4 0
4 Product D 3 0
5 Product E 0 0

How to remove redundant conditions in **IN** query Sql

I have this kind of query. But i need to optimize this query so how can omit redundant conditions with same split function.
DECLARE #Filter nvarchar(20)
SELECT #Filter ='5,22,3'
SELECT * FROM Employee e
WHERE e.code IN
(
CASE WHEN((SELECT count(*) FROM dbo.FNSPLITSTRING(SUBSTRING(#Filter,1,LEN(#Filter)-1), ',') d
WHERE d.splitdata IN (5, 16, 20, 23, 33, 49, 62, 90, 91, 92, 93, 94))>0) THEN 5 ELSE 0 END
,CASE WHEN((SELECT count(*) FROM dbo.FNSPLITSTRING(SUBSTRING(#Filter,1,LEN(#Filter)-1), ',') d
WHERE d.splitdata IN (22, 18))>0) THEN 46 ELSE 0 END
,CASE WHEN((SELECT count(*) FROM dbo.FNSPLITSTRING(SUBSTRING(#Filter,1,LEN(#Filter)-1), ',') d
WHERE d.splitdata IN (3, 28))>0) THEN 3 ELSE 0 END
)
As #Damien_The_Unbeliever said, avoid split strings as table of values. You do not need to split the same string multiple times. Instead you can use a temporary table variable.
DECLARE #SplitStrings TABLE
(
splitdata int
)
INSERT #SplitStrings
SELECT splitdata FROM dbo.FNSPLITSTRING(SUBSTRING(#Filter,1,LEN(#Filter)-1), ',') d
DECLARE #EmployeeCodes TABLE
(
splitdata INT,
code int
)
INSERT #EmployeeCodes (splitdata, code)
VALUES (5, 5), (16, 5), (20, 5), (23, 5), (33, 5), (49, 5), (62, 5), (90, 5), (91, 5), (92, 5), (93, 5), (94, 5),
(22, 46), (18, 46),
(3, 3), (28, 3)
SELECT e.*
FROM Employee e
JOIN #EmployeeCodes ec
ON e.code = ec.code
JOIN #SplitStrings ss
ON ec.splitdata = ss.splitdata
I hope this is the direction you are looking at.
Note: Assuming that you do not need 0 as employee code.
I have done new way. Less complex and omit redundant code.
DECLARE #Filter nvarchar(20)
SELECT #Filter ='5,22,3'
SELECT Distinct e.EmployeeId FROM Employee e
CROSS JOIN dbo.fnSplitString(#Filter, ',') AS d
WHERE
(e.code = 5 AND d.splitdata IN ('5', '16', '20', '23', '33', '49', '62', '90', '91', '92', '93', '94'))
OR (e.code = 46 AND d.splitdata IN ('22', '18'))
OR (e.code = 3 AND d.splitdata IN ('3', '28'))

SQL Insert Into Select Statement With Condition [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I have a table like this :
I want to insert into detail_salary_table with Insert into Select statement.
I can insert the salary_component item "Salary" with this code
INSERT INTO detail_salary_table (date_work, id_emp, salary_component, nominal)
SELECT
date_work, id_emp, 'Salary',
IIF(DATEDIFF(minute, start_work, finish_work) > 480, 10000, round(convert(float(53), datediff(minute, start_work, finish_work)) / 480, 1) * 10000)
FROM
attendance_table
How to insert the salary_component item "OverTime" with T-SQL like the image?
If I use VB.NET, I can do it with if and loop statement.
Note :
480 is fix. 10.000 is fix.
overtime = finish_work - start_work - 480. It take nominal from overtime_rate_table where the value near to time_in_minutes
the increment of nominal in overtime_rate_table is not measured. (so, i cannot use * 1000) (example is measured)
The SQL code to create the tables and sample data:
create table employee_table
(
id_emp int primary key,
name_emp varchar(200)
);
GO
create table attendance_table
(
id_data int primary key identity(1,1),
date_work date,
id_emp int,
start_work datetime,
finish_work datetime
);
GO
create table overtime_rate_table
(
id_data int,
time_in_minutes int,
nominal money
);
GO
create table detail_salary_table
(
id_data int primary key identity(1,1),
date_work date,
id_emp int,
salary_component varchar(100),
nominal money
);
GO
insert into employee_table
values (1, 'Emp A'), (2, 'Emp B'), (3, 'Emp C'), (4, 'Emp D'), (5, 'Emp E');
GO
insert into attendance_table (date_work, id_emp, start_work, finish_work)
values
('2017-02-01',1,'2017-02-01 08:00','2017-02-01 16:52'),
('2017-02-01',2,'2017-02-01 07:45','2017-02-01 16:48'),
('2017-02-01',3,'2017-02-01 08:02','2017-02-01 12:05'),
('2017-02-01',4,'2017-02-01 07:56','2017-02-01 16:49'),
('2017-02-01',5,'2017-02-01 07:30','2017-02-01 18:05'),
('2017-02-02',1,'2017-02-02 07:52','2017-02-02 16:23'),
('2017-02-02',2,'2017-02-02 07:19','2017-02-02 18:56'),
('2017-02-02',3,'2017-02-02 07:55','2017-02-02 18:23'),
('2017-02-02',4,'2017-02-02 08:01','2017-02-02 16:01'),
('2017-02-02',5,'2017-02-02 07:31','2017-02-02 16:49'),
('2017-02-03',1,'2017-02-03 07:52','2017-02-03 17:44'),
('2017-02-03',2,'2017-02-03 07:41','2017-02-03 17:23'),
('2017-02-03',3,'2017-02-03 07:06','2017-02-03 17:56'),
('2017-02-03',4,'2017-02-03 07:56','2017-02-03 19:00'),
('2017-02-03',5,'2017-02-03 07:45','2017-02-03 18:56');
GO
insert into overtime_rate_table
values (1, 15, 1000), (2, 30, 2000), (3, 45, 3000),
(4, 60, 4000), (5, 75, 5000), (6, 90, 6000),
(7, 105, 7000), (8, 120, 8000), (9, 135, 9000),
(10, 150, 10000), (11, 165, 11000), (12, 180, 12000),
(13, 195, 13000), (14, 210, 14000), (15, 225, 15000);
GO
INSERT INTO detail_salary_table
(date_work,
id_emp,
salary_component,
nominal
)
SELECT date_work,
id_emp,
'OverTime',
ISNULL(o.Nominal, 0)
FROM attendance_table a
LEFT JOIN overtime_rate_table o ON CONVERT( INT, DATEDIFF(minute, a.start_work, a.finish_work) - 480) / 15 * 15 = o.time_in_minutes;

SQL Server: String insertion by position

I want to insert a set of values into a given string at specified positions. I couldn't find an existing solution for this so I created the following query which does so. I am wondering if there is a way to simplify it, especially the portion which queries the cte and creates the NewString. Also, is there a way to construct the cte recursion without involving the ID column? The ID (and the rest) seems to work fine, just wondering if it could be tweaked to make it more organic/elegant or if there is a better solution overall. The different groups are really only for testing purposes; each group corresponds to a possible insertion position scenario. Thus, there will not be groups involved when I use it.
declare
#String varchar(200),
#StringLen int,
#GroupID int,
#PositionMax int
declare #Chars table (
ID int identity,
GroupID int,
Position int,
Value varchar(20)
)
select
#String = 'abcde',
#StringLen = len(#String),
#GroupID = 1
--Affix
--[P]refix
--[I]nfix
--[S]uffix
insert #Chars
select
GroupID,
Position,
Value
from (
values
(1, 0, 'X'), --P
(2, 2, 'Y'), --I
(3, 5, 'Z'), --S
(4, 0, 'X'), --P
(4, 2, 'Y'), --I
(5, 2, 'Y'), --I
(5, 5, 'Z'), --S
(6, 0, 'X'), --P
(6, 5, 'Z'), --S
(7, 0, 'X'), --P
(7, 2, 'Y'), --I
(7, 5, 'Z'), --S
(8, 2, 'Y1'), --I
(8, 4, 'Y2'), --I
(9, 0, 'X'), --P
(9, 2, 'Y1'), --I
(9, 4, 'Y2'), --I
(10, 2, 'Y1'), --I
(10, 4, 'Y2'), --I
(10, 5, 'Z'), --S
(11, 0, 'X'), --P
(11, 2, 'Y1'), --I
(11, 4, 'Y2'), --I
(11, 5, 'Z') --S
) as T(GroupID, Position, Value)
order by GroupID, Position
;with cte (
ID,
GroupID,
LeftString,
Value,
RightString,
Position
) as (
select
ID,
GroupID,
LeftString,
Value,
RightString,
Position
from (
select
row_number() over (partition by GroupID order by ID) as RowNumber,
ID,
GroupID,
cast(left(#String, Position) as varchar(200)) as LeftString,
Value,
cast(right(#String, #StringLen - Position) as varchar(200)) as RightString,
Position
from #Chars
) as C
where RowNumber = 1
union all
select
vc.ID,
vc.GroupID,
cast(left(RightString, vc.Position - cte.Position) as varchar(200)) as LeftString,
vc.Value,
cast(right(RightString, #StringLen - vc.Position) as varchar(200)) as RightString,
vc.Position
from #Chars vc
join cte cte
on cte.GroupID = vc.GroupID
and cte.ID + 1 = vc.ID
)
select
GroupID,
case
when LSLenSumMax < #StringLen
then NewString + RightString
else NewString
end as NewString
from (
select
GroupID,
max(LSLenSum) as LSLenSumMax,
RightString,
stuff((
select
LeftString + Value
from cte cte
where cte.GroupID = cteLR.GroupID
for xml path(''), type
).value('(./text())[1]', 'varchar(max)'), 1, 0, '') as NewString
from (
select
GroupID,
(select sum(len(LeftString)) from cte cteL where cteL.groupID = cte.groupID) as LSLenSum,
(select top 1 RightString from cte cteR where cteR.groupID = cte.groupID order by cteR.ID desc) as RightString
from cte cte
) as cteLR
group by
GroupID,
RightString
) as C
order by GroupID
You can implement a custom
aggregate function... Or try this: A recursive scalar function:
CREATE FUNCTION dbo.GetPrefixTo (#GroupID INT, #Position INT, #String CHAR(200))
RETURNS Char(200)
WITH EXECUTE AS CALLER
AS
BEGIN
DECLARE #str CHAR(200) = NULL
DECLARE #beforePosition INT = 0
IF (SELECT COUNT(*) FROM Chars WHERE GroupID = #GroupID AND Position < #Position) > 0
BEGIN
SELECT #beforePosition = MAX(Position) FROM chars WHERE GroupID = #GroupID AND Position < #Position
select #str = RTRIM(dbo.GetPrefixTo(#GroupID, #beforePosition, substring(#String, 1, #Position))) +
+ RTrim(Value) + substring(#String, #Position + 1, len(#string) + 1)
FROM Chars WHERE GroupID = #GroupID AND Position = #Position
END
ELSE
SELECT #str = substring(#String, 1, #Position) + RTrim(Value) + substring(#String, #Position + 1, len(#string) + 1) FROM Chars
WHERE GroupID = #GroupID AND Position = #Position
RETURN #str
END
And group by GroupID and aggregate max(position):
SELECT groupID, max(Position)
, dbo.GetPrefixTo(groupID, max(Position), 'abcde')
FROM Chars
GROUP BY GroupID
This is the result:
1 0 Xabcde
2 2 abYcde
3 5 abcdeZ
4 2 XabYcde
5 5 abYcdeZ
6 5 XabcdeZ
7 5 XabYcdeZ
8 4 abY1cdY2e
9 4 XabY1cdY2e
10 5 abY1cdY2eZ
11 5 XabY1cdY2eZ
========================================================================

Deleting records from SQL Server table without cursor

I am trying to selectively delete records from a SQL Server 2005 table without looping through a cursor. The table can contain many records (sometimes > 500,000) so looping is too slow.
Data:
ID, UnitID, Day, Interval, Amount
1 100 10 21 9.345
2 100 10 22 9.367
3 200 11 21 4.150
4 300 11 21 4.350
5 300 11 22 4.734
6 300 11 23 5.106
7 400 13 21 10.257
8 400 13 22 10.428
Key is: ID, UnitID, Day, Interval.
In this example I wish to delete Records 2, 5 and 8 - they are adjacent to an existing record (based on the key).
Note: record 6 would not be deleted because once 5 is gone it is not adjacent any longer.
Am I asking too much?
See these articles in my blog for performance detail:
SQL Server: deleting adjacent values
SQL Server: deleting adjacent values (improved)
The main idea for the query below is that we should delete all even rows from continuous ranges of intervals.
That is, if for given (unitId, Day) we have the following intervals:
1
2
3
4
6
7
8
9
, we have two continuous ranges:
1
2
3
4
and
6
7
8
9
, and we should delete every even row:
1
2 -- delete
3
4 -- delete
and
6
7 -- delete
8
9 -- delete
, so that we get:
1
3
6
8
Note that "even rows" means "even per-range ROW_NUMBER()s" here, not "even values of interval".
Here's the query:
DECLARE #Table TABLE (ID INT, UnitID INT, [Day] INT, Interval INT, Amount FLOAT)
INSERT INTO #Table VALUES (1, 100, 10, 21, 9.345)
INSERT INTO #Table VALUES (2, 100, 10, 22, 9.345)
INSERT INTO #Table VALUES (3, 200, 11, 21, 9.345)
INSERT INTO #Table VALUES (4, 300, 11, 21, 9.345)
INSERT INTO #Table VALUES (5, 300, 11, 22, 9.345)
INSERT INTO #Table VALUES (6, 300, 11, 23, 9.345)
INSERT INTO #Table VALUES (7, 400, 13, 21, 9.345)
INSERT INTO #Table VALUES (8, 400, 13, 22, 9.345)
INSERT INTO #Table VALUES (9, 400, 13, 23, 9.345)
INSERT INTO #Table VALUES (10, 400, 13, 24, 9.345)
INSERT INTO #Table VALUES (11, 400, 13, 26, 9.345)
INSERT INTO #Table VALUES (12, 400, 13, 27, 9.345)
INSERT INTO #Table VALUES (13, 400, 13, 28, 9.345)
INSERT INTO #Table VALUES (14, 400, 13, 29, 9.345)
;WITH rows AS
(
SELECT *,
ROW_NUMBER() OVER
(
PARTITION BY
(
SELECT TOP 1 qi.id AS mint
FROM #Table qi
WHERE qi.unitid = qo.unitid
AND qi.[day] = qo.[day]
AND qi.interval <= qo.interval
AND NOT EXISTS
(
SELECT NULL
FROM #Table t
WHERE t.unitid = qi.unitid
AND t.[day] = qi.day
AND t.interval = qi.interval - 1
)
ORDER BY
qi.interval DESC
)
ORDER BY interval
) AS rnm
FROM #Table qo
)
DELETE
FROM rows
WHERE rnm % 2 = 0
SELECT *
FROM #table
Update:
Here's a more efficient query:
DECLARE #Table TABLE (ID INT, UnitID INT, [Day] INT, Interval INT, Amount FLOAT)
INSERT INTO #Table VALUES (1, 100, 10, 21, 9.345)
INSERT INTO #Table VALUES (2, 100, 10, 22, 9.345)
INSERT INTO #Table VALUES (3, 200, 11, 21, 9.345)
INSERT INTO #Table VALUES (4, 300, 11, 21, 9.345)
INSERT INTO #Table VALUES (5, 300, 11, 22, 9.345)
INSERT INTO #Table VALUES (6, 300, 11, 23, 9.345)
INSERT INTO #Table VALUES (7, 400, 13, 21, 9.345)
INSERT INTO #Table VALUES (8, 400, 13, 22, 9.345)
INSERT INTO #Table VALUES (9, 400, 13, 23, 9.345)
INSERT INTO #Table VALUES (10, 400, 13, 24, 9.345)
INSERT INTO #Table VALUES (11, 400, 13, 26, 9.345)
INSERT INTO #Table VALUES (12, 400, 13, 27, 9.345)
INSERT INTO #Table VALUES (13, 400, 13, 28, 9.345)
INSERT INTO #Table VALUES (14, 400, 13, 29, 9.345)
;WITH source AS
(
SELECT *, ROW_NUMBER() OVER (PARTITION BY unitid, day ORDER BY interval) rn
FROM #Table
),
rows AS
(
SELECT *, ROW_NUMBER() OVER (PARTITION BY unitid, day, interval - rn ORDER BY interval) AS rnm
FROM source
)
DELETE
FROM rows
WHERE rnm % 2 = 0
SELECT *
FROM #table
I don't think what you're asking for is possible — but you may be able to get close. It appears you can almost do it by finding records with a self-join like this:
SELECT t1.id
FROM
table t1 JOIN table t2 ON (
t1.unitid = t2.unitid AND
t1.day = t2.day AND
t1.interval = t2.interval - 1
)
but the problem is, that'll find id=6 as well. However, if you create a temporary table from this data, it may be much smaller than your original data, and thus far faster to scan with a cursor (to fix the id=6 problem). You can then do a DELETE FROM table WHERE id IN (SELECT id FROM tmp_table) to kill the rows.
There may be a way to fix the ID=6 problem w/o a cursor, but if so, I don't see it.
There is the WHILE statement, which is an alternative to the cursor. That combined with table variables might let you do the same thing within a performance bound you're OK with.
DECLARE #Table TABLE (ID INT, UnitID INT, [Day] INT, Interval INT, Amount FLOAT)
INSERT INTO #Table VALUES (1, 100, 10, 21, 9.345)
INSERT INTO #Table VALUES (2, 100, 10, 22, 9.367)
INSERT INTO #Table VALUES (3, 200, 11, 21, 4.150)
INSERT INTO #Table VALUES (4, 300, 11, 21, 4.350)
INSERT INTO #Table VALUES (5, 300, 11, 22, 4.734)
INSERT INTO #Table VALUES (6, 300, 11, 23, 5.106)
INSERT INTO #Table VALUES (7, 400, 13, 21, 10.257)
INSERT INTO #Table VALUES (8, 400, 13, 22, 10.428)
DELETE FROM #Table
WHERE ID IN (
SELECT t1.ID
FROM #Table t1
INNER JOIN #Table t2
ON t2.UnitID = t1.UnitID
AND t2.Day = t1.Day
AND t2.Interval = t1.Interval - 1
LEFT OUTER JOIN #Table t3
ON t3.UnitID = t2.UnitID
AND t3.Day = t2.Day
AND t3.Interval = t2.Interval - 1
WHERE t3.ID IS NULL)
SELECT * FROM #Table
Lieven is so close - it worked for the test set, but if I add a few more records it starts to miss some.
We cannot use any odd/even criteria - we have no idea how the data falls.
Add this data and retry:
INSERT #Table VALUES (9, 100, 10, 23, 9.345)
INSERT #Table VALUES (10, 100, 10, 24, 9.367)
INSERT #Table VALUES (11, 100, 10, 25, 4.150)
INSERT #Table VALUES (12, 100, 10, 26, 4.350)
INSERT #Table VALUES (13, 300, 11, 25, 4.734)
INSERT #Table VALUES (14, 300, 11, 26, 5.106)
INSERT #Table VALUES (15, 300, 11, 27, 10.257)
INSERT #Table VALUES (16, 300, 11, 29, 10.428)

Resources