SQL: Deleting row which values already exist - sql

I have a table that look like this:
ID | DATE | NAME | VALUE_1 | VALUE_2
1 | 27.11.2015 | Homer | A | B
2 | 27.11.2015 | Bart | C | B
3 | 28.11.2015 | Homer | A | C
4 | 28.11.2015 | Maggie | C | B
5 | 28.11.2015 | Bart | C | B
I currently delete duplicate rows (thank to this thread) using this code :
WITH cte AS
(SELECT ROW_NUMBER() OVER (PARTITION BY [VALUE_1], [VALUE_2]
ORDER BY [DATE] DESC) RN
FROM [MY_TABLE])
DELETE FROM cte
WHERE RN > 1
But this code don't delete exactly the lines I want. I would like to delete only rows which values already exist so in my example I would like to delete only line 5 because line 2 have the same values and is older.
Code to create my table and insert values:
CREATE TABLE [t_diff_values]
([id] INT IDENTITY NOT NULL PRIMARY KEY,
[date] DATETIME NOT NULL,
[name] VARCHAR(255) NOT NULL DEFAULT '',
[val1] CHAR(1) NOT NULL DEFAULT '',
[val2] CHAR(1) NOT NULL DEFAULT '');
INSERT INTO [t_diff_values] ([date], [name], [val1], [val2]) VALUES
('2015-11-27','Homer', 'A','B'),
('2015-11-27','Bart', 'C','B'),
('2015-11-28','Homer', 'A','C'),
('2015-11-28','Maggie', 'C','B'),
('2015-11-28','Bart', 'C','B');

You need to add one more CTE where you will index all islands and then apply your duplicate logic in second CTE:
DECLARE #t TABLE
(
ID INT ,
DATE DATE ,
VALUE_1 CHAR(1) ,
VALUE_2 CHAR(1)
)
INSERT INTO #t
VALUES ( 1, '20151127', 'A', 'B' ),
( 2, '20151128', 'C', 'B' ),
( 3, '20151129', 'A', 'B' ),
( 4, '20151130', 'A', 'B' );
WITH cte1
AS ( SELECT * ,
ROW_NUMBER() OVER ( ORDER BY date)
- ROW_NUMBER() OVER ( PARTITION BY VALUE_1, VALUE_2 ORDER BY DATE) AS gr
FROM #t
),
cte2
AS ( SELECT * ,
ROW_NUMBER() OVER ( PARTITION BY VALUE_1, VALUE_2, gr ORDER BY date) AS rn
FROM cte1
)
DELETE FROM cte2
WHERE rn > 1
SELECT *
FROM #t

Try this
CREATE TABLE [dbo].[Employee](
[ID] INT NOT NULL,
[Date] DateTime NOT NULL,
[VAL1] varchar(20) NOT NULL,
[VAL2] varchar(20) NOT NULL
)
INSERT INTO [dbo].[Employee] VALUES
(1,'2015-11-27 10:44:33.087','A','B')
INSERT INTO [dbo].[Employee] VALUES
(2,'2015-11-28 10:44:33.087','C','B')
INSERT INTO [dbo].[Employee] VALUES
(3,'2015-11-29 10:44:33.087','A','B')
INSERT INTO [dbo].[Employee] VALUES
(4,'2015-11-30 10:44:33.087','A','B')
with cte as(
select
*,
rn = row_number() over(partition by [VAL1], [VAL2]
ORDER BY [DATE] DESC),
cc = count(*) over(partition by [VAL1], [VAL2])
from [Employee]
)
delete
from cte
where
rn > 1 and rn < cc
select * from [Employee]

