How to update/Edit table through CSVs? - sql-server-2008

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)

Related

Insert rows into table with single ID and rows from two comma separated lists

I have two comma separated list which I know belong to a single ID, so I need to insert each corresponding value from the two comma separated list into the table with the common ID.
I have #listA, #listB
and their values would be
#listA ='BRE,CT,DIA,DEXA'
#listB ='2.00,3.00,4.00,5.00'
and I know the ID to which these values belong, say
#SpecID=1
Now what I want is to insert data into a table which contains all three columns like this
Please provide me the steps to approach this problem.
Step 1: I have created the below Function that accepts the Comma separated list items and a Delimiter. It returns the split values along with a RowNumber.
CREATE FUNCTION dbo.SplitString
(
#Delimiter VARCHAR(1),
#InputString VARCHAR(MAX)
)
RETURNS
#ListItems TABLE
(
RowNumber INT,
List VARCHAR(50)
)
AS
BEGIN
DECLARE #Position INT, #RowNumber INT = 1, #ListItem VARCHAR(MAX)
WHILE CHARINDEX(#Delimiter, #InputString) > 0
BEGIN
SELECT #Position = CHARINDEX(#Delimiter, #InputString)
SELECT #ListItem = SUBSTRING(#InputString, 1, #Position-1)
INSERT INTO #ListItems
SELECT #RowNumber,#ListItem
SELECT #InputString = SUBSTRING(#InputString, #Position+1, LEN(#InputString)-#Position)
SET #RowNumber = #RowNumber + 1
END
INSERT INTO #ListItems
Select #RowNumber,#InputString
RETURN
END
Step 2: Using the above function, I split the comma separated list items and created 2 table variables.
DECLARE #listA VARCHAR(MAX), #listB VARCHAR(MAX), #SpecID INT, #Delimiter VARCHAR(1)
SET #listA= 'BRE,CT,DIA,DEXA'
SET #listB ='2.00,3.00,4.00,5.00'
SET #SpecID = 1
SET #Delimiter = ','
DECLARE #ListItems Table
(
SpecID INT,
listA VARCHAR(50),
listB VARCHAR(50)
)
DECLARE #TableListA Table
(
RowNumber INT,
ListA VARCHAR(50)
)
DECLARE #TableListB Table
(
RowNumber INT,
ListB VARCHAR(50)
)
INSERT INTO #TableListA
SELECT * FROM SplitString(#Delimiter,#listA)
INSERT INTO #TableListB
SELECT * FROM SplitString(#Delimiter,#listB)
INSERT INTO #ListItems
SELECT
#SpecID,
A.ListA,
B.ListB
FROM #TableListA A
INNER JOIN #TableListB B ON B.RowNumber = A.RowNumber
SELECT * FROM #ListItems
Please use the SQL Fiddle to check the output: http://sqlfiddle.com/#!6/9e12b/1/0
You will have to do it like this:
1) Split using `,`
2) Have 2 arrays
3) Both need to have the same size so iterate over 1 array
4) Use the index within the loop to insert the values.

Loop over SQL stored procedure

I have a stored procedure In which insert query fire on two table.
masters_table,child_table as you see here #Value1,#Value2,#Value3,#Value4 having parameter. I have written insert statement for each block, can I make use loop here to avoid multiple insert write for each block, suppose I have nth value then i have to write nth time block wise insert query, any better way to achieve this task
Create proc sp_insert_master_child
(
#Details_Data custom_tb READONLY,
#Value1 nvarchar(500),
#Value2 nvarchar(500),
#Value3 nvarchar(500),
#Value4 nvarchar(500),
#Value5 nvarchar(500),
#Value6 nvarchar(500),
#Value7 nvarchar(500)
)
as begin
declare #id bigint
------- block 1
if #Value1 is not null
begin
insert into masters_table (col1,col2,col3))
select Substring(#Value1, 1,Charindex(',', #Value1)-1) as col_value_1,
Substring(#Value1, Charindex(',', #Value1)+1, LEN(#Value1)) as col_value_2
select #id = ##IDENTITY
insert into child_table (col1,col2,col3)
SELECT #id,col_val_2,col_val_3 FROM #Details_Data WHERE blockType='blk_1';
end
------ block 2
if #Value2 is not null
begin
insert into masters_table (col1,col2,col3))
select Substring(#Value2, 1,Charindex(',', #Value2)-1) as col_value_1,
Substring(#Value2, Charindex(',', #Value2)+1, LEN(#Value2)) as col_value_2
select #id = ##IDENTITY
insert into child_table (col1,col2,col3)
SELECT #id,col_val_2,col_val_3 FROM #Details_Data WHERE blockType='blk_2';
end
------ block 3
if #Value3 is not null
begin
insert into masters_table (col1,col2,col3))
select Substring(#Value3, 1,Charindex(',', #Value3)-1) as col_value_1,
Substring(#Value3, Charindex(',', #Value2)+1, LEN(#Value3)) as col_value_2
select #id = ##IDENTITY
insert into child_table (col1,col2,col3)
SELECT #id,col_val_2,col_val_3 FROM #Details_Data WHERE blockType='blk_3';
end
------ block 4
.......
------ block 5
.......
You can insert all parameters into a table .Use while loop and read one by one row (parameter) from table .
Ex:
declare #x int
set #x= 1
declare #tmp table ( val int )
while (#x < noofrows)
begin
***********
Use Top #x value to get row(parameter in your case) from table
perform your operation
*************
increment x(set #X=#x+1)
end

Sql server stored Procedure for cut records by comparing between two tables

I have two tables i should make a comparing between those two tables, the first table have one column this column is the full URL and the other table have two columns first column is URLCategory and the other one is the number of how many / i should cut before in the other table column URL
the first table is
URL
http://10.6.2.26/ERP/HRServices/WorkflowService.asmx
http://195.170.180.170/SADAD/PaymentNotificationService.asmx
http://10.6.2.26/ERP/HRServices/WorkflowService.asmx
http://10.6.2.26/ERP/HRServices/WorkflowService.asmx
http://10.6.2.26/ERP/HRServices/WorkflowService.asmx
http://217.146.8.6/din.aspx?s=11575802&client=DynGate&p=10002926
http://195.170.180.170/SADAD/PaymentNotificationService.asmx
http://10.6.2.26/ERP/HRServices/WorkflowService.asmx
http://195.170.180.170/SADAD/PaymentNotificationService.asmx
http://www.google.com/
the Second table which is hould compare with
URL CUT_BEFORE
http://10.6.2.26 3
http://217.146.8.6 1
http://195.170.180.170 2
I should compare between second table with first column to be like that
URL
http://10.6.2.26/ERP/HRServices
http://195.170.180.170/SADAD
http://10.6.2.26/ERP/HRServices
http://10.6.2.26/ERP/HRServices
http://10.6.2.26/ERP/HRServices
http://217.146.8.6
http://195.170.180.170/SADAD
http://10.6.2.26/ERP/HRServices
http://195.170.180.170/SADAD
http://www.google.com/
What's the procedure script with while loop to do something like that in SQLServer
waiting for your answers
Thanks
Please see the code below.
--------------------------------------------------------------------------------
DECLARE #URL TABLE (ID INT IDENTITY(1,1), URL VARCHAR(200))
INSERT INTO #URL VALUES
('http://10.6.2.26/ERP/HRServices/WorkflowService.asmx'),
('http://195.170.180.170/SADAD/PaymentNotificationService.asmx'),
('http://10.6.2.26/ERP/HRServices/WorkflowService.asmx'),
('http://10.6.2.26/ERP/HRServices/WorkflowService.asmx'),
('http://10.6.2.26/ERP/HRServices/WorkflowService.asmx'),
('http://217.146.8.6/din.aspx?s=11575802&client=DynGate&p=10002926'),
('http://195.170.180.170/SADAD/PaymentNotificationService.asmx'),
('http://10.6.2.26/ERP/HRServices/WorkflowService.asmx'),
('http://195.170.180.170/SADAD/PaymentNotificationService.asmx'),
('http://www.google.com/')
DECLARE #MAP TABLE (ID INT IDENTITY(1,1), URL VARCHAR(200),CUT INT)
INSERT INTO #MAP VALUES
('http://10.6.2.26',3),
('http://217.146.8.6',1),
('http://195.170.180.170',2)
--------------------------------------------------------------------------------
See the code from here
DECLARE #DEST TABLE
(ID INT, URL VARCHAR(200),URLREF VARCHAR(200),CUT INT,RESULT VARCHAR(200))
INSERT INTO #DEST (ID,URL,URLREF,CUT)
SELECT A.ID,A.URL,B.URL URLREF,B.CUT
FROM #URL A,#MAP B
WHERE LEFT(A.URL,LEN(B.URL)) = B.URL
DECLARE #A INT = 1,
#B INT,
#C VARCHAR(200),
#D VARCHAR(200),
#E INT,
#F INT,
#G INT,
#H VARCHAR(200)
SET #B = (SELECT COUNT(*) FROM #DEST)
WHILE #A<= #B
BEGIN
SET #C = ( SELECT SUBSTRING(URL,LEN(URLREF)+2,LEN(URL))
FROM #DEST WHERE ID = #A)
SET #H = ''
SET #G = 0
SET #F = 1
SET #E = LEN(#C)
WHILE #F <= #E
BEGIN
SET #D = SUBSTRING(#C,#F,1)
IF #D = '/'
BEGIN
SET #G = #G + 1
IF #G = (SELECT CUT-1 FROM #DEST WHERE ID = #A)
BEGIN
SET #F = #E
END
END
SET #H = #H + #D
SET #F = #F + 1
END
UPDATE #DEST
SET RESULT = URLREF +'/'+ LEFT(#H,LEN(#H)-1)
WHERE ID = #A
SET #A = #A + 1
END
UPDATE #DEST
SET RESULT = URLREF
WHERE CUT = 1
SELECT RESULT FROM #DEST
Result:
Added comment:
If We use the above two set of code in an SSMS window, we wont get an error.
I tried it with empty values in both #URL and #MAP. Still I am not getting error.
If you are making it to varchar(max), please make sure that you make changes everywhere..

Loop items in list of user defined table types

I have simple table with 2 columns CarId int, primary key and CarName, varchar.
I need to create a stored procedure which accepts a list of cars. If car with CarId doesn't exist, I want to insert that car, and if already exists, I want to update it.
I created a user-defined table type CarType:
CREATE TYPE dbo.CarType
AS TABLE
(
CARID int null,
CARNAME varchar(800) not null,
);
and stored procedure InsertCars:
CREATE PROCEDURE dbo.InsertCars
#Cars AS CarType READONLY
AS
DECLARE #CarCount INT = 0;
DECLARE #Counter INT = 0;
BEGIN
SET #CarsCount = (SELECT COUNT(CarId) FROM #Cars);
WHILE(#Counter < #CarsCount)
BEGIN TRY
--how get item from list Cars?
#CurrentCar = Cars(#Counter)
IF EXISTS(SELECT 1 FROM Cars WHERE CarsId = CurrentCar.CarId)
--if doesn’t exist insert
BEGIN
INSERT INTO CARS(CARID, CARNAME)
SELECT * FROM #CurrentCar;
END
ELSE
BEGIN
--if exist update
END
END
SET #Counter= #Counter + 1;
END TRY
BEGIN CATCH
Print (ERROR_MESSAGE());
END CATCH
END
I don't know how get current car in loop from list of cars (parameter Cars in the stored procedure).
Or some elegant solution for this problem.
It seems you may get rid of loop here:
CREATE PROCEDURE dbo.InsertCars
#Cars AS CarType READONLY
AS
BEGIN
SET NOCOUNT ON;
UPDATE c
SET c.CARNAME = c2.CARNAME
FROM Cars c
JOIN #Cars c2 on c2.CARID = c.CARID;
INSERT INTO Cars(CARID, CARNAME)
SELECT c.CARID, c.CARNAME
FROM #Cars c
WHERE NOT EXISTS (SELECT 1 FROM Cars WHERE CARID = c.CARID);
END
or (using merge construct):
CREATE PROCEDURE dbo.InsertCars
#Cars AS CarType READONLY
AS
BEGIN
SET NOCOUNT ON;
MERGE Cars AS target
USING (SELECT CARID, CARNAME FROM #Cars) AS source (CARID, CARNAME)
ON (target.CARID = source.CARID)
WHEN MATCHED THEN
UPDATE SET CARNAME = source.CARNAME
WHEN NOT MATCHED THEN
INSERT (CARID, CARNAME)
VALUES (source.CARID, source.CARNAME);
END

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))