How to store semicolon separated long string into multiple columns? - sql

Basically due to restriction on live server, I cannot use text file so I need to hard code the data in T-SQL code.
So first I created string from text file like this:
("001122;Sale Item 1", "001123;Sale Item 23", "001124;Sale Item 24", .... )
I have this table structure:
DECLARE #Product TABLE(ProductCode INT NOT NULL, Description nvarchar(100) NOT NULL)
First I need to store code and description in a table variable. Once that's done, then I can easily map it to the physical table and update the records.
How can I achieve this something similar to:
insert into #Product(ProductCode, Description)
values ("001122;Sale Item 1", "001123;Sale Item 23", "001124;Sale Item 24", .... )
Code Description
001122 Sale Item1
001123 Sale Item2
001124 Sale Item3

If you have fixed format like in example then you can achieve desired output simply using CHARINDEX and SUBSTRING
SELECT
SUBSTRING(description, 0, CHARINDEX(';', DESCRIPTION, 0)) code,
SUBSTRING(description, CHARINDEX(';', DESCRIPTION, 0)+1, LEN(DESCRIPTION)) Description
FROM #Product
OUTPUT:
code Description
------------------------
001122 Sale Item 1
001123 Sale Item 23
001124 Sale Item 24

I crated a sample for you, please check this
declare #Questions varchar(100)= '"001122;Sale Item 1", "001123;Sale Item 23", "001124;Sale Item 24"'
DECLARE #myXML AS XML = N'<H><r>' +Replace(#Questions, ',', '</r><r>') + '</r></H>'
select #myXML
;WITH cte
AS (
SELECT CAST(N'<H><r>' + Replace(Vals.id.value('.', 'NVARCHAR(50)') ,';' , '</r><r>') + '</r></H>' as XML) AS val
FROM #myXML.nodes('/H/r') AS Vals(id)
)
,mycte1 as (
SELECT distinct
Replace( S.a.value('(/H/r)[1]', 'NVARCHAR(50)') , '"', '') AS c1,
Replace( S.a.value('(/H/r)[2]', 'NVARCHAR(50)') , '"', '') AS c2
FROM cte CROSS APPLY val.nodes('/H/r') S(a)
)
select * from mycte1
The output will be
c1 c2
001123 Sale Item 23
001124 Sale Item 24
001122 Sale Item 1

Here we go matey:
DECLARE #MyString nvarchar(max) = '"001122;Sale Item 1", "001123;Sale Item 23", "001124;Sale Item 24"';
DECLARE #delimiter1 nvarchar(1)
, #delimiter2 nvarchar(1)
, #Start1 int
, #End1 int
, #Length int
, #cNEXTVALUE nvarchar(1000)
, #cNEXTVALUE2 nvarchar(1000)
, #StringLength int;
DECLARE #Product TABLE (
ProductCode int NOT NULL
, Description nvarchar(100) NOT NULL );
SET #MyString = RTRIM(LTRIM(#MyString));
SET #MyString = REPLACE(#MyString, CHAR(13), '');
SET #MyString = REPLACE(#MyString, CHAR(10), '');
SET #delimiter1 = ';';
SET #delimiter2 = ',';
SET #MyString = REPLACE(#MyString, '"', '')+#delimiter2;
SET #StringLength = LEN(#MyString);
SELECT #Start1 = 0
, #End1 = CHARINDEX(#delimiter1, #MyString, 1);
SELECT #Length = #End1 - #Start1;
WHILE #Length > 0
BEGIN
SET #cNEXTVALUE = SUBSTRING(#MyString, #Start1, #Length);
SET #Start1 = #End1 + 1;
SET #End1 = CHARINDEX(#delimiter2, #MyString, #Start1);
SELECT #Length = #End1 - #Start1;
SET #cNEXTVALUE2 = SUBSTRING(#MyString, #Start1, #Length);
IF LEN(RTRIM(LTRIM(#cNEXTVALUE))) > 0
BEGIN
INSERT INTO #Product
( ProductCode
, Description
)
VALUES
( #cNEXTVALUE, #cNEXTVALUE2 );
END;
SET #Start1 = #End1 + 2;
SET #End1 = CHARINDEX(#delimiter1, #MyString, #Start1);
SELECT #Length = #End1 - #Start1;
END;
SELECT *
FROM #Product;

Related

How to create a Stored Procedure in SQL Server?

I was creating a Stored Procedure for validation based on not allowing special characters in LeaveTypeText, for my project that I am learning now. And I want LeaveTypeText to not allow duplicate values and update LeaveTypeKey based on LeaveTypeText by removing space in between two characters.
How can I correct this?
ALTER PROCEDURE [dbo].[PreSaveAnd_AfterSave_Validation] (
#FBFormId INT
,#PkId INT
,#TF_ProjectId INT
,#UserDetails NVARCHAR(MAX)
,#IsPostSave BIT
,#ContactId INT
,#Who NVARCHAR(100)
,#RoleId INT
,#Culture NVARCHAR(200)
)
AS
BEGIN
DECLARE #GlobalDateFormatCode INT
DECLARE #ErrorMsg NVARCHAR(Max)
SELECT #GlobalDateFormatCode = dbo.TF_FN_GetCurrentDateFormat()
IF ISNULL(#IsPostSave, 0) = 0
BEGIN
DECLARE #ParaMeterTable TABLE (
Id INT IDENTITY(1, 1) PRIMARY KEY
,ParameterName NVARCHAR(MAX)
,ParameterValue NVARCHAR(MAX)
)
INSERT INTO #ParaMeterTable (
ParameterName
,ParameterValue
)
SELECT LTRIM(LEFT(Value, CHARINDEX('=', Value, 0) - 1)) AS ParameterName
,LTRIM(SUBSTRING(Value, CHARINDEX('=', Value, 0) + 1, LEN(Value))) AS ParameterValue
FROM dbo.TF_FN_Split(#UserDetails, '||')
WHERE ISNULl(Value, '') <> ''
--SELECT * FROM #ParaMeterTable
DECLARE #LeaveTypeText NVARCHAR(1000)
DECLARE #LeaveTypeKey NVARCHAR(1000)
--SELECT #LeaveTypeText = ParameterValue
--FROM #ParaMeterTable
--WHERE ParameterName LIKE '#LeaveTypeText%'
--select #LeaveTypeKey = LeaveTypeKey from DBO.Master_LeaveType_Sample
--SELECT #LeaveTypeText
SET #ErrorMsg = ' "Leave Type Key" field does not allow Special characters '
--Validate Here
IF EXISTS (#LeaveTypeKey like '%$%')
BEGIN
SELECT 0 AS IsValid
,#ErrorMsg AS [ErrorMessage]
END
IF (ISNULL(#ErrorMsg, '') != '')
BEGIN
SELECT 0 AS IsValid
,#ErrorMsg AS [ErrorMessage]
END
ELSE
BEGIN
SELECT 1 IsValid
,dbo.TF_FN_GetCultureMessage('TF_DB_Success', #ContactId, #Who, #RoleId, #Culture) AS [ErrorMessage]
END
END
ELSE IF ISNULL(#IsPostSave, 0) = 1
BEGIN
-- Post Save Logic
UPDATE DBO.Master_LeaveType_Sample
SET LeaveTypeKey = Replace(ParameterValue, ' ', '')
FROM DBO.Master_LeaveType_Sample
WHERE LeaveTypeText = ParameterValue
SELECT 1 IsValid
,dbo.TF_FN_GetCultureMessage('TF_DB_Success', #ContactId, #Who, #RoleId, #Culture) AS [ErrorMessage]
END
END

Aliasing column names dynamically in SQL Server

Providing separate aliasing values to each column dynamically. The number of values in #column_name1 and #aliasing_val can change as per requirements, so please provide a solution that can work for any number of values in the #column_name1 and #aliasing_val.
Declare #table_name1 NVARCHAR(250) = 'table1',
#column_name1 NVARCHAR(250) = 't1col1,t1col2,t1col3',
#aliasing_val NVARCHAR(250) = 'c1,c2,c3',
#SQLString nvarchar(max),
#SQLString2 nvarchar(max)
If ((#table_name1 IS NOT NULL AND LEN(#table_name1) !=0)
AND (#column_name1 IS NOT NULL AND LEN(#column_name1) !=0))
BEGIN
set #SQLString2 = 'SELECT '
Select #SQLString2 = #SQLString2 +
QUOTENAME(split.a.value('.', 'VARCHAR(100)')) + ' As '+aliasing_val+',
'
FROM (SELECT Cast ('<M>' + Replace(#column_name1, ',', '</M><M>')+ '</M>' AS XML) AS Data) AS A
CROSS apply data.nodes ('/M') AS Split(a);
Set #SQLString2 = LEFT(#SQLString2, LEN(#SQLString2) - 3)
END
print #SQLString2
Current output:
SELECT [t1col1] As c1,c2,c3,
[t1col2] As c1,c2,c3,
[t1col3] As c1,c2,c3
Expected output
SELECT [t1col1] As c1,
[t1col2] As c2,
[t1col3] As c3
This should do the job. You need to separate the comma-separated elements of each string out one at a time. This script loops through the items and maintains a pointer to the next item in the list. Then at each loop it extracts the item and adds it to the SQL:
Declare #table_name1 NVARCHAR(250) = 'table1',
#column_name1 NVARCHAR(250) = 't1col1,t1col2,t1col3',
#aliasing_val NVARCHAR(250) = 'c1,c2,c3',
#SQLString nvarchar(max),
#SQLString2 nvarchar(MAX),
#count [int],
#pos int,
#pos2 [int],
#delimiter varchar(1);
SET #delimiter = ',';
SET #pos = CHARINDEX(#delimiter, #aliasing_val, 1)
SET #pos2 = CHARINDEX(#delimiter, #column_name1, 1)
SET #aliasing_val = LTRIM(RTRIM(#aliasing_val)) + #delimiter
SET #column_name1 = LTRIM(RTRIM(#column_name1)) + #delimiter
SET #count = 0
IF ((#table_name1 IS NOT NULL AND LEN(#table_name1) !=0) AND (#column_name1 IS NOT NULL AND LEN(#column_name1) !=0))
BEGIN
SET #SQLString2 = 'SELECT '
IF REPLACE(#aliasing_val, #delimiter, '') <> '' -- make sure there are actually any delimited items in the list
BEGIN
WHILE #pos > 0
BEGIN
IF #count > 0 SET #SQLString2 = #SQLString2 + ','
SET #SQLString2 = #SQLString2 + LTRIM(RTRIM(LEFT(#column_name1, #pos2 - 1))) + ' As ' + LTRIM(RTRIM(LEFT(#aliasing_val, #pos - 1)))
SET #aliasing_val = RIGHT(#aliasing_val, LEN(#aliasing_val) - #pos) -- remove the item we just extracted from the list
SET #column_name1 = RIGHT(#column_name1, LEN(#column_name1) - #pos2) -- remove the item we just extracted from the list
SET #pos = CHARINDEX(#delimiter, #aliasing_val, 1) -- reset the position to point to the next delimiter
SET #pos2 = CHARINDEX(#delimiter, #column_name1, 1) -- reset the position to point to the next delimiter
SET #count = #count + 1
END
END
END
SELECT #SQLString2
You are at the right approach. Only thing you need to do is make two separate select statement for #column_name and #aliasing_val and join it using ROW_NUMBER() function and you got what you expect - Try this
IF ((#table_name1 IS NOT NULL AND LEN(#table_name1) !=0) AND (#column_name1 IS NOT NULL AND LEN(#column_name1) !=0))
BEGIN
SET #SQLString2 = 'SELECT '
SELECT #SQLString2 += tab.ColName + ' As '+ res.AliasName +','
FROM
(
SELECT QUOTENAME(split.a.value('.', 'VARCHAR(100)')) AS ColName, ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS RowNum
FROM
(
SELECT Cast ('<M>' + Replace(#column_name1, ',', '</M><M>')+ '</M>' AS XML) AS Data
) AS A
CROSS apply data.nodes ('/M') AS Split(a)
) tab
INNER JOIN
(
Select AliasSplit.c.value('.', 'varchar(100)') AS AliasName, ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS RowNum
FROM
(
SELECT Cast ('<A>' + Replace(#aliasing_val, ',', '</A><A>')+ '</A>' AS XML) AS AliasData
) AS A
CROSS apply AliasData.nodes ('/A') AS AliasSplit(c)
) res
ON tab.RowNum = res.RowNum
Set #SQLString2 = LEFT(#SQLString2, LEN(#SQLString2) - 1)
END
PRINT #SQLString2
Output
SELECT [t1col1] As c1,[t1col2] As c2,[t1col3] As c3

MSSQL - Create table function, return substring

I need to create this table function. The function needs to return single words from passed parameters like: hello, hhuu, value
The table function should return:
hello,
hhuu,
value
But I am always getting some errors, please could you help me?
you can write as:
DECLARE #input_char VARCHAR(255)
SET #input_char = 'hello, hhuu, value'
;WITH cte AS (
SELECT
CAST('<r>' + REPLACE(#input_char, ' ', '</r><r>') + '</r>' AS XML) AS input_char
)
SELECT
rtrim( LTRIM (xTable.xColumn.value('.', 'VARCHAR(MAX)')) ) AS input_char
FROM cte
CROSS APPLY input_char.nodes('//r') AS xTable(xColumn)
Please give a look at this article:
http://www.codeproject.com/Tips/625872/Convert-a-CSV-delimited-string-to-table-column-in
and you could use ' ' (space) as delimiter.
SELECT * FROM dbo.CSVtoTable('hello, hhuu, value', ' ')
I have used the following function many times. It is a bit lengthy forgive me, but it has become a great tool for me.
CREATE Function [dbo].[ParseText2Table]
(
#p_SourceText varchar(MAX)
,#p_Delimeter varchar(100) = ',' --default to comma delimited.
)
RETURNS #retTable TABLE
(
POSITION INT
,Int_Value bigint
,Num_value REAL--Numeric(18,3)
,txt_value varchar(MAX)
)
AS
BEGIN
DECLARE #tmpTable TABLE
(
Position2 INT IDENTITY(1,1) PRIMARY KEY
,Int_Value bigint
,Num_value REAL--Numeric(18,3)
,txt_value varchar(MAX)
)
DECLARE #w_Continue INT
,#w_StartPos INT
,#w_Length INT
,#w_Delimeter_pos INT
,#w_tmp_int bigint
,#w_tmp_num REAL--numeric(18,3)
,#w_tmp_txt varchar(MAX)
,#w_Delimeter_Len INT
IF len(#p_SourceText) = 0
BEGIN
SET #w_Continue = 0 -- force early exit
END
ELSE
BEGIN
-- if delimiter is ' ' change
IF #p_Delimeter = ' '
BEGIN
SET #p_SourceText = replace(#p_SourceText,' ','ÿ')
SET #p_Delimeter = 'ÿ'
END
-- parse the original #p_SourceText array into a temp table
SET #w_Continue = 1
SET #w_StartPos = 1
SET #p_SourceText = RTRIM( LTRIM( #p_SourceText))
SET #w_Length = DATALENGTH( RTRIM( LTRIM( #p_SourceText)))
SET #w_Delimeter_Len = len(#p_Delimeter)
END
WHILE #w_Continue = 1
BEGIN
SET #w_Delimeter_pos = CHARINDEX( #p_Delimeter
,(SUBSTRING( #p_SourceText, #w_StartPos
,((#w_Length - #w_StartPos) + #w_Delimeter_Len)))
)
IF #w_Delimeter_pos > 0 -- delimeter(s) found, get the value
BEGIN
SET #w_tmp_txt = LTRIM(RTRIM( SUBSTRING( #p_SourceText, #w_StartPos
,(#w_Delimeter_pos - 1)) ))
IF dbo.isReallyNumeric(#w_tmp_txt) = 1 --and not #w_tmp_txt in('.', '-', '+', '^')
BEGIN
--set #w_tmp_int = cast( cast(#w_tmp_txt as real) as bigint)--numeric) as bigint)
SET #w_tmp_int = CASE WHEN (CAST(#w_tmp_txt AS REAL) BETWEEN -9223372036854775808 AND 9223372036854775808) THEN CAST( CAST(#w_tmp_txt AS REAL) AS bigint) ELSE NULL END
SET #w_tmp_num = CAST( #w_tmp_txt AS REAL)--numeric(18,3))
END
ELSE
BEGIN
SET #w_tmp_int = NULL
SET #w_tmp_num = NULL
END
SET #w_StartPos = #w_Delimeter_pos + #w_StartPos + (#w_Delimeter_Len- 1)
END
ELSE -- No more delimeters, get last value
BEGIN
SET #w_tmp_txt = LTRIM(RTRIM( SUBSTRING( #p_SourceText, #w_StartPos
,((#w_Length - #w_StartPos) + #w_Delimeter_Len)) ))
IF dbo.isReallyNumeric(#w_tmp_txt) = 1 --and not #w_tmp_txt in('.', '-', '+', '^')
BEGIN
--set #w_tmp_int = cast( cast(#w_tmp_txt as real) as bigint)--as numeric) as bigint)
SET #w_tmp_int = CASE WHEN (CAST(#w_tmp_txt AS REAL) BETWEEN -9223372036854775808 AND 9223372036854775808) THEN CAST( CAST(#w_tmp_txt AS REAL) AS bigint) ELSE NULL end
SET #w_tmp_num = CAST( #w_tmp_txt AS REAL)--numeric(18,3))
END
ELSE
BEGIN
SET #w_tmp_int = NULL
SET #w_tmp_num = NULL
END
SELECT #w_Continue = 0
END
INSERT INTO #tmpTable VALUES( #w_tmp_int, #w_tmp_num, #w_tmp_txt )
END
INSERT INTO #retTable SELECT Position2, Int_Value ,Num_value ,txt_value FROM #tmpTable
RETURN
END
Here are the supporting functions for above as well:
CREATE FUNCTION dbo.isReallyInteger
(
#num VARCHAR(64)
)
RETURNS BIT
BEGIN
IF LEFT(#num, 1) = '-'
SET #num = SUBSTRING(#num, 2, LEN(#num))
RETURN CASE
WHEN PATINDEX('%[^0-9-]%', #num) = 0
AND CHARINDEX('-', #num) <= 1
AND #num NOT IN ('.', '-', '+', '^')
AND LEN(#num)>0
AND #num NOT LIKE '%-%'
THEN
1
ELSE
0
END
END
CREATE FUNCTION dbo.isReallyNumeric
(
#num VARCHAR(64)
)
RETURNS BIT
BEGIN
IF LEFT(#num, 1) = '-'
SET #num = SUBSTRING(#num, 2, LEN(#num))
DECLARE #pos TINYINT
SET #pos = 1 + LEN(#num) - CHARINDEX('.', REVERSE(#num))
RETURN CASE
WHEN PATINDEX('%[^0-9.-]%', #num) = 0
AND #num NOT IN ('.', '-', '+', '^')
AND LEN(#num)>0
AND #num NOT LIKE '%-%'
AND
(
((#pos = LEN(#num)+1)
OR #pos = CHARINDEX('.', #num))
)
THEN
1
ELSE
0
END
END
Usage Examples:
--Single Character Delimiter
--select * from dbo.ParseText2Table('100|120|130.56|Yes|Cobalt|Blue','|')
--select txt_value from dbo.ParseText2Table('100 120 130.56 Yes Cobalt Blue',' ') where Position = 3
--select * from dbo.ParseText2Table('100,120,130.56,Yes,Cobalt,Blue,,',',')
/*
POSITION Int_Value Num_value txt_value
----------- ----------- -------------------- --------------
1 100 100.000 100
2 120 120.000 120
3 131 130.560 130.56
4 NULL NULL Yes
5 NULL NULL Cobalt Blue
*/

Split numbers from string

I have my table like this
4-Documento d’identità-3-Attestato di Rischio-2-Carta di Circolazione
10-Contrassegno
12-Documenti di annullo polizza-10-Contrassegno
10-Contrassegno
12-Documenti di annullo polizza-10-Contrassegno
I want to split every row to be like this
4-3-2
10
12-10
10
12-10
try this
DECLARE #table AS TABLE
(
ID INT IDENTITY(1, 1) ,
SomeText VARCHAR(500)
)
INSERT INTO #table
( SomeText )
VALUES ( '4-Documento d’identità-3-Attestato di Rischio-2-Carta di Circolazione' ),
( '10-Contrassegno' ),
( '12-Documenti di annullo polizza-10-Contrassegno' ),
( '10-Contrassegno' ),
( '12-Documenti di annullo polizza-10-Contrassegno' );
WITH cte
AS ( SELECT n = 1
UNION ALL
SELECT n + 1
FROM cte
WHERE n <= 100
),
SplitToChr
AS ( SELECT T.ID ,
SUBSTRING(T.SomeText, cte.n, 1) AS Chr
FROM #table AS T
JOIN cte ON DATALENGTH(T.SomeText) >= cte.n
AND SUBSTRING(T.SomeText, cte.n, 1) LIKE '[0-9-]'
)
SELECT T.ID ,
REVERSE(SUBSTRING(REVERSE(T.FInal),2,LEN(T.FInal))) AS Final
FROM ( SELECT DISTINCT
o.ID ,
REPLACE(( SELECT '' + chr
FROM SplitToChr AS i
WHERE i.id = o.id
FOR
XML PATH('')
), '--', '-') AS FInal
FROM SplitToChr AS o
) AS T
SAMPLE TABLE
CREATE TABLE #TEMP(STRINGCOLUMN NVARCHAR(MAX))
INSERT INTO #TEMP
SELECT '4-Documento d’identità-3-Attestato di Rischio-2-Carta di Circolazione'
UNION ALL
SELECT '10-Contrassegno'
UNION ALL
SELECT '12-Documenti di annullo polizza-10-Contrassegno'
UNION ALL
SELECT '10-Contrassegno'
UNION ALL
SELECT '12-Documenti di annullo polizza-10-Contrassegno'
You can use a function in case you need the query to be simple
Function
CREATE FUNCTION [dbo].[ConvertToNumber]
(#strAlphaNumeric VARCHAR(256))
RETURNS VARCHAR(256)
AS
BEGIN
SET #strAlphaNumeric = LEFT(#strAlphaNumeric,
LEN(#strAlphaNumeric) - CHARINDEX('-', REVERSE(#strAlphaNumeric)) + 0)
DECLARE #intAlpha INT
SET #intAlpha = PATINDEX('%[^0-9]-%', #strAlphaNumeric)
BEGIN
WHILE #intAlpha > 0
BEGIN
SET #strAlphaNumeric = STUFF(#strAlphaNumeric, #intAlpha, 1, '' )
SET #intAlpha = PATINDEX('%[^0-9]-%', #strAlphaNumeric )
END
END
RETURN ISNULL(#strAlphaNumeric,0)
END
And your final query
SELECT DBO.ConvertToNumber(STRINGCOLUMN)STRINGCOLUMN
FROM #TEMP
RESULT
first use this split func
CREATE FUNCTION [dbo].[fnSplitString] ( #string NVARCHAR(MAX)
, #delimiter CHAR(1) )
RETURNS #output TABLE ( splitdata NVARCHAR(MAX) )
BEGIN
DECLARE #start INT
, #end INT
SELECT #start = 1
, #end = CHARINDEX(#delimiter, #string)
WHILE #start < LEN(#string) + 1
BEGIN
IF #end = 0
SET #end = LEN(#string) + 1
INSERT INTO #output ( splitdata )
VALUES ( SUBSTRING(#string, #start, #end - #start) )
SET #start = #end + 1
SET #end = CHARINDEX(#delimiter, #string, #start)
END
RETURN
END
and then use this code
CREATE TABLE #t10 ( id int identity(1,1)
, num int )
INSERT INTO #t10
select *
from dbo.fnSplitString ('4-Documento d’identità-3-Attestato di Rischio-2-Carta di Circolazione','-')
WHERE ISNUMERIC(splitdata)=1
DECLARE #x int = 1
DECLARE #y varchar(10)=''
DECLARE #q varchar(10)
WHILE #x<=(SELECT count(*)
from #t10)
BEGIN
SET #q=(SELECT num
FROM #t10
WHERE id = #x )
set #y=#y+#q+'-'
SET #x=#x+1
END
SELECT left(ltrim(#y),len(#y)-1)
--SELECT * FROM #t10
--drop table #t10
It's a bit messy, but it gets the job done :-)
CREATE TABLE dbo.Documents (
Details VARCHAR(1000)
);
GO
INSERT INTO dbo.Documents
VALUES ('4-Documento d’identità-3-Attestato di Rischio-2-Carta di Circolazione'),
('10-Contrassegno'),
('12-Documenti di annullo polizza-10-Contrassegno'),
('10-Contrassegno'),
('12-Documenti di annullo polizza-10-Contrassegno');
SELECT CASE WHEN (FirstLine + SecondLine + ThirdLine) LIKE '%-'
THEN LEFT(FirstLine + SecondLine + ThirdLine, LEN(FirstLine + SecondLine + ThirdLine) -1)
ELSE (FirstLine + SecondLine + ThirdLine) END AS CleanData
FROM (
SELECT
LEFT(Details, CHARINDEX('-', Details)) AS FirstLine,
REPLACE(CASE
WHEN REPLACE( REPLACE( LEFT(Details,CHARINDEX('-', Details, CHARINDEX('-', Details )+1)+2) , LEFT(Details, CHARINDEX('-', Details, CHARINDEX('-', Details)+1)), ''), LEFT(Details, CHARINDEX('-', Details)), '') LIKE '%[0-9]' THEN REPLACE( REPLACE( LEFT(Details,CHARINDEX('-', Details, CHARINDEX('-', Details )+1)+2) , LEFT(Details, CHARINDEX('-', Details, CHARINDEX('-', Details)+1)), ''), LEFT(Details, CHARINDEX('-', Details)), '') + '-'
ELSE REPLACE( LEFT(Details,CHARINDEX('-', Details, CHARINDEX('-', Details )+1)+2) , LEFT(Details, CHARINDEX('-', Details, CHARINDEX('-', Details)+1)), '')
END , LEFT(Details, CHARINDEX('-', Details)), '') AS SecondLine,
CASE WHEN REVERSE(LEFT(REVERSE(Details), CHARINDEX('-', REVERSE(Details))+2)) LIKE '-%'
THEN LEFT(REVERSE(LEFT(REVERSE(Details), CHARINDEX('-', REVERSE(Details))+2)), 3) ELSE '' END AS ThirdLine
FROM dbo.Documents
) AS A;
Another way of doing it in a much simpler way. Create a function to remove the alphabets from the string
Create FUNCTION dbo.RemoveAlphabets (#string VARCHAR(256))
returns VARCHAR(256)
BEGIN
IF #string IS NULL
RETURN NULL
DECLARE #Result VARCHAR(256)='',#len INT = Len(#string ),#cnt INT=1
WHILE #cnt <= #len
BEGIN
DECLARE #parse INT
SET #parse = Ascii(Substring(#string , #cnt, 1))
IF #parse BETWEEN 48 AND 57 or #parse =45
SET #Result = #Result + Char(#parse)
SET #cnt = #cnt + 1
END
select #result= replace(#Result,'--','-')
RETURN left(#result,case when right(#Result,1)='-' then len(#Result)-1 else len(#result) end)
END
If numbers inside the string is always surrounded by '-' then replace the return statement with this.
RETURN left(#result,len(#Result)-1)
execute the function
select dbo.RemoveAlphabets
('4-Documento d’identità-3-Attestato di Rischio-2-Carta di Circolazione')
Result : 4-3-2

search in a string creditcard numeric value

I want to find a credit card numeric value in a sql string.
for example;
DECLARE #value1 NVARCHAR(MAX) = 'The payment is the place 1234567812345678'
DECLARE #value2 NVARCHAR(MAX) = 'The payment is the place 123456aa7812345678'
DECLARE #value3 NVARCHAR(MAX) = 'The payment1234567812345678is the place'
The result should be :
#value1Result 1234567812345678
#value2Result NULL
#value3Result 1234567812345678
16 digits must be together without space.
How to do this in a sql script or a function?
edit :
if I want to find these 2 credit card value.
#value4 = 'card 1 is : 4034349183539301 and the other one is 3456123485697865'
how should I implement the scripts?
You can use PathIndex as
PATINDEX('%[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]%', yourStr)
if the result is 0 then it doesnt containg 16 digits other was it contains.
It can be used withing a Where statement or Select statement based on your needs
You can write as:
SELECT case when Len(LEFT(subsrt, PATINDEX('%[^0-9]%', subsrt + 't') - 1)) = 16
then LEFT(subsrt, PATINDEX('%[^0-9]%', subsrt + 't') - 1)
else ''
end
FROM (
SELECT subsrt = SUBSTRING(string, pos, LEN(string))
FROM (
SELECT string, pos = PATINDEX('%[0-9]%', string)
FROM table1
) d
) t
Demo
DECLARE #value1 NVARCHAR(MAX) = 'card 1 is : 4034349183539301 and the other one is 3456123485697865'
DECLARE #Lenght INT
,#Count INT
,#Candidate CHAR
,#cNum INT
,#result VARCHAR(16)
SELECT #Count = 1
SELECT #cNum = 0
SELECT #result = ''
SELECT #Lenght = LEN(#value1)
WHILE #Count <= #Lenght
BEGIN
SELECT #Candidate = SUBSTRING(#value1, #Count, 1)
IF #Candidate != ' '
AND ISNUMERIC(#Candidate) = 1
BEGIN
SET #cNum = #cNum + 1
SET #result = #result + #Candidate
END
ELSE
BEGIN
SET #cNum = 1
SET #result = ''
END
IF #cNum > 16
BEGIN
SELECT #result 'Credit Number'
END
SET #Count = #Count + 1
END
There you go kind sir.
DECLARE
#value3 NVARCHAR(MAX) = 'The payment1234567812345678is the place',
#MaxCount int,
#Count int,
#Numbers NVARCHAR(100)
SELECT #Count = 1
SELECT #Numbers = ''
SELECT #MaxCount = LEN(#value3)
WHILE #Count <= #MaxCount
BEGIN
IF (UNICODE(SUBSTRING(#value3,#Count,1)) >= 48 AND UNICODE(SUBSTRING(#value3,#Count,1)) <=57)
SELECT #Numbers = #Numbers + SUBSTRING(#value3,#Count,1)
SELECT #Count = #Count + 1
END
PRINT #Numbers
You can make this as a function if you are planning to use it a lot.