Change value of duplicated rows - sql

There is a table with tow columns(ID, Data) and there are 3 rows with same value.
ID Data
4 192.168.0.22
4 192.168.0.22
4 192.168.0.22
Now I want to change third row DATA column. In update SQL Server Generate an error that I ca not change the value.
I can delete all 3 rows. But I can not delete third row separately.
This table is for a software that I bought and I changed the third Server IP.

You can try the following query
create table #tblSimilarValues(id int, ipaddress varchar(20))
insert into #tblSimilarValues values (4, '192.168.0.22'),
(4, '192.168.0.22'),(4, '192.168.0.22')
Use Below query if you want to change all rows
with oldData as (
select *,
count(*) over (partition by id, ipaddress) as cnt
from #tblSimilarValues
)
update oldData
set ipaddress = '192.168.0.22_1'
where cnt > 1;
select * from #tblSimilarValues
Use Below query if you want to skip firs row
;with oldData as (
select *,
ROW_NUMBER () over (partition by id, ipaddress order by id, ipaddress) as cnt
from #tblSimilarValues
)
update oldData
set ipaddress = '192.168.0.22_2'
where cnt > 1;
select * from #tblSimilarValues
drop table #tblSimilarValues
You can find the live demo live demo here

Since there is no column that allows us to distinguish these rows from each other, there's no "third row" (nor a first or second one for that matter).
We can use a ROW_NUMBER function to apply arbitrary row numbers to these rows, however, and if we place that in a CTE, we can apply DELETE/UPDATE actions via the CTE and use the arbitrary row numbers:
declare #t table (ID int not null, Data varchar(15))
insert into #t(ID,Data) values
(4,'192.168.0.22'),
(4,'192.168.0.22'),
(4,'192.168.0.22')
;With ArbitraryAssignments as (
select *,ROW_NUMBER() OVER (PARTITION BY ID, Data ORDER BY Data) as rn
from #t
)
delete from ArbitraryAssignments where rn > 2
select * from #t
This produces two rows of output - one row was deleted.
Note that I say that the ROW_NUMBER is arbitrary. One of the expressions in both the PARTITION BY and ORDER BY clauses is the same. By definition, then, we know that no real ORDER is defined by this (because all rows within the same partition, by definition, have the same value for that expression).

In this case ID columns allows duplicate value which is wrong, ID should be unique.
Now what you can do is create a new column make that unique or Primary Key or change the duplicate values of ID column and make it Unique/Primary key.
Now as per your Unique key/Primary key you can update DATA column value by query as below:
UPDATE <Table Name>
SET DATA = 'new data'
WHERE ID = 3;

Related

Unique ID using function with every record in Insert statement

I have a statement in stored procedure
INSERT into table(ID, name, age)
SELECT fnGetLowestFreeID(), name, age
FROM #tempdata
The function fnGetLowestFreeID() gets the lowest free ID of the table table.
I want to insert unique ID with every record in the table. I have tried iteration and transaction. But they aren't fitting the scenario.
I cannot use Identity Column. I have this restriction of using IDs between 0-4 and assigning the lowest free ID using that function. In case of returned ID greater than 4, the function is returning an error. Suppose there are already 1 and 2 in the table. The function will return 0 and I have to assign this ID to the new record, 3 to the next record and so on on the basis of number of records in the #tempdata.
try this
CREATE TABLE dbo.Tmp_City(Id int NOT NULL IDENTITY(1, 1),
Name varchar(50) , Country varchar(50), )
OR
ALTER TABLE dbo.Tmp_City
MODIFY COLUMN Id int NOT NULL IDENTITY(1, 1)
OR
Create a Sequence and assign Sequence.NEXTVAL as ID
in the insert statement
You can make use of a rank function like row_number and do something like this.
INSERT into table(ID, name, age)
SELECT row_number() over (order by id) + fnGetLowestFreeID(), name, age
FROM #tempdata
Here are 3 scenarios-
1)Show the function which you are using
2) Doesn't make sense to use a function and make it unique
still- you can use rank-
INSERT into table(ID, name, age)
SELECT row_number() over (order by id) + fnGetLowestFreeID(), name, age
FROM #tempdata
3)Else, get rid of function and use max(id)+1 because you dont want to use identitiy column
You could use a Numbers table to join the query doing your insert. You can google the concept for more info, but essentially you create a table (for example with the name "Numbers") with a single column "nums" of some integer type, and then you add some amount of rows, starting with 0 or 1, and going as far as you need. For example, you could end with this table content:
nums
----
0
1
2
3
4
5
6
Then you can use such a table to modify your insert, you don't need the function anymore:
INSERT into table(ID, name, age)
SELECT t2.nums, t.name, t.age
FROM (
SELECT name, age, row_number() over (order by name) as seq
FROM #tempdata
) t
INNER JOIN (
SELECT n.nums, row_number() over (order by n.nums) as seq
FROM Numbers n
WHERE n.nums < 5 AND NOT EXISTS (
SELECT * FROM table WHERE table.ID = n.nums
)
) t2 ON t.seq = t2.seq
Now, this query leaves out one of your requirements, that would be launching an error when no slots are available, but that is easy to fix. You can do previously a query and test if the count of records in table plus the sum of records in #tempdata is higher than 5. If so, you launch the error as you know there would not be enough free slots for the records in #tempdata.
Side note: table looks like a terrible name for a table, I hope that in your real code you have a meaningful name :)

Gow to select unique id when ids are same and have different string values in variable

I am working with Microsoft SQL Server. Now I have many same ids and the values of other variables associated with them may or may not be same.
I just want to select one unique id every time (I don't care about values of other variables). Values of other variables can be anything. I am just focused on selecting unique id and any values associated with any of the duplicate ids.
You could use the row_number function to assign a unique number to every ID, and then query just one of them:
SELECT id, variablea, variableb
FROM (SELECT id, variablea, variableb,
ROW_NUMBER() OVER (PARTITION BY id ORDER BY varaiblea) AS rn
FROM mytable) t
WHERE rn = 1
Another option is to use the WITH TIES clause in concert with Row_Number()
Note: No Extra Field.
Example
Declare #YourTable Table ([id] int,[variableA] varchar(50),[variableB] varchar(50))
Insert Into #YourTable Values
(1,'xyz','abc')
,(1,'fgh','rty')
,(2,'qwe','ui')
,(3,'jk','vbn')
,(3,'asd','ty')
,(3,'fgh','po')
Select top 1 with ties *
From #YourTable
Order By Row_Number() over (Partition By ID Order by variableA)
Returns
id variableA variableB
1 fgh rty
2 qwe ui
3 asd ty

Use Date from most recent and delete others SQL

Is it possible to delete all other rows but keep one which has oldest date in it ?
E.g.
Person
ID Name Birthdate
1 A 20160101
2 B 20160202
3 C 20160303
Is there any query that returns me ID of person row with OLDEST birthdate and DELETE all other rows that is
returns 3 and deletes all other rows
If all birthdays are SAME date then return me row with LOWEST ID
Thanks
Aiden
If you use ROW_NUMBER it will help you identify the records you want more correctly due to the fact that Birthdate could have ties. So build a Common Table Expression [CTE] that will identify the row you are looking for. Then if you actually want to delete the records from the database delete from the cte, but if you only want to return and not modify the data (more likely) just select where the row number is 1.
DECLARE #Table AS TABLE (ID INT, Name CHAR(1), Birthdate DATE)
INSERT INTO #Table VALUES
(1,'A','2016/01/01')
,(2,'B','2016/02/02')
,(3,'C','2016/03/03')
,(4,'D','2016/01/01') --note this is a tie for oldest birthdate
;WITH cte AS (
SELECT
*
,ROW_NUMBER() OVER (ORDER BY Birthdate, Id) as RowNumber
FROM
#Table
)
So if you really want to modify/delte the data you would do the following right after the above code:
DELETE FROM cte WHERE RowNumber > 1
SELECT * FROM #Table
If you really just want the 1 row matching your criteria you would simply put this statement after the above CTE.
SELECT * FROM cte WHERE RowNumber = 1
Sure, if by DELETE you mean to remove records from the database and by RETURN you mean selecting a row, AND if you can use a batch of two queries, you could do:
DELETE Person
WHERE ID <> (
SELECT TOP 1 ID
FROM Person
ORDER BY Birthdate DESC, ID
);
SELECT TOP 1 ID
FROM Person;
Ordering the subquery last for Id ASC garantees that, if there are equal Birthdates, only the lowest ID is returned.
The SELECT in the end will return the only remaining Person.
If you require just one query for both operations, then I don't think it's possible.

remove duplicate records with a criteria

I am using a script which requires only unique values. And I have a table which has duplicates like below, i need to keep only unique values (first occurrence) irrespective of what is present inside the brackets.
can I delete the records and keep the unique records using a single query?
Input table
ID Name
1 (Del)testing
2 (Del)test
3 (Delete)testing
4 (Delete)tester
5 (Del)tst
6 (Delete)tst
So the output tables should be something like
Input table
ID Name
1 (Del)testing
2 (Del)test
3 (Delete) tester
4 (Del)tst
SELECT DISTINCT * FROM FOO;
It depends how much data you have to retrieve, if you only have to change Delete -> Del you can try with REPLACE
http://technet.microsoft.com/en-us/library/ms186862.aspx
also grouping functions should help you
I don't think this would be easy query
Assumption: The name column always has all strings in the format given in the sample data.
Try this:
;with cte as
(select *, rank() over
(partition by substring(name, charindex(')',name)+1,len(name)+1 - charindex(')',name))
order by id) rn
from tbl
),
filtered_cte as
(select * from cte
where rn = 1
)
select rank() over (partition by getdate() order by id,getdate()) id , name
from filtered_cte
How this works:
The first CTE cte uses rank() to rank the occurrence of the string outside brackets in the name column.
The second CTE filtered_cte only returns the first row for each occurence of the specified string. In this step, we get the expected results, but not in the desired format.
In this step we partition by and order by the getdate() function. This function is chosen as a dummy to give us continuous values for the id column while using the rank function as we did in step 1.
Demo here.
Note that this solution will return filtered values, but not delete anything in the source table. If you wish, you can delete from the CTE created in step 1 to remove data from the source table.
First use this update to make them uniform
Update table set name = replace(Name, '(Del)' , '(Delete)')
then delete the repetitive names
Delete from table where id in
(Select id from (Select Row_Number() over(Partition by Name order by id) as rn,* from table) x
where rn > 1)
First create the input date table
CREATE TABLE test
(ID int,Name varchar(20));
INSERT INTO test
(`ID`, `Name`)
VALUES
(1, '(Del)testing'),
(2, '(Del)test'),
(3, '(Delete)testing'),
(4, '(Delete)tester'),
(5, '(Del)tst'),
(6, '(Delete)tst');
Select Query
select id, name
from (
select id, name ,
ROW_NUMBER() OVER(PARTITION BY substring(name,PATINDEX('%)%',name)+1,20) ORDER BY name) rn
from test ) t
where rn= 1
order by 1
SQL Fiddle Link
http://www.sqlfiddle.com/#!6/a02b0/34

Remove duplicates if you have only one column with value

This is too easy, if you have Id column and Value column which has duplicate rows. But in the interview i had been asked how to remove it, if you have only Value column. For example:
table_a input:
Value
A
A
B
A
C
D
D
E
F
F
E
table_a output:
Value
A
B
C
D
E
F
Question: You have table with only one column Value and you have to delete all rows, which have duplicates (as in result upper).
if you are allowed to use CTE:
with cte as (
select
row_number() over(partition by Value order by Value) as row_num,
Value
from Table1
)
delete from cte where row_num > 1
sql fiddle demo
as t-clausen.dk suggested in comments, you don't even need value inside the CTE:
with cte as (
select
row_number() over(partition by Value order by Value) as row_num
from Table1
)
delete from cte where row_num > 1;
Well, gow about using a CTE
A common table expression (CTE) can be thought of as a temporary
result set that is defined within the execution scope of a single
SELECT, INSERT, UPDATE, DELETE, or CREATE VIEW statement. A CTE is
similar to a derived table in that it is not stored as an object and
lasts only for the duration of the query. Unlike a derived table, a
CTE can be self-referencing and can be referenced multiple times in
the same query.
and ROW_NUMBER.
Returns the sequential number of a row within a partition of a result
set, starting at 1 for the first row in each partition.
Something like
;WITH Vals AS (
SELECT [Value],
ROW_NUMBER() OVER(PARTITION BY [Value] ORDER BY [Value]) RowID
FROM MyTable
)
DELETE
FROM Vals
WHERE RowID > 1
select distinct value
from your_table
(not relevant anymore as the question has been updated by the user, see Roman Pekar's answer)