How to write this query in SQL server 2008 - sql-server-2008

I have a requirement to insert more than one record into the table where the stored procedure will return the value for insertion. Please consider my logic.
Query Logic
foreach(var a in (select id from table1))
{
insert into table2 values(a,DateTime.Now)
}
I need the same above logic needs to be done in SQL server. Any help to this solution will be appreciated.
Thanks,

declare #a int=0
while(#a<10)
begin
if(#a in (select id from table1))
begin
insert into table2 values(a,DateTime.Now)
set #a=#a+1
end
end

I tried this and working well. Thanks to #Nikola Markovinović
insert into table2(idColumn, dateColumn) select id, getdate() from table1

hope this helps..
DECLARE #intFlag INT
SET #intFlag = 1
WHILE (#intFlag <=5)
BEGIN
PRINT #intFlag
SET #intFlag = #intFlag + 1
IF #intFlag = 4
BREAK;
END
GO

declare #a int = 0, #n int, #i int = 1
select #n=COUNT(*) from table1
while #i < #n
begin
insert into table2 values
select x.a,Getdate() from
(select ROW_NUMBER() over (order by [key]) as slno,* from table1 ) as x where x.slno = #i
set #i=#i+1;
end

Related

Loop through a split string variable to insert rows in a stored procedure in SQL Server 2008

I am working on SQL Server 2008 to create a stored procedure that:
takes a string variable like this: '1,2,3'
splits the string using a table-valued function to get each value separately
and then inserts each value into a new row in a table
What I am trying to do is something like this:
WHILE (select vlaue FROM dbo.SplitString('1,2,3',',')) has rows
insert into TableName (col1,col2) values (col1Data, value)
I am having a hard time trying to find the right syntax for this.
I use this Table-valued function:
CREATE FUNCTION [dbo].[Split] (#sep char(1), #s varchar(512))
RETURNS table
AS
RETURN (
WITH Pieces(pn, start, stop) AS (
SELECT 1, 1, CHARINDEX(#sep, #s)
UNION ALL
SELECT pn + 1, stop + 1, CHARINDEX(#sep, #s, stop + 1)
FROM Pieces
WHERE stop > 0
)
SELECT pn,
SUBSTRING(#s, start, CASE WHEN stop > 0 THEN stop-start ELSE 512 END) AS s
FROM Pieces
)
GO
Which takes a string with a separator and returns a table with two columns the first returns a 1-based position and the second the element at that position in the string:
Usage:
SELECT * FROM dbo.Split(',', '1,2,3')
Returns:
pn s
1 1
2 2
3 3
To Insert results into a table:
INSERT INTO TableName (Col1)
SELECT S FROM dbo.Split(',', '1,2,3)
For your specific example change your syntax to be:
insert into TableName (col1,col2)
select col1Data, value FROM dbo.SplitString('1,2,3',',')
The typical INSERT INTO ... SELECT ... should do:
INSERT INTO TableName (col1,col2)
SELECT #col1Data,value FROM dbo.SplitString('1,2,3',','))
If someone else is looking for this, I was about to make a split function as several answers mentioned but noticed there's a built-in function that does this already.
string_split was added in MSSQL 2016.
INSERT INTO Project.FormDropdownAnswers (FkTableId, CreatedBy, CreatedDate)
SELECT 123, TRY_CAST(value AS INT), #username, getdate()
FROM string_split('44,45,46,47,55',',')
https://learn.microsoft.com/en-us/sql/t-sql/functions/string-split-transact-sql
CREATE TABLE tablename
(
id SMALLINT ,
value INT
)
INSERT INTO tablename ( id, value )
SELECT * FROM dbo.Split('1,2,3',',')
try this....
If need to use as variables there is 2 nice options:
Procedure MF_SPLIT
CREATE PROC [MF_SPLIT] (#ELS NVARCHAR(MAX)=NULL OUTPUT, #RET NVARCHAR(MAX)=NULL OUTPUT, #PROC NVARCHAR(MAX)=NULL) AS BEGIN
IF #ELS IS NULL BEGIN
PRINT ' #ELS
List of elements in string (OUTPUT)
#RET
Next return (OUTPUT)
#PROC
NULL = '','', content to do split
Example:
DECLARE #NAMES VARCHAR(100) = ''ERICK,DE,VATHAIRE''
DECLARE #N VARCHAR(100)
WHILE #NAMES IS NOT NULL BEGIN
EXEC MF_SPLIT #NAMES OUTPUT, #N OUTPUT
SELECT List = #NAMES, ActiveWord = #N
END'
RETURN
END
SET #PROC = ISNULL(#PROC, ',')
IF CHARINDEX(#PROC, #ELS) = 0 BEGIN
SELECT #RET = #ELS, #ELS = NULL
RETURN
END
SELECT
#RET = LEFT(#ELS, CHARINDEX(#PROC, #ELS) - 1)
, #ELS = STUFF(#ELS, 1, LEN(#RET) + 1, '')
END
Usage:
DECLARE #NAMES VARCHAR(100) = '1,2,3'
DECLARE #N VARCHAR(100)
WHILE #NAMES IS NOT NULL BEGIN
EXEC MF_SPLIT #NAMES OUTPUT, #N OUTPUT
SELECT List = #NAMES, ActiveWord = #N
END
Procedure MF_SPLIT_DO (Depends of MF_SPLIT), less sintax to use BUT the code will be in a string and use default variable "#X"
CREATE PROC MF_SPLIT_DO (#ARR NVARCHAR(MAX), #DO NVARCHAR(MAX)) AS BEGIN
--Less sintax
DECLARE #X NVARCHAR(MAX)
WHILE #ARR IS NOT NULL BEGIN
EXEC MF_SPLIT #ARR OUT, #X OUT
EXEC SP_EXECUTESQL #DO, N'#X NVARCHAR(MAX)', #X
END
END
Usage:
EXEC MF_SPLIT_DO '1,2,3', 'SELECT #X'

How to update/Edit table through CSVs?

I stored 2 contact numbers in a table corresponding to one companyID in companycontactno. table. I did that using extracting values from CSV in Stored procedure.
If I want to edit those contact numbers Corresponding to company ID how am I going to do that?
This is the storedProcedure I will use for editing contact numbers .. I am having difficulty in updating it .. please help
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
CREATE PROCEDURE dbo.EditCompanyDetails
(
#OldCompanyName varchar(max),
#NewCompanyName varchar(max),
#newAddress varchar(max),
#newMailID varchar(max),
#Temp varchar(8000)
)
AS
BEGIN
SET NOCOUNT ON;
declare #compID int
DECLARE #c int, #a varchar(max), #id int, #variable varchar(8000), #max int
DECLARE #Temp_Table table (serial_no int Identity(1,1), value varchar(max))
--PROCEDURE--
--Editing Company Table--
set #compID=(Select Company.CompanyID from Company where Company.CompanyName=#OldCompanyName)
update Company
set CompanyName=#NewCompanyName, [Address]=#newAddress, Email=#newMailID
where Company.CompanyID=#compID
--For CONTACT NUMBERS
--Using Table to store CSV seperately in each row--
select #c = CHARINDEX(',', #Temp)
while #c > 0
BEGIN
insert into #Temp_Table
select LEFT(#Temp, #c - 1)
select #Temp = right(#Temp, LEN(#Temp) - #c)
select #c = CHARINDEX(',', #Temp)
END
--Update Table CompanyContactNo
--CompanyContactNo have following Columns:
--CNoID (PK)
--CompanyID (references PK in Company table
--ContactNumber
set #max= (select MAX(serial_no) from #Temp_Table)
while #max > 0
BEGIN
set #variable = (select value from #Temp_Table where serial_no=#max)
update CompanyContactNo
set ContactNumber=#variable
where CompanyID=#compID
set #max = #max-1
END
End
GO
Assuming you will only have 2 rows, and you know that there are 2 contact rows in the CompanyContactNo table, you could execute 2 Update statements that would each affect a different row:
UPDATE CompanyContactNo
Set ContactNumber=
(SELECT value FROM #Temp_Table WHERE serial_no = (SELECT MAX(serial_no) FROM #Temp_Table))
WHERE
CompanyID=#compID
AND (CNoId = select MAX(CNoId) FROM CompanyContactNo WHERE CompanyID = #compID)
and then for second contact number:
UPDATE CompanyContactNo
SET ContactNumber=
(SELECT value FROM #Temp_Table WHERE serial_no = (SELECT MIN(serial_no) FROM #Temp_Table))
WHERE
CompanyID=#compID
AND (CNoId = select MIN(CNoId) FROM CompanyContactNo WHERE CompanyID = #compID)

mysql if not exist

I am coming from MSSQL, and now using Mysql, this may be a easy one but how do you execute a
if not exist statement. thanks
IF NOT EXISTS(SELECT * from users WHERE Username = spUsername)
BEGIN
INSERT into users(ID,Username,Password,Email,Birthdate,DateJoin)
VALUES(UUID(),spUsername,spPassword,spEmail,spBirthDate,NOW());
END
Im not a database expert by any means but this is how I do it.
http://www.somethinghitme.com/2010/05/06/mysql-stored-procedures-if-not-exists/
DECLARE SomeId int;
DECLARE CheckExists int;
SET CheckExists = 0;
SELECT 1 INTO CheckExists from lookup_table WHERE someField = in_SomeParam LIMIT 1;
IF (CheckExists > 0) THEN
SELECT id INTO SomeId FROM lookup_table WHERE someField = in_SomeParam;
ELSE
INSERT INTO lookup_table (someField ) VALUES(in_SomeParam);
SELECT SomeId = LAST_INSERT_ID();
END IF;

How to loop the data and if username exists append incremental number e.g. JOHSMI1 or JOHSMI2

I have a userid table
UserId
JHOSMI
KALVIE
etc...
What I would like to do is create a select statement and pass user id, if the userid already exists then append 1 to the id, This gets complicated if you already have JHOSMI, JHOSMI1, then I want to return JHOSMI2.
Really appreciate help here.
Thanks in advance
edited 21-Jul
this is what i got so far.. but not working the way
select #p AS StaffID,
#old_p := #p,
#Cnt := #Cnt+1 As Lvl,
(SELECT #p :=Concat(#i, #Cnt)
FROM departmenttaff
WHERE upper(trim(UserId)) = upper(trim(StaffID))
AND upper(trim(department)) like upper(trim('SERVICE'))
) AS dummy
FROM (
SELECT
#i := upper(trim('JOHSMI')),
#p := upper(trim('JOHSMI')),
#old_p :='',
#Cnt:=0
) vars,
departmenttaff p
WHERE #p <> #old_p
order by Lvl Desc LIMIT 1;
This will do exactly what you want. You will need a unique constraint on your column.
You might also need to add in error code if success = 0.
This is in MSSQL, you will need to add the relevant commands for MySQL. I do not have MySQL so I cannot test it.
NOTE: You can replace the try catch with some IF EXISTS logic. I just prefer the try catch because its more stable for multiple threads.
begin tran
select * from #tmp
declare #success bit
declare #name varchar(50)
declare #newname varchar(50)
declare #nextid int
declare #attempts int
set #name = 'brad2something'
set #success = 0
set #attempts = 0
while #success = 0 and #attempts < 5 begin
begin try
set #attempts = #attempts + 1 -- failsafe
set #newname = #name
if exists (select * from #tmp where username = #name) begin
select #nextid = isnull(max(convert(int, substring(username, LEN(#name) + 1, 50))), 0) + 1
from #tmp where username like #name + '%' and isnumeric(substring(username, LEN(#name) + 1, 50)) = 1
set #newname = #name + CONVERT(varchar(20), #nextid)
end
insert into #tmp (username) values (#newname)
set #success = 1
end try begin catch end catch
end
--insert into #tmp (username)
--select
select #success
select * from #tmp
rollback
/*
drop table #tmp
create table #tmp (
username varchar(50) not null unique
)
insert into #tmp (username)
select 'brad'
union all select 'brad1'
union all select 'brad2something5'
union all select 'brad2'
union all select 'laney'
union all select 'laney500'
*/
I noticed you want to back fill data. If you want to back fill then this will work. It is extremely inefficient but there is no way around it. There is optimizing code you can put in for when an "error" occurs to prevent all previous counts from happening, but this will work.
begin tran
select * from #tmp
declare #success bit
declare #name varchar(50)
declare #newname varchar(50)
declare #nextid int
declare #attempts int
set #name = 'laney'
set #success = 0
set #attempts = 0
set #nextid = 1
while #success = 0 and #attempts < 5 begin
begin try
if exists (select * from #tmp where username = #name) begin
set #newname = #name + CONVERT(varchar(20), #nextid)
while exists (select * from #tmp where username = #newname) begin
set #nextid = #nextid + 1
set #newname = #name + CONVERT(varchar(20), #nextid)
end
end else
set #newname = #name
set #attempts = #attempts + 1 -- failsafe
insert into #tmp (username) values (#newname)
set #success = 1
end try begin catch end catch
end
--insert into #tmp (username)
--select
select #success
select * from #tmp
rollback
/*
drop table #tmp
create table #tmp (
username varchar(50) not null unique
)
insert into #tmp (username)
select 'brad'
union all select 'brad1'
union all select 'brad2something5'
union all select 'brad2'
union all select 'laney'
union all select 'laney500'
*/
Is it mandatory to have the count in same column? its better to have it in a different integer column. Anyways, if this is the requirement then select userid from table where userid like 'JHOSMI%', then do extract the number using mysql substr function.
For other people who might find this, here's a version in PostgreSQL:
create or replace function uniquify_username(varchar) returns varchar as $$
select $1 || coalesce((max(num) + 1)::varchar, '')
from
(select
substring(name, '^(.*?)[0-9]*$') as prefix,
coalesce(substring(name, '.*([0-9]+)$'), '0')::integer as num
from user1) users
where prefix = $1
$$ LANGUAGE sql;
I think it could be adapted to MySQL (though probably not as a stored procedure) but I don't have a MySQL server handy to do the conversion on.
Put a UNIQUE constraint on the column.
You didn't say what language you are using, so use this pseudo code
counter = 0
finished = false
while finished = false
{
try
{
if counter >= 1 then name = name + counter
counter = counter + 1
insert into table (name)
}
}
This code is extremely finicky. But will get the job done and there is no real other way to do this except for in sql, and you will always have some type of try catch to avoid two processes running at the same time. This way you use the unique key constraint to force the error, and supress it because it is expected.
I in no way condone using try/catch for business logic like this, but you are putting yourself in a situation thats unavoidable. I would say put the ID in a seperate column and make a unique constraint on both fields.
Proper solution:
Columns: Name, ID, Display Name
Unique constraint on: Name, ID
Display Name is a computed column (virtual) is Name + ID
If you do it this way, then all you have to do is INSERT INTO table (name, (select max() from table))

Dealing with conditionally-executed SELECT statements

i have this sp: using sql server 2008
create procedure SelectTopCounts
#Id bigint = null,
#Count int = null,
#GetAll bit = 0
as
begin
set nocount on
IF (#Count IS NULL)
SELECT #Count = 15 --default
if(#GetAll = 1)
begin
select col,col2... .......
--very long select statement...
end
if(#Count is not null)
begin
select top #count .....
--very long select statement...
end
Is there a way I can have only ONE select statement instead of duplicating within the if and else condition?
Assuming your table will always have <= 2 billion rows, replace all the IFs/ELSEs with this:
SELECT TOP(COALESCE(CASE #GetAll WHEN 1 THEN 2000000000 END, #Count, 15))
col1, col2
FROM ...
-- I assume the #Id comes into play somehow...
-- WHERE ID_column = COALESCE(#Id, ID_column);