You could use this query:
WITH cte AS
(
SELECT RN = ROW_NUMBER() OVER (ORDER BY ID)
, *
FROM #data
)
DELETE FROM c1
--SELECT *
FROM CTE c1
INNER JOIN CTE c2 ON c1.RN +1 = c2.RN AND c1.VALUE_1 = c2.VALUE_1 AND c1.VALUE_2 = c2.VALUE_2
Here I order them by ID. If the next one (RN+1) has similar V1 and V2, it is deleted.
Output:
ID DATE VALUE_1 VALUE_2
1 2015-11-27 A B
2 2015-11-28 C B
4 2015-11-30 A B
Data:
declare #data table(ID int, [DATE] date, VALUE_1 char(1), VALUE_2 char(1));
insert into #data(ID, [DATE], VALUE_1, VALUE_2) values
(1, '20151127', 'A', 'B'),
(2, '20151128', 'C', 'B'),
(3, '20151129', 'A', 'B'),
(4, '20151130', 'A', 'B');

Related

How can I prevent inserting duplicate data into a SQL Server table where value is multiple

I have a declared some of data that need to be inserted into SQL, what should I do to check the data in SQL to prevent same data inserted into table?
123(AA) is already uploaded and 123(BB) is a new invitee.
At this case, server should upload just 123(BB).
declare #inviteename VARCHAR(500) = 'aa,bb' ,#inviteephoneno VARCHAR(500) = '123,45',#Code varchar(10)='123', #CustomerID VARCHAR(50) = 10
DECLARE #tbl TABLE (
inviteename VARCHAR(100),
inviteephoneno VARCHAR(100)
);
INSERT INTO #tbl ( inviteename, inviteephoneno) select #inviteename, #inviteephoneno;
DECLARE #temp TABLE (
inviteename VARCHAR(100),
inviteephoneno VARCHAR(100),
CustomerID VARCHAR(100)
);
;WITH cte1 AS
(
SELECT value AS inviteename , ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS seq
FROM #tbl CROSS APPLY STRING_SPLIT(inviteename, ',')
), cte2 AS
(
SELECT value AS inviteephoneno , ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS seq
FROM #tbl CROSS APPLY STRING_SPLIT(inviteephoneno, ',')
)
INSERT INTO #temp ( inviteename, inviteephoneno,CustomerID)
SELECT cte1.inviteename, cte2.inviteephoneno,#CustomerID FROM cte1 INNER JOIN cte2 ON cte2.seq = cte1.seq;
if not exists (select 1 from test a where a.inviteename= (select InviteeName from #temp a where a.CustomerID=#CustomerID)
and a.InviteeMobileNumber = (select InviteeMobileNumber from #temp a where a.CustomerID=#CustomerID))
begin
INSERT dbo.test (InviteeName ,InviteeMobileNumber )
SELECT a.inviteename, a.inviteephoneno FROM #temp a
end
test table
create table test (
id int identity(1,1)
, inviteename VARCHAR(100)
, inviteephoneno VARCHAR(100) );
You can use merge
create table test (
id int identity(1,1)
, inviteename VARCHAR(100)
, InviteeMobileNumber VARCHAR(100) );
GO
declare #inviteename VARCHAR(500) = 'aa,bb'
,#inviteephoneno VARCHAR(500) = '123
,45',#Code varchar(10)='123'
, #CustomerID VARCHAR(50) = 10
DECLARE #tbl TABLE (
inviteename VARCHAR(100),
inviteephoneno VARCHAR(100)
);
INSERT INTO #tbl ( inviteename, inviteephoneno) select #inviteename, #inviteephoneno;
DECLARE #temp TABLE (
inviteename VARCHAR(100),
inviteephoneno VARCHAR(100),
CustomerID VARCHAR(100)
);
;WITH cte1 AS
(
SELECT value AS inviteename , ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS seq
FROM #tbl CROSS APPLY STRING_SPLIT(inviteename, ',')
), cte2 AS
(
SELECT value AS inviteephoneno , ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS seq
FROM #tbl CROSS APPLY STRING_SPLIT(inviteephoneno, ',')
)
INSERT INTO #temp ( inviteename, inviteephoneno,CustomerID)
SELECT cte1.inviteename, cte2.inviteephoneno,#CustomerID FROM cte1 INNER JOIN cte2 ON cte2.seq = cte1.seq;
MERGE dbo.test AS T
USING #temp AS S
ON (T.inviteename = S.inviteename AND T.InviteeMobileNumber = S.inviteephoneno)
WHEN NOT MATCHED BY TARGET
THEN INSERT (InviteeName ,InviteeMobileNumber) VALUES(S.inviteename, S.inviteephoneno)
OUTPUT $action, Inserted.*;
GO
$action | id | inviteename | InviteeMobileNumber
:------ | -: | :---------- | :------------------
INSERT | 1 | aa | 123<br>
INSERT | 2 | bb | 45
SELECT * FROM test
GO
id | inviteename | InviteeMobileNumber
-: | :---------- | :------------------
1 | aa | 123<br>
2 | bb | 45
db<>fiddle here

How to get first value from first row and last value from last row in SQL Server

I have a table in SQL Server as below
+---+-------------+-------------+-------------+
|Id | FromCity | ToCity | RequestId |
+---+-------------+-------------+-------------+
| 1 | Mysore | Atlanta | 12 |
+---+-------------+-------------+-------------+
| 2 | Atlanta | Singapore | 12 |
+---+-------------+-------------+-------------+
| 3 | Singapore | Pakistan | 12 |
+---+-------------+-------------+-------------+
| 4 | Pakistan | Myscot | 12 |
+---+-------------+-------------+-------------+
| 5 | Rome | Singapore | 13 |
+---+-------------+-------------+-------------+
Here, I am trying to get a value as From and To Cities (Round Trip Data) (i.e. Mysore - > Myscot for the RequestId =12). Ho to get this value?
When I pass RequestId=12, I should get the value as Mysore -> Myscot
I Tried as below:
SELECT MIN(FromCity) [From],
MAX(ToCity) [To]
FROM MyTable
WHERE RequestId = 12
But I'm getting Mysore -> Singapore (based on string MIN and MAX).
Check This :
SELECT M.FromCity [From],
M2.ToCity [To]
FROM #MyTable M
Inner join (select Min(ID) min ,Max(ID) max from #MyTable M2 WHERE M2.RequestId = 12 )
A on A.Min =ID
Inner join #MyTable M2 on M2.ID=A.Max
Output :
SELECT RequestId,
f.FromCity [From],
t.ToCity [To]
FROM MyTable t
CROSS APPLY (
SELECT TOP (1) FromCity
FROM MyTable
WHERE RequestId = t.RequestId
ORDER BY Id ASC
) f
CROSS APPLY (
SELECT TOP (1) ToCity
FROM MyTable
WHERE RequestId = t.RequestId
ORDER BY Id DESC
) t
WHERE RequestId = 12
The only logic I see is using the Id from your table and do something like this. Using CTE you will find the MIN and MAX id per request, that means from city - to city.
And after that you join your table to the CTE to find the actual values.
declare #tbl as table
([Id] int, [FromCity] varchar(9), [ToCity] varchar(9), [Date Created] datetime, [RequestId] int)
;
INSERT INTO #tbl
([Id], [FromCity], [ToCity], [Date Created], [RequestId])
VALUES
(1, 'Mysore', 'Atlanta', '2018-10-05 15:10:00', 12),
(2, 'Atlanta', 'Singapore', '2018-10-06 15:10:00', 12),
(3, 'Singapore', 'Pakistan', '2018-10-07 15:10:00', 12),
(4, 'Pakistan', 'Myscot', '2018-10-07 15:10:00', 12),
(5, 'UK', 'Atlanta', '2018-10-06 15:10:00', 13),
(6, 'Atlanta', 'Singapore', '2018-10-06 15:10:00', 13),
(7, 'Singapore', 'Italy', '2018-10-23 15:10:00', 13);
;with cte as (
select
MIN(Id) as [start]
,MAX(Id) as [end]
,RequestId
from #tbl
group by requestID
)
select
t1.FromCity
,t1.[Date Created]
,t2.ToCity
,t2.[Date Created]
from cte
inner join #tbl t1
on t1.Id = cte.[start]
and t1.RequestId = cte.RequestId
inner join #tbl t2
on t2.Id = cte.[end]
and t2.RequestId = cte.RequestId
Update: based on #Panagiotis Kanavos comment you can simplify the query like this
;with cte as (
select
MIN(Id) as [start]
,MAX(Id) as [end]
from #tbl
where RequestId = 12 ---> here you can use a variable containing the requestID
)
select
t1.FromCity
--,t1.[Date Created]
,t2.ToCity
--,t2.[Date Created]
from cte
inner join #tbl t1
on t1.Id = cte.[start]
inner join #tbl t2
on t2.Id = cte.[end]
If Id in main table is used to describe travel order then something like this will work:
SELECT startLocation.FromCity [From], endLocation.ToCity AS [To]
FROM (
SELECT MIN(Id) AS StartLocationId, MAX(Id) AS EndLocationId
FROM MyTable
WHERE RequestId = 12
) AS a
INNER JOIN MyTable AS startLocation ON a.StartLocationId = startLocation.Id
INNER JOIN MyTable AS endLocation ON a.EndLocationId = endLocation.Id
This is a example of solution for situation when ids are just ids and don`t match travel order:
declare #tbl as table
([Id] int, [FromCity] varchar(9), [ToCity] varchar(9), [Date Created] datetime, [RequestId] int)
;
INSERT INTO #tbl
([Id], [FromCity], [ToCity], [Date Created], [RequestId])
VALUES
(19, 'Mysore', 'Atlanta', '2018-10-05 15:10:00', 12),
(22, 'Atlanta', 'Singapore', '2018-10-06 15:10:00', 12),
(1, 'Singapore', 'Pakistan', '2018-10-07 15:10:00', 12),
(4, 'Pakistan', 'Myscot', '2018-10-07 15:10:00', 12),
(5, 'UK', 'Atlanta', '2018-10-06 15:10:00', 13),
(0, 'Atlanta', 'Singapore', '2018-10-06 15:10:00', 13),
(-1, 'Singapore', 'Italy', '2018-10-23 15:10:00', 13)
;
select * from #tbl
declare #Id int = 12
declare #FromStart nvarchar(255), #ToStart nvarchar(255)
declare #StartResult nvarchar(255), #ToResult nvarchar(255)
declare #StartResultFound bit = 0, #ToResultFound bit = 0
-- select random starting point
select #FromStart = [FromCity], #ToStart = [ToCity] from #tbl where [RequestId] = #Id
ORDER BY NEWID()
select #FromStart, #ToStart
while (#StartResultFound = 0)
begin
if exists (select top 1 1 from #tbl where [RequestId] = #Id and [ToCity] = #FromStart)
begin
select top 1 #FromStart = [FromCity] from #tbl where [RequestId] = #Id and [ToCity] = #FromStart
end
else
begin
set #StartResultFound = 1
set #StartResult = #FromStart
end
end
while (#ToResultFound = 0)
begin
if exists (select top 1 1 from #tbl where [RequestId] = #Id and [FromCity] = #ToStart)
begin
select top 1 #ToStart = [ToCity] from #tbl where [RequestId] = #Id and [FromCity] = #ToStart
end
else
begin
set #ToResultFound = 1
set #ToResult = #ToStart
end
end
select #StartResult, #ToResult
maybe this is whar you need
DECLARE
#t TABLE (
ID INT
, FromCity VARCHAR(250)
, ToCity VARCHAR(250)
, RequestId INT
)
INSERT INTO #t VALUES
(1,'Mysore','Atlanta',12)
,(2,'Atlanta','Singapore',12)
,(3,'Singapore','Pakistan',12)
,(4,'Pakistan','Myscot',12)
,(5,'Rome','Singapore',13)
SELECT DISTINCT
ISNULL(FromCity, ISNULL(NextCity, PreCity) ) FromCity
, ISNULL(ToCity, ISNULL(NextCity2, PreCity2) ) FromCity
FROM (
SELECT
CASE WHEN RN = 1 THEN FromCity END FromCity
, CASE WHEN RN = CNT THEN ToCity END ToCity
, LEAD(CASE WHEN RN = 1 THEN FromCity END) OVER(PARTITION BY RequestId ORDER BY ID) NextCity
, LEAD(CASE WHEN RN = CNT THEN ToCity END) OVER(PARTITION BY RequestId ORDER BY ID) NextCity2
, LAG(CASE WHEN RN = 1 THEN FromCity END) OVER(PARTITION BY RequestId ORDER BY ID) PreCity
, LAG(CASE WHEN RN = CNT THEN ToCity END) OVER(PARTITION BY RequestId ORDER BY ID) PreCity2
FROM (
SELECT
*, ROW_NUMBER() OVER(PARTITION BY RequestId ORDER BY ID) RN
, COUNT(ToCity) OVER(PARTITION BY RequestId) CNT
FROM #t
) D
WHERE
RN = 1 OR RN = CNT
) C
A recursive version, not depending on Ids order. The idea is to build the biggest chain of trip connected by To / From cities.
WITH cte1 AS (
-- start with all trips as 1 hop chain
SELECT [FromCity], [ToCity], 1 AS HOP
FROM Mytable
WHERE REQUESTID = 12
UNION ALL
-- recursively add one hop if we find a trip ending in start city of the chain
SELECT T.[FromCity], cte1.[ToCity], cte1.HOP + 1
FROM cte1
JOIN Mytable t
ON t.[ToCity] = cte1.[FromCity]
WHERE t.REQUESTID = 12
)
, cte2 AS (
-- order by number of hops
SELECT [FromCity], [ToCity], ROW_NUMBER() OVER (ORDER BY HOP DESC) AS N
FROM cte1
)
-- choose the chain with the more hops
SELECT [FromCity], [ToCity]
FROM cte2
WHERE N = 1
try this code
SELECT MIN(Id) [From],
MAX(Id) [To]
FROM MyTable
WHERE RequestId = 12

Find row where COL1 matches but COL2 doesn't and delete oldest entries

I have data like this:
+--------------+------------+----------+
| name | id | data | date |
+-------+------+-----------------------+
| host1 | 1 | data1 |07/20/2017|
| host1 | 1 | data2 |07/20/2017|
| host2 | 2 | data1 |07/20/2017|
| host2 | 3 | data1 |07/19/2017|
| host3 | 4 | data1 |07/20/2017|
| host3 | 4 | data2 |07/20/2017|
| host3 | 4 | data3 |07/20/2017|
| host3 | 4 | data4 |07/20/2017|
| host4 | 5 | data3 |07/20/2017|
| host4 | 6 | data4 |07/17/2017|
+-------+------+------------+----------+
I need to be able to remove some stale data from the table. The data has multiple rows for each object. But I need the ability to search the table and find instances where the 'name' matches but the 'IDs' don't. Then delete the older records. In the data example above I would like to delete from tableName where ID = '3' or '6'
I've been able to use the following query to isolate which ones don't match, but I can't figure out how to step through each one (especially if there are multiple 'names' that need to be deleted).
SELECT *
FROM tableName
WHERE NAME IN (SELECT T1.NAME
FROM aid2245.tableName T1
INNER JOIN aid2245.tableName T2
ON T1.NAME = T2.NAME
WHERE T1.ID <> T2.ID)
Any help would be appreciated.
Thanks!
This deletes 3 and 6.
create table tableName
(id int,
name varchar(50),
[date] date)
GO
-- Sample data
insert into tableName
(name, id, [date])
values('host1' , 1 , '07/20/2017'),
( 'host1' , 1 , '07/20/2017'),
( 'host2' , 2 , '07/20/2017'),
( 'host2' , 3 , '07/19/2017'),
( 'host3' , 4 , '07/20/2017'),
( 'host3' , 4 , '07/20/2017'),
( 'host3' , 4 , '07/20/2017'),
( 'host3' , 4 , '07/20/2017'),
( 'host4' , 5 , '07/20/2017'),
( 'host4' , 6 , '07/17/2017')
GO
-- Look at what we are deleting first.
SELECT b.*
FROM (SELECT name, max(date) maxDate
FROM tableName
GROUP BY name) AS a
JOIN tableName AS b
ON a.name = b.name
AND b.date < a.maxDate
AND b.Id not in
(SELECT max(id)
FROM tableName
GROUP BY [date]
HAVING date = maxDate)
GO
-- delete the older rows
DELETE b
FROM (SELECT name, max(date) maxDate
FROM tableName
GROUP BY name) AS a
JOIN tableName AS b
ON a.name = b.name
AND b.date < a.maxDate
AND b.Id not in
(SELECT max(id)
FROM tableName
GROUP BY [date]
HAVING date = maxDate)
GO
The following should do the trick.
IF OBJECT_ID('tempdb..#TestData', 'U') IS NULL
BEGIN -- DROP TABLE #TestData
CREATE TABLE #TestData (
[name] CHAR(5) NOT NULL,
id INT NOT NULL,
[data] CHAR(5) NOT NULL,
[date] DATE NOT NULL
);
INSERT #TestData (name, id, data, date) VALUES
('host1', 1, 'data1', '07/20/2017'),
('host1', 1, 'data2', '07/20/2017'),
('host2', 2, 'data1', '07/20/2017'),
('host2', 3, 'data1', '07/19/2017'),
('host3', 4, 'data1', '07/20/2017'),
('host3', 4, 'data2', '07/20/2017'),
('host3', 4, 'data3', '07/20/2017'),
('host3', 4, 'data4', '07/20/2017'),
('host4', 5, 'data3', '07/20/2017'),
('host4', 6, 'data4', '07/17/2017');
END;
--==========================================================
-- 1) View before DELETE...
SELECT
*,
NeedsDelete = CASE WHEN td.id = LAG(td.id, 1, td.id) OVER (PARTITION BY td.name ORDER BY td.date) THEN '' ELSE 'Delete' END
FROM
#TestData td
ORDER BY
td.name,
td.date DESC;
-- 2) Do the actual DELETE...
WITH
cte_FindDelete AS (
SELECT
*,
NeedsDelete = CASE WHEN td.id = LAG(td.id, 1, td.id) OVER (PARTITION BY td.name ORDER BY td.date) THEN '' ELSE 'Delete' END
FROM
#TestData td
)
DELETE fd
FROM
cte_FindDelete fd
WHERE
fd.NeedsDelete = 'Delete';
HTH,
Jason
I would do this with window functions:
with todelete as (
select t.*,
min(id) over (partition by name) as minid,
max(id) over (partition by name) as maxid,
row_number() over (partition by name order by date desc) as seqnum
from tablename t
)
delete from todelete
where minid <> maxid and seqnum > 1;

Unpivot multiple columns not showing desire result

Original
RecordKey Name Section1_Product Section1_Code Section2_Product Section2_Code ......
1 a ff 22
2 b gg 22
3 c hh 33
RecordKey Name Section Product Code ......
1 a 1 ff 22
1 a 2
2 b 1 gg 22
2 b 2
3 c 1 hh 22
3 c 2
I am trying to unpivot the columns into rows. Some sections will have null value.
SELECT RecordKey
,Name
,'Num_of_Sections' = ROW_NUMBER() OVER (PARTITION BY RecordKey ORDER BY ID)
,Product
,Code
FROM (
SELECT RecordKey, Name, Section1_Product, Section1_Code, Section2_Product, Section2_Code FROM Table
) M
UNPITVOT (
Product FOR ID IN (Section1_Product, Section2_Product)
) p
UNPIVOT (
Code FOR CO IN (Section1_Code, Section2_Code)
) c
If I execute with only one column (Product, comment out Code) then I will have 2 values in ID column (1,2). If I run the query with 2 columns then I get 4 values in ID column(1, 2, 3, 4).
may as per my assumption and your data provided we can achieve this using Cross apply and Row_number
declare #Record TABLE
([RecordKey] int,
[Name] varchar(1),
[Section1_Product] varchar(2),
[Section1_Code] int,
[Section2_Product] varchar(2),
[Section2_Code] int)
;
INSERT INTO #Record
([RecordKey], [Name], [Section1_Product], [Section1_Code],[Section2_Product],[Section2_Code])
VALUES
(1, 'a', 'ff', 22,NULL,NULL),
(2, 'b', 'gg', 22,NULL,NULL),
(3, 'c', 'hh', 33,NULL,NULL)
;
With cte as (
Select T.RecordKey,
T.Name,
T.val,
T.val1 from (
select RecordKey,Name,val,val1 from #Record
CROSS APPLY (VALUES
('Section1_Product',Section1_Product),
('Section2_Product',Section2_Product))cs(col,val)
CROSS APPLY (VALUES
('Section1_Code',Section1_Code),
('Section2_Code',Section2_Code))css(col1,val1)
WHERE val is NOT NULL)T
)
Select c.RecordKey,
c.Name,
c.RN,
CASE WHEN RN = 2 THEN NULL ELSE c.val END Product,
c.val1 Code
from (
Select RecordKey,
Name,
ROW_NUMBER()OVER(PARTITION BY val ORDER BY (SELECT NULL))RN,
val,
val1 from cte )C

How do you order a group of records then insert their order placement too?

I have a table of logs that contain a ID and TIMESTAMP. I want to ORDER BY ID and then TIMESTAMP.
For example, this is what the result set would look like:
12345 05:40
12345 05:50
12345 06:22
12345 07:55
12345 08:33
Once that's done, I want to INSERT a order value in a third column that signifies it's placement in the group from earliest to latest.
So, you would have something like this:
12345 05:40 1 <---First entry
12345 05:50 2
12345 06:22 3
12345 07:55 4
12345 08:33 5 <---Last entry
How can I do that in a SQL statement? I can select the data and ORDER BY ID, TIMESTAMP. But, I can't seem to INSERT a order value based on the groupings. :(
Try this update not an insert:
Fiddle demo here:
;with cte as(
select id, yourdate, row_number() over(order by id,yourdate) rn
from yourTable
)
Update ut Set thirdCol = rn
From yourTable ut join cte on ut.Id = cte.id and ut.yourdate = cte.yourdate
NOTE: if you need to get the thirdColumn updated per id basis, please partition your rownumber by using row_number() over (partition by id, order by order by id,yourdate)
Results:
| ID | YOURDATE | THIRDCOL |
|-------|----------|----------|
| 12345 | 05:40 | 1 |
| 12345 | 05:50 | 2 |
| 12345 | 06:22 | 3 |
| 12345 | 07:55 | 4 |
| 12345 | 08:33 | 5 |
Using a derived table and an update.
IF OBJECT_ID('tempdb..#TableOne') IS NOT NULL
begin
drop table #TableOne
end
CREATE TABLE #TableOne
(
SomeColumnA int ,
LetterOfAlphabet varchar(12) ,
PositionOrdinal int not null default 0
)
INSERT INTO #TableOne ( SomeColumnA , LetterOfAlphabet )
select 123 , 'x'
union all select 123 , 'b'
union all select 123 , 'z'
union all select 123 , 't'
union all select 123 , 'c'
union all select 123 , 'd'
union all select 123 , 'e'
union all select 123 , 'a'
Select 'pre' as SpaceTimeContinium , * from #TableOne order by LetterOfAlphabet
Update
#TableOne
Set PositionOrdinal = derived1.rowid
From
( select SomeColumnA , LetterOfAlphabet , rowid = row_number() over (order by LetterOfAlphabet asc) from #TableOne innerT1 )
as derived1
join #TableOne t1
on t1.LetterOfAlphabet = derived1.LetterOfAlphabet and t1.SomeColumnA = derived1.SomeColumnA
Select 'post' as SpaceTimeContinium, * from #TableOne order by LetterOfAlphabet
IF OBJECT_ID('tempdb..#TableOne') IS NOT NULL
begin
drop table #TableOne
end
To get the order you desire without doing an insert and an update, you can set your clustered index to handle it for you. The example below creates a clustered primary key.
To do this you must remove any clustered index that you already have on the table because you can only have one clustered index per table.
CREATE TABLE dbo.Table_1
(
ID int NOT NULL,
DTStamp datetime NOT NULL
)
ALTER TABLE dbo.Table_1 ADD CONSTRAINT
PK_Table_1 PRIMARY KEY CLUSTERED
(
ID,
DTStamp
)
Insert some random data to test with...
INSERT INTO [dbo].[Table_1]([ID],[DTStamp])VALUES(12346,getdate());
INSERT INTO [dbo].[Table_1]([ID],[DTStamp])VALUES(12346,dateadd(mi,1,getdate()));
INSERT INTO [dbo].[Table_1]([ID],[DTStamp])VALUES(12346,dateadd(mi,2,getdate()));
INSERT INTO [dbo].[Table_1]([ID],[DTStamp])VALUES(12346,dateadd(mi,3,getdate()));
INSERT INTO [dbo].[Table_1]([ID],[DTStamp])VALUES(12346,dateadd(mi,4,getdate()));
INSERT INTO [dbo].[Table_1]([ID],[DTStamp])VALUES(12340,dateadd(mi,5,getdate()));
INSERT INTO [dbo].[Table_1]([ID],[DTStamp])VALUES(12340,dateadd(mi,6,getdate()));
INSERT INTO [dbo].[Table_1]([ID],[DTStamp])VALUES(12340,dateadd(mi,7,getdate()));
INSERT INTO [dbo].[Table_1]([ID],[DTStamp])VALUES(12340,dateadd(mi,8,getdate()));
INSERT INTO [dbo].[Table_1]([ID],[DTStamp])VALUES(12344,dateadd(mi,1,getdate()));
INSERT INTO [dbo].[Table_1]([ID],[DTStamp])VALUES(12344,dateadd(mi,2,getdate()));
INSERT INTO [dbo].[Table_1]([ID],[DTStamp])VALUES(12344,dateadd(mi,3,getdate()));
INSERT INTO [dbo].[Table_1]([ID],[DTStamp])VALUES(12344,dateadd(mi,4,getdate()));
INSERT INTO [dbo].[Table_1]([ID],[DTStamp])VALUES(12344,dateadd(mi,5,getdate()));
INSERT INTO [dbo].[Table_1]([ID],[DTStamp])VALUES(12344,dateadd(mi,6,getdate()));
INSERT INTO [dbo].[Table_1]([ID],[DTStamp])VALUES(12344,dateadd(mi,7,getdate()));
INSERT INTO [dbo].[Table_1]([ID],[DTStamp])VALUES(12344,dateadd(mi,8,getdate()));
Now query your table and check out the order...
SELECT [ID] ,[DTStamp] FROM [Table_1]
If you need the order to display in a query, you can add the row number with an over clause.
SELECT [ID] ,[DTStamp],row_number() over (partition by [ID] order by [ID] ,[DTStamp]) as SortOdr FROM [Table_1]