Updating Sql Server Row with increasing ID - sql-server

How do I update sql server with increasing ID according to another column?
I have a table with following structure:
sn name val
test 0
test 0.5
test 2
test1 0
test1 0.5
test1 2
How do i update it so that is will be:
sn name val
1 test 0
2 test 0.5
3 test 2
1 test1 0
2 test1 0.5
3 test1 2
fiddle

Use cte and row_number
Here is an example :
create table #mytable (sn int, name varchar(20), val money)
insert into #mytable values (null, 'test', 0.5)
insert into #mytable values (null, 'test', 1)
insert into #mytable values (null, 'test1', 0.5)
insert into #mytable values (null, 'test1', 1)
;with cte as (select row_number() over (order by name, val) as rn, * from #mytable)
update cte set sn = rn
select * from #mytable

This can easily be done using Row_Number() and the OVER ... PARTITION BY clause, if you have a key column in the table. I added a column: Id int identity primary key and here's the update:
;with RowNumberedData as (
select
id,
row_number() over (
partition by name
order by id
) as rowno
from sql_test
)
update s
set sn = r.rowno
from sql_test s
join RowNumberedData r
on s.id = r.id;
SQLFiddle: http://sqlfiddle.com/#!3/43fa8/4

You should use ROW_NUMBER() function. Also as soon as you have to start new counter for each NAME value you should use PARTITON by NAME in this statement.
WITH T AS
(select sql_test.*,
ROW_NUMBER() OVER (PARTITION BY Name ORDER BY Val) as RowNumber
from sql_test)
UPDATE T SET SN=RowNumber;
SQLFiddle demo

Related

Need to skip Dense Rank in SQL Server

I want to generate Dense_Rank on a particular column but I want to provide default Rank on few value but the sequence should not break any suggestion.
What you want is:
select *,
dense_rank() over (order by case when id <> 3 then id end)-1 as Ranking
from test
order by id;
DBFiddle demo
Probably this was what you meant in your comment:
IF OBJECT_ID('tempdb..#test') IS NOT NULL
DROP TABLE #test
create table #test (id int);
insert into #test (id) values (1),(2),(3),(4),(4),(5),(6),(7);
with mx(id) as
(select max(id) from #test),
data(id, idrev) as (select t.id, mx.id - t.id + 1 from #test t, mx)
select id,
dense_rank() over (order by case when id <> 3 then idrev end)-1 as Ranking
from data order by id;
DBFiddle demo

Self join and get unique records between a date

I have my table and data as follows where I am trying to filter based on period and get results
CREATE TABLE testData
(
Id int,
period date,
value decimal(18,2)
)
INSERT INTO testData
VALUES (1, '2001-08-01', 400), (2, '2001-09-01', 400), (2, '2001-09-01', 300)
I have a fiddle which is giving results but not as expected you can check fiddle here http://sqlfiddle.com/#!6/beb4c/5
This is my SQL query
SELECT
a.id,
[value] - (SELECT TOP 1 b.[value]
FROM testData b
WHERE b.period = a.period
ORDER BY b.id DESC) x
FROM
testData a
Output I am expecting is
1 2001-08-01 400
2 2001-09-01 100
try This
WITH CTE
AS
(
SELECT
SeqNo = ROW_NUMBER() OVER(PARTITION BY Id ORDER BY Period),
*
FROM TestData
)
SELECT
A.Id,
A.Period,
Value = ISNULL(A.Value,0) - ISNULL(Q.Value,0)
FROM CTE A
LEFT JOIN(
SELECT
B.Id,
B.period,
Value = SUM(B.Value)
FROM CTE B
WHERE B.SeqNo <> 1
GROUP BY B.Period,B.Id
)Q
ON A.Id = Q.Id
WHERE A.SeqNo = 1
Fiddle Link Here

Aggregate function with where clause

I have a situation where I need the aggregate function to be use in the where condition for the update
statement and also for select statement.
Example:
Situation 1:
Update test_table
set ID_Number = 0
where count(ID_Number)=1; /* Not possible with where */
Note: Above script is not possible with where clause.
Situation 2:
For example I have the following table: Test
ID_Number Column1 Column2
--------------------------
1 XYZ ZYX
1 MMM NNN
2 III JJJ
3 AAA BBB
3 CCC DDD
Now I need to show only those records who's ID_Number is appear two times.
Expected Result:
ID_Number Column1 Column2
------------------------------
1 XYZ ZYX
1 MMM NNN
3 AAA BBB
3 CCC DDD
My try:
select * from Test
group by ID_Number,Column1,Column2
having count(ID_Number)>1;
Note: This gives me nothing in result.
SET NOCOUNT ON;
DECLARE #Test TABLE
(
ID_Number INT NOT NULL,
Column1 VARCHAR(50),
Column2 VARCHAR(50)
);
INSERT INTO #Test VALUES (1, 'XYZ', 'ZYX');
INSERT INTO #Test VALUES (1, 'MMM', 'NNN');
INSERT INTO #Test VALUES (2, 'III', 'JJJ');
INSERT INTO #Test VALUES (3, 'AAA', 'BBB');
INSERT INTO #Test VALUES (3, 'CCC', 'DDD');
-- Situation #1
;WITH cte AS
(
SELECT ID_Number
FROM #Test
GROUP BY ID_Number
HAVING COUNT(*) = 1
)
UPDATE ts
SET ts.ID_Number = 0
FROM #Test ts
INNER JOIN cte
ON cte.ID_Number = ts.ID_Number;
-- Situation #2
;WITH cte AS
(
SELECT ID_Number
FROM #Test
GROUP BY ID_Number
HAVING COUNT(*) > 1
)
SELECT ts.*
FROM #Test ts
INNER JOIN cte
ON cte.ID_Number = ts.ID_Number;
The output is the "Expected Result" shown in the question.
For both situations, the CTE gets the ID_Number values that show up more than once, and that list of values is used to filter the main SELECT or UPDATE.
First looking to your Situation 2 your query to getting your desired output will be as follows:
SELECT * FROM Test
WHERE ID_Number IN (select ID_Number from Test
group by ID_Number
having count(ID_Number)>1)
Now looking to your Situation 1 you can write UPDATE query which updates columns
: ID_Number = 0 to only those records whose ID_Number records coming once as per you stated in your Update query. You can modify your update query as follows:
Update test_table
set ID_Number = 0
FROM test_table
WHERE ID_Number IN (select ID_Number from Test
group by ID_Number
having count(ID_Number) = 1
try this:
Situation 1:
For Updating Your Can USE Common Table Expressions
Update test_table
set ID_Number = 0
where ID_Number IN (
select tst.ID_Number from test_table tst join
(
select ID_Number,COUNT(*) as CNT from test_table
GROUP BY ID_Number)d
ON d.ID_Number=tst.ID_Number
where d.CNT=1
)
Situation 2:
select tst.ID_Number,Column1,Column2 from test_table tst join
(
select ID_Number,COUNT(*) as CNT from test_table
GROUP BY ID_Number)d
ON d.ID_Number=tst.ID_Number
where d.CNT>1
SQL Fiddle
Here's what I'd do:
with cte as (
select *, count(*) over (partition by ID_Number) as c
from test_table
)
select *
from cte
where c > 1

sql server combine values in two tables

I am new to SQL in general and even newer to MS SQL. I apologize if the title isn't clear on what I want.
I have two tables an old one that I want to derive data from into a new table. The tables have the exact same columns but different number of rows. The new table has multiple copies of each value in the old table, which only has 2 occurences. see below comparison of two columns: letter and amount.
New table:
A 0
A 0
A 0
B 0
B 0
old table:
A 12
A 0
B 10
B 0
C 23
What I want to achieve is adding the values of the amount column from the old table into just the first occurence of the leter in the new table like so:
A 12
A 0
A 0
B 10
B 0
Inner join causes all the values to be filled ( so all the A's are set to 12).
try this:
DECLARE #test1 TABLE(col1 varchar(2),idn int)
insert into #test1
VALUES('A',0),
('A',0),
('A',0),
('B',0),
('B',0)
DECLARE #test2 TABLE(col1 varchar(2),idn int)
insert into #test2
VALUES('A',12),
('A',0),
('B',10),
('B',0),
('C',23)
;WITH CTE as (select *,ROW_NUMBER() over (partition by col1 order by col1) as rn from #test1)
update c SET c.idn=b.idn
from CTE c inner join (select col1,SUM(idn) as idn from #test2
group by col1) b
on c.col1 = b.col1
where c.rn=1
select * from #test1
click here to see Demo
declare #t table
(
val varchar(2),
digit int
)
insert into #t(val, digit)values('A', 0)
insert into #t(val, digit)values('A', 0)
insert into #t(val, digit)values('A', 0)
insert into #t(val, digit)values('B', 0)
insert into #t(val, digit)values('B', 0)
declare #t1 table
(
val varchar(2),
digit int
)
insert into #t1(val, digit)values('A', 12)
insert into #t1(val, digit)values('A', 0)
insert into #t1(val, digit)values('B', 10)
insert into #t1(val, digit)values('B', 0)
insert into #t1(val, digit)values('C', 23)
Select k.val, isNull(sum(k.digit + k1.digit), 0) as Digit from
(
Select ROW_NUMBER() over(partition by val order by val) as rowid, * from #t
)K
Left Join
(
Select ROW_NUMBER() over(partition by val order by val) as rowid, * from #t1
)K1
on k.val = k1.val AND K.rowid = K1.rowid
group by k.val, K.rowid

How to select from duplicate rows from a table?

I have the following table:
CREATE TABLE TEST(ID TINYINT NULL, COL1 CHAR(1))
INSERT INTO TEST(ID,COL1) VALUES (1,'A')
INSERT INTO TEST(ID,COL1) VALUES (2,'B')
INSERT INTO TEST(ID,COL1) VALUES (1,'A')
INSERT INTO TEST(ID,COL1) VALUES (1,'B')
INSERT INTO TEST(ID,COL1) VALUES (1,'B')
INSERT INTO TEST(ID,COL1) VALUES (2,'B')
I would like to select duplicate rows from that table. How can I select them?
I tried the following:
SELECT TEST.ID,TEST.COL1
FROM TEST WHERE TEST.ID IN
(SELECT ID
FROM TEST WHERE TEST.COL1 IN
(SELECT COL1
FROM TEST WHERE TEST.ID IN
(SELECT ID
FROM TEST
GROUP BY ID
HAVING COUNT(*) > 1)
GROUP BY COL1
HAVING COUNT(*) > 1)
GROUP BY ID
HAVING COUNT(*) > 1)
Where's the error? What do I need to modify?
And I would like it to show as:
ID COL1
---- ----
1 A
1 A
1 B
1 B
(4 row(s) affected)
SELECT id, col1
FROM Test
GROUP BY id, col1
HAVING COUNT(*) > 1
when you use
SELECT id, col1, COUNT(*) AS cnt
FROM Test
GROUP BY id, col1
HAVING COUNT(*) > 1
you practically have all duplicate rows and how often they appear. You can't identify them individually either way.
A slower way would be:
SELECT id, col1
FROM Test T
WHERE (SELECT COUNT(*)
FROM Test I
WHERE I.id = T.id AND I.col1 = T.col1) > 1
Using Sql Server 2005+ and CTE you could try
;WITH Dups AS (
SELECT *,
ROW_NUMBER() OVER(PARTITION BY ID, Col1 ORDER BY ID, Col1) Rnum
FROM #TEST t
)
SELECT *
FROM Dups
WHERE Rnum > 1
OR just a standard
SELECT ID,
Col1,
COUNT(1) Cnt
FROM #TEST
GROUP BY ID,
Col1
HAVING COUNT(1) > 1
EDIT:
Display duplicate rows
SELECT t.*
FROM #Test t INNER JOIN
(
SELECT ID,
Col1,
COUNT(1) Cnt
FROM #TEST
GROUP BY ID,
Col1
HAVING COUNT(1) > 1
) dups ON t.ID = dups.ID
AND t.Col1 = dups.Col1
Every row in that set of data is a duplicate
select id, col1, count(*)
from test
group by id, col1
shows this
if you want to exclude the 2,B rows you need to do it explicitly
eg
SELECT id, col1
FROM Test
WHERE NOT (id = 2 and col1 = 'B')
SELECT t.*
FROM TEST t
INNER JOIN (
SELECT ID,COL1
from test
GROUP BY ID,COL1
HAVING COUNT(*) > 1
)
AS t2
ON t2.ID = t.ID AND t2.COL1 =t.COL1
order by t.ID,t.COL1

Resources