How to update string values with incrementing numbers - sql

I have a table that has a column which needs to be updated with values like
dummy1
dummy2
dummy3
..
..
..
dummy6
I created the following while loop script
create table people_test(UserName varchar(40))
GO
INSERT INTO people_test (UserName) values ('admin'),('test'),('opq'),('mn'),('ijkl'),('efgh'),('abcd')
GO
Select * from people_test
GO
DECLARE #i int;
DECLARE #j int = 1;
BEGIN
SELECT #i = COUNT(*) FROM people_test WHERE username <> 'admin';
WHILE(#j <= #i)
BEGIN
print 'i='+CONVERT(VARCHAR,#i)+' j='+CONVERT(VARCHAR,#j);
UPDATE people_test
SET
UserName = 'dummy'+ CONVERT(VARCHAR,#j)
WHERE username <> 'admin';
print 'i='+CONVERT(VARCHAR,#i)+' j='+CONVERT(VARCHAR,#j);
SET #j = #j + 1;
END;
END;
GO
Expected result
UserName
admin
dummy1
dummy2
dummy3
Result that I am seeing
UserName
admin
dummy6
dummy6
dummy6

You can solve this task with the row_number() function and therefore without a loop. Something like this:
drop table if exists #people_test
go
create table #people_test (UserName varchar (1000))
go
INSERT INTO #people_test (UserName) values ('admin'),('test'),('opq'),('mn'),('ijkl'),('efgh'),('abcd')
GO
update t
set t.UserName = 'dummy' + cast(t.rn as varchar(10))
from (
select row_number() over (order by UserName ) rn, *
from #people_test
where UserName!='admin'
) t
select * from #people_test
order by UserName

IF OBJECT_ID('tempdb..#TEMPS','U') IS NOT NULL
DROP TABLE #TEMPS
create table #TEMPS (UserName varchar(40))
GO
INSERT INTO #TEMPS (UserName) values ('admin'),('test'),('opq'),('mn'),('ijkl'),('efgh'),('abcd')
GO
UPDATE T1 SET T1.USERNAME= 'DUMMY'+CAST(T2.ROW AS varchar)
FROM #TEMPS AS T1, (SELECT ROW_NUMBER() OVER (ORDER BY USERNAME) AS ROW,* FROM #TEMPS ) AS T2
WHERE T2.UserName=T1.UserName AND T1.UserName!='ADMIN'
SELECT * FROM #TEMPS ORDER BY 1

Your own solution might work, but this is the wrong century for a CURSOR/LOOP based solution for such an easy task. Try something along this:
--Create a test table and fill it with data.
CREATE TABLE people_test(USERID INT IDENTITY,UserName VARCHAR(40))
GO
INSERT INTO people_test (UserName) VALUES
('admin')
,('test')
,('opq')
,('mn')
,('ijkl')
,('efgh')
,('abcd');
GO
SELECT * FROM people_test;
GO
--This is an updateable CTE
WITH upd AS
(
SELECT UserName
,CONCAT(UserName,ROW_NUMBER() OVER(ORDER BY USERID)) AS NewUserName
FROM people_test
WHERE UserName <> 'admin'
)
UPDATE upd SET UserName=NewUserName;
GO
--See the result
SELECT * FROM people_test;
GO
--Clean-up (carefull with real data!)
DROP TABLE people_test;
GO
The idea in short:
The CTE upd will return two columns:
UserName is the column you want to change
NewUserName is a computed column returning the value you want to see in UserName.
We can simply use UPDATE upd to update the underlying table.

create table people_test(USERID int,UserName varchar(40))
GO
INSERT INTO people_test (USERID, UserName) values (1,'admin'),(2,'test'),(3,'opq'),(4,'mn'),(5,'ijkl'),(6,'efgh'),(7,'abcd')
GO
Select * from people_test
GO
DECLARE #i int;
DECLARE #j int = 1;
DECLARE #k int;
DECLARE c_id cursor for
Select USERID from PEOPLE_TEST
WHERE username <> 'admin'
BEGIN
open c_id;
FETCH NEXT FROM c_id into #k
SELECT #i = COUNT(*) FROM PEOPLE_TEST WHERE username <> 'admin';
WHILE(#j <= #i)
BEGIN
UPDATE PEOPLE_TEST
SET
UserName = concat('dummy',#j)
WHERE userid = #k;
print 'i='+CONVERT(VARCHAR,#i)+' j='+CONVERT(VARCHAR,#j)+' k='+CONVERT(VARCHAR,#k);
SET #j = #j + 1;
FETCH NEXT FROM c_id into #k
END;
close c_id
Deallocate c_id
END;
Select * from people_test
GO

Related

IF EXISTS (SELECT) in SQL Server not working as expected

I have a code like this:
IF EXISTS (SELECT * FROM table WHERE id = #id)
BEGIN
UPDATE table
SET stock = stock + #stock
WHERE id = #id
END
ELSE
BEGIN
INSERT INTO [table] ([id], [name], [stock])
VALUES (#id, #name, #stock)
END
But, this code isn't working and I am unable to find the root cause for the same. Can someone please help me?
I do not see any error in your code, I tried to replicate the process and it is working fine for me. Can you tell me what is the error you are facing exactly.
The following is the code I tried to replicate your scenario:
CREATE TABLE stocks (
id INT
,NAME VARCHAR(100)
,stock BIGINT
)
CREATE PROCEDURE InsertStocks #id INT
,#name VARCHAR(100)
,#stock BIGINT
AS
BEGIN
IF EXISTS (
SELECT *
FROM stocks
WHERE id = #id
)
BEGIN
UPDATE stocks
SET stock = stock + #stock
WHERE id = #id
END
ELSE
BEGIN
INSERT INTO stocks (
[id]
,[name]
,[stock]
)
VALUES (
#id
,#name
,#stock
)
END
END
INSERT INTO stocks
VALUES (
1
,'abc'
,200
)
INSERT INTO stocks
VALUES (
2
,'abc'
,300
)
INSERT INTO stocks
VALUES (
3
,'abc'
,500
)
EXEC Insertstocks 1
,'abc'
,700
This is updated successfully in my case.
table is a reserved keyword. so I guess you have a trivial syntax error: Incorrect syntax near the keyword 'table'. Wrap it with [], as you already did for INSERT statement
IF EXISTS (
SELECT * FROM [table] WHERE id = #id)
BEGIN
UPDATE [table] SET stock = stock + #stock
WHERE id = #id
END
ELSE
BEGIN
INSERT INTO [table] ([id]
,[name]
,[stock])
VALUES
(
#id,#name,#stock
)
END
Your code and syntax is correct. Let's see a sample example:
if EXISTS(select * from dbo.tbName where Id=1)
BEGIN
print 1
END
ELSE
BEGIN
print 2
END

SQL Server : loop through every row, add incremented value to column

I have just added a new column, Person_Id_Helper to MyTable. It is supposed to contain 1,2,3 etc, in the order the table is now sorted.
This is what I want to do:
DECLARE #i INT = 1, #NumberOfRows INT = SELECT COUNT(*) FROM MyTable
WHILE(#i <= #NumberOfRows)
BEGIN
-- Person_Id_Helper = #i
-- #i = #i + 1
END
How do I write this?
I think, that it might be the wrong idea to persist the sort oder within a column. But - for sure! - it is the wrong idea to do this in a while loop.
Read about row-based and set-based approaches. SQL demands for set-based thinking...
Look at this as an example how to do this (just paste it into an empty query window and execute, adapt to your needs):
DECLARE #tbl TABLE(SortDate DATE, Inx INT);
INSERT INTO #tbl VALUES({d'2016-01-20'},0)
,({d'2016-01-19'},0)
,({d'2016-01-14'},0)
,({d'2016-01-16'},0);
WITH cte AS
(
SELECT Inx,ROW_NUMBER() OVER(ORDER BY SortDate) AS RN
FROM #tbl
)
UPDATE cte SET Inx=RN;
SELECT * FROM #tbl;
I think this is what you want to achieve -
DECLARE #i INT = 0
UPDATE MyTable
SET
#i = Person_Id_Helper = #i + 1
Now check your column value.
Well we can not use ORDER BY clause in update statement. But to use it here is the updated query.
UPDATE t
SET Person_Id_Helper = rn.RowNum
FROM MyTable t
INNER JOIN (SELECT
ID
,ROW_NUMBER() OVER (ORDER BY ID) AS RowNum
FROM MyTable) rn
ON t.ID = rn.ID
#shungo: Thanks for point out.
Try like this,
DECLARE #tbl TABLE
(
datecolumn DATE,
Person_Id_Helper INT
);
INSERT INTO #tbl
VALUES ({d'2016-01-20'},
0),
({d'2016-01-19'},
0),
({d'2016-01-14'},
0),
({d'2016-01-16'},
0);
SELECT *
FROM #tbl;
UPDATE T
SET Person_Id_Helper = rn
FROM (SELECT Person_Id_Helper,
Row_number()
OVER(
ORDER BY datecolumn) AS rn
FROM #tbl) T
SELECT *
FROM #tbl;
Looping add increment the value using cursor in sqlserver
CREATE TABLE [dbo].[Table1](
[PID] [int] NULL,
[ProductDesc] [nvarchar](50) NULL,
[ProductCode] [nvarchar](10) NULL
) ON [PRIMARY]
GO
INSERT [dbo].[Table1] ([PID], [ProductDesc], [ProductCode], [Person_Id_Helper]) VALUES (1, N'Packet-Eye', N'P001', NULL)
GO
INSERT [dbo].[Table1] ([PID], [ProductDesc], [ProductCode], [Person_Id_Helper]) VALUES (2, N'Wiggy', N'W099 ', NULL)
GO
INSERT [dbo].[Table1] ([PID], [ProductDesc], [ProductCode], [Person_Id_Helper]) VALUES (3, N'Wimax-Lite', N'W001', NULL)
GO
INSERT [dbo].[Table1] ([PID], [ProductDesc], [ProductCode], [Person_Id_Helper]) VALUES (4, N'Wimax-Home', N'e W002 ', NULL)
GO
Declare #count int
DECLARE #PID int
set #count=0
DECLARE c1 CURSOR READ_ONLY
FOR
SELECT [PID] FROM [Table1]
OPEN c1
FETCH NEXT FROM c1 INTO #PID
WHILE ##FETCH_STATUS = 0
BEGIN
set #count=#count+1
update Table1 set Person_Id_Helper=#count where [PID]=#PID
FETCH NEXT FROM c1 INTO #PID END
CLOSE c1
DEALLOCATE c1
select * from Table1

loop in sql stored procedure and removing cursors

I have to modify a STORED procedure that is written by someone else.Basically the stored prcoedure uses a cusrsor to fetch the data from the table and then insert that data in another table. While fetching the code form another table, it also gets some distinct columns from another table Below is my code:
Declare data_cursor cursor for
Select emp_no, emp_name, event_date, Test_no, Code, Test_result
From test_table1
ORDER by emp_no
declare
#empNo varchar(100),
#emp_name varchar(2000),
#eventDate varchar(20),
#TestNo varchar(100),
#Code varchar(100),
#TestReuslt varchar(100),
#ProcessName varchar(100),
#FileProcess varchar(200),
#TestProcess varchar(100),
#countA int,
#error_count int
SELECT #ProcessName = (select distinct userID from test_table1)
SELECT #FileProcess = 'EW' + #ProcessName
Select #TestProcess = (Select distinct userID from test_Table1) + 'TXT'
select #countA = 0
BEGIN tran
OPEN data_cursor
fetch data_cursor into
#empNo ,
#emp_name ,
#eventDate ,
#TestNo ,
#Code ,
#TestReuslt
while (##FETCH_STATUS=0)
begin
insert into TESTTable2
(
empNum, empName, eventDate,TestNum, Code, TestResult, Testprocess, ProcessName)
values (#empNo, #emp_name, #eventDate , #TestNo , #Code, #TestReuslt, #TestProcess, #ProcessName)
if # ERROR > 0
begin
select #error_count = #error_count + 1
end
else
set #record_id = ##Identity
if #code like 'D%'
Insert into TESTTable3
(testProcess, FileProcess, empNum)
values (#TestProcess, #FileProcess, #empNo )
if ##error > 0
begin
select #error_count = #error_count + 1
end
set #countA = #countA + 1
fetch data_cursor into
fetch data_cursor into
#empNo ,
#emp_name ,
#eventDate ,
#TestNo ,
#Code ,
#TestReuslt
if # ERROR > 0
BEGIN
select #error_count = #error_count + 1
end
end
if #error_count > 0
begin
rollback tran
end
else
begin /* ##error = 0 */
commit tran
close data_cursor
deallocate data_cursor
Insert into LOG_File
(Name, Count, Processname)
values ('Test1', #CountA,#ProcessName)
Select 'TotalCount' = #CountA
The reason, I have to modify the above STORED proc now is because of some APPLICATION changes, I am getting around 50 distinct userID's from test_table1 so the above subquery(SELECT #ProcessName = (select distinct userID from test_table1) doesn't work. How can I loop through the above stored proc so that each #ProcessName can get inserted in table TESTTable2 so in other words
I want to pass each userId one at a time and insert it in table test_table1 and other subsequent tables. I can declare another cursor to accomplish this, but I was wondering if there is any better way to rewrite this stored proc and not use the cursor at all.
because of my application changes all these three statements above are throwing the error:
SELECT #ProcessName = (select distinct userID from test_table1)
SELECT #FileProcess = 'EW' + #ProcessName
Select #TestProcess = (Select distinct userID from testTable1) + 'TXT'
I am using sql server 2005.
any help will be greatly appreciated.
declare #countA int=0
begin tran
begin try
insert into TESTTable2(empNum, empName, eventDate,TestNum, Code, TestResult, Testprocess, ProcessName)
Select emp_no, emp_name, event_date, Test_no, Code, Test_result,userID+ 'TXT',userID
From test_table1
ORDER by emp_no
SET #CountA=##ROWCOUNT
Insert into TESTTable3(testProcess, FileProcess, empNum)
Select userID+ 'TXT','EW' + userID,emp_no
From test_table1
Where code like 'D%'
ORDER by emp_no
commit tran
Insert into LOG_File(Name, Count, Processname) values ('Test1', #CountA,'#ProcessName')
end try
begin catch
rollback tran
SET #CountA =0
Insert into LOG_File(Name, Count, Processname) values ('Test1', #CountA,'#ProcessName')
SELECT ERROR_NUMBER() AS ErrorNumber,ERROR_MESSAGE() AS ErrorMessage
end catch
Select #CountA [TotalCount]

How to execute the GO statement with dynamic count?

How to set dynamic count for GO statement?
I am getting the following error:
A fatal scripting error occurred.Incorrect syntax was encountered
while parsing Go.
when I tried to run the below query:
Declare #count int
Select #count=COUNT(*) From Users
Insert Into #DummyUsers
Select * from Users where UserName = 'Sachin'
GO #Count
But the same is working fine when I use the below query with hard coded count.
Declare #count int
Select #count=COUNT(*) From Users
Insert Into #DummyUsers
Select * from Users where UserName = 'Sachin'
GO 5
Appreciate your suggestions if you have any idea on this.
You can't. As soon as SSMS encounters GO the batch is terminated and your variable no longer exists.
You can't use a variable for the count parameter to GO, but in your example (which may be contrived) you could just join back to Users :
Insert Into #DummyUsers
Select U.* from Users U
INNER JOIN Users U2
ON U.UserName = 'Sachin'
Other options:
Dynaimc SQL (building up SQL by concatenating strings) and executing via SQLCMD.EXE or OSQL.EXE
Using a WHILE loop with a counter
If you simply want to insert a repeated row you could use a CTE or numbers table.
-- Sample data.
declare #Users as Table ( UserId Int Identity, Name VarChar(16) );
insert into #Users ( Name ) values
( 'Bob' ), ( 'Carol' ), ( 'Ted' ), ( 'Alice' );
select * from #Users;
-- Load another table with repetitions of a single user.
declare #TempUsers as Table ( UserId Int, Name VarChar(16) );
declare #Repetitions as Int = ( select Count(*) from #Users );
with TempUsers as (
select UserId, Name, 1 as Repetitions
from #Users
where Name = 'Ted'
union all
select UserId, Name, Repetitions + 1
from TempUsers
where Repetitions < #Repetitions
)
insert into #TempUsers ( UserId, Name )
select UserId, Name
from TempUsers;
select * from #TempUsers;
Instead try this.
DECLARE #cntr INT=1
WHILE #cntr <= #count
BEGIN
INSERT INTO #DummyUsers
SELECT *
FROM Users
WHERE UserName = 'Sachin'
SET #cntr+=1
END
I would just loop it
Declare #count int
Select #count=COUNT(*) From Users
WHILE(#count > 0)
BEGIN
Insert Into #DummyUsers
Select *
FROM Users
WHERE UserName = 'Sachin'
SET #count = #count - 1;
END
While I agree with the others that there is likely a better way to achieve what you are trying to do, if there is some limitation that we are not seeing, you could look into using a sequence
The sequence you create persists and can be reset as needed and you can "increment" it by calling the NEXT VALUE FOR function

get error in sql stored procedure table type

i have this procedure and i want insert list of value into table,and i want check duplicate value and return this but i get this error
ERROR:
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
ALTER PROCEDURE [dbo].[insertData]
#Value insertTbl READONLY,
#Result INT OUTPUT
AS
BEGIN
BEGIN TRY
IF (SELECT COUNT(Id)
FROM #Values
WHERE Id IN (SELECT Id
FROM [dbo].[username])) = 0
BEGIN
INSERT INTO dbo.username ( Id, NAME )
SELECT Id,
NAME
FROM #Values
WHERE Id NOT IN (SELECT Id
FROM [dbo].[username])
SELECT #Result = 101
END
ELSE
SELECT #Result = (
SELECT Id
FROM #Values
WHERE Id IN (SELECT Id
FROM [dbo].[username])
)
END TRY
BEGIN CATCH
SELECT ERROR_MESSAGE()
END CATCH
END
Please try this.
I have changed the return type to VARCHAR. That would return a CSV (e.g. 1,3,9...)
The other option is to return a result set. For this replace SELECT #Result = to INSERT INTO #Result...
Hope this helps.
ALTER PROCEDURE [dbo].[insertData]
#Value insertTbl READONLY,
#Result VARCHAR(500) OUTPUT
AS
BEGIN
BEGIN TRY
IF (SELECT COUNT(Id)
FROM #Values
WHERE Id IN (SELECT Id
FROM [dbo].[username])
) = 0
BEGIN
INSERT INTO dbo.username (Id,NAME)
SELECT Id,
NAME
FROM #Values
WHERE Id NOT IN (SELECT Id
FROM [dbo].[username])
SELECT #Result = 101
END
ELSE
BEGIN
SELECT #Result = (SELECT STUFF((SELECT ', ' + CAST(ID AS VARCHAR(5))
FROM #Values
WHERE Id IN (SELECT Id
FROM [dbo].[username])
ORDER BY Id FOR XML PATH('')),1,2,''))
END
END TRY
BEGIN CATCH
SELECT ERROR_MESSAGE()
END CATCH
END
Probably this line
SELECT #Result=(SELECT Id FROM #Values WHERE Id IN (SELECT Id FROM [dbo].[username]))
return more than one row. You should change the query to return only one value as below
SELECT #Result=(SELECT top 1 Id FROM #Values WHERE Id IN (SELECT Id FROM [dbo].[username]))
or you should change your logic. Alternative way is to use temprary table to return listo of ID. Try below solution
-- create temporary table before (!) creating procedure
create table #Resulttab
(
Result int
)
go
ALTER PROCEDURE [dbo].[insertData]
#Value insertTbl READONLY,
#Result INT OUTPUT -- in this solution I think you don't need this parameter
AS
BEGIN
BEGIN TRY
IF (SELECT COUNT(Id)
FROM #Values
WHERE Id IN (SELECT Id
FROM [dbo].[username])) = 0
BEGIN
INSERT INTO dbo.username ( Id, NAME )
SELECT Id,
NAME
FROM #Values
WHERE Id NOT IN (SELECT Id
FROM [dbo].[username])
SELECT #Result = 101
END
ELSE
insert into #Resulttab
SELECT Id
FROM #Values
WHERE Id IN (SELECT Id
FROM [dbo].[username])
END TRY
BEGIN CATCH
SELECT ERROR_MESSAGE()
END CATCH
END
go
You can use it that way:
-- create temporary table before run procedure
create table #Resulttab
(
Result int
)
-- run procedure with parameters
exec insertData ...
--after run procedure you can check list of your IDs
select Result from #Resulttab