I have a string with separator. Now I need to insert these values into table extracting data from it. Each set of data is seperated by '|' and each value is seperated by '~'
EX: @data='col1 ~ 100 ~ 200 | col2 ~ 700 ~ 800 | col3 ~ 180 ~ 800 ' Now I need to insert this value to table t1.
**Table T1**
A B C
COL1 100 200
COL2 700 800
COL3 180 800
Have you considered using SSIS for loading the data into the table? If, for example, your string data is in a text-file, you could simply use the built-in Flat File Source-component of SSIS, to specify that '|' should act as a row separator and '~' should act as a column separator.
If you cannot use SSIS, you will have to use a T-SQL loop. Inside the loop, you could use the CHARINDEX
and SUBSTRING
functions to cut the string apart, and construct SQL INSERT statements on the fly.
Step 1. Create a String_Split function. Please follow this link for various options.
Go
CREATE FUNCTION [dbo].[string_split](
@delimited NVARCHAR(MAX),
@delimiter NVARCHAR(100)
) RETURNS @t TABLE (id INT IDENTITY(1,1), val NVARCHAR(MAX))
AS
BEGIN
DECLARE @xml XML
SET @xml = N'<t>' + REPLACE(@delimited,@delimiter,'</t><t>') + '</t>'
INSERT INTO @t(val)
SELECT r.value('.','varchar(MAX)') as item
FROM @xml.nodes('/t') as records(r)
RETURN
END
GO
Step 2. Compose the INSERT queries from your data as below. I have used a temp table here, you can easily replace it with your actual table. Please note I did not replace spaces from your @data
(you can adjust this SQL as per your needs).
go
CREATE TABLE #target_table (A VARCHAR(100), B INT, C INT);
DECLARE @temp TABLE (q varchar(max));
DECLARE @data varchar(max)='col1 ~ 100 ~ 200 | col2 ~ 700 ~ 800 | col3 ~ 180 ~ 800' ;
DECLARE @inserts varchar(max)='';
INSERT INTO @temp
SELECT 'SELECT ''' + REPLACE(val, '~', ''',''') +'''' from dbo.string_split(@data, '|');
SELECT @inserts = @inserts + CHAR(13) + CHAR(10) + q + ' UNION ALL '
FROM @temp
SELECT @inserts = 'INSERT INTO #target_table(A, B, C) ' + @inserts
SELECT @inserts = SUBSTRING(@inserts, 1, LEN(@inserts) - LEN(' UNION ALL'))
--print(@inserts)
EXEC(@inserts)
SELECT * FROM #target_table
If you do not wish to change the #target_table in the above SQL, you could write a SELECT INTO query at the end.
INSERT INTO <Your_Actual_Target_Table>(cols...)
SELECT cols...
FROM #target_table
Note: Please remember to replace any single quotes within the @data with two single quotes, an error will be produced otherwise.
This is quite a brittle answer (ie very tailored to this specific purpose rather) but...
Create a split function that splits a string into 3 columns (ie splits a string like 'col1~100~200' into a table entry with 3 columns)
CREATE FUNCTION [dbo].[SplitThreeStringList] ( @List NVARCHAR(MAX), @SplitOn NVARCHAR(5) ) RETURNS @RtnTable TABLE ( Id NVARCHAR(MAX), A INT, B INT ) AS BEGIN DECLARE @TempString NVARCHAR(MAX); DECLARE @ValueLen int; DECLARE @idlen int; SET @idlen = LEN(SUBSTRING(@List, 0, CHARINDEX(@SplitOn, @List))); SET @TempString = SUBSTRING(@List,CHARINDEX(@SplitOn,@List)+LEN(@SplitOn),LEN(@List)-@idlen-LEN(@SplitOn)); SET @ValueLen = LEN(SUBSTRING(@TempString,0,CHARINDEX(@SplitOn,@TempString))); INSERT INTO @RtnTable (Id, A, B) SELECT Id = SUBSTRING(@List,1,CHARINDEX(@SplitOn,@List)-1), A = CONVER(int, SUBSTRING(@TempString,1,@ValueLen)), B = CONVERT(int, SUBSTRING(@TempString,@ValueLen+LEN(@SplitOn)+1,LEN(@List)-@idlen-@ValueLen-LEN(@SplitOn)-LEN(@SplitOn))) RETURN END
Create a standard split string function, eg
CREATE FUNCTION [dbo].[SplitStringList] ( @List NVARCHAR(MAX), @SplitOn NVARCHAR(5) ) RETURNS @RtnTable TABLE ( Id INT IDENTITY(1,1), Value NVARCHAR(100) ) AS BEGIN DECLARE @Count int SET @Count = 1 WHILE (CHARINDEX(@SplitOn,@List)>0) BEGIN INSERT INTO @RtnTable (Value) SELECT Value = LTRIM(RTRIM(SUBSTRING(@List,1,CHARINDEX(@SplitOn,@List)-1))) SET @List = SUBSTRING(@List,CHARINDEX(@SplitOn,@List)+LEN(@SplitOn),LEN(@List)) Set @Count = @Count + 1 END INSERT INTO @RtnTable (Value) SELECT Value = LTRIM(RTRIM(@List)) RETURN END
Use the standard split string function to split your original string, then iterate over the rows of the resulting table using a cursor, calling the SplitThreeStringList function each time:
DECLARE @Value nvarchar(max) CREATE TABLE #results( Value NVARCHAR(max), A INT, B INT) DECLARE db_cursor CURSOR FOR SELECT Value FROM SplitStringList('col1~100~200|col2~700~300|col3~180~400','|') OPEN db_cursor FETCH NEXT FROM db_cursor INTO @Value WHILE @@FETCH_STATUS = 0 BEGIN INSERT INTO #results (Value, A, B) SELECT * FROM SplitThreeStringList(@Value, '~') FETCH NEXT FROM db_cursor INTO @Value END CLOSE db_cursor DEALLOCATE db_cursor
SELECT * FROM #results
Since others already answered how to do with string parsing I am going to take a different approach. A big reason for packing multiple values into a string like that is to avoid roundtrips to the DB server which depending on your environment can be costly.
Another approach is to create a UDT such as:
CREATE TYPE [dbo].[myT1UDT] AS TABLE
(
A UNIQUEIDENTIFIER, B DECIMAL(18,5),C INT
)
Then in your stored procedure you can specify that parameter such as:
CREATE PROCEDURE [dbo].[mySP]
@Items AS dbo.MYT1UDT READONLY
AS
INSERT INTO T1
SELECT * FROM @Items
If your executing this from .Net you can create a Datatable and pass it in
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.