Extracting a single line value from a multi-line string T-SQL - sql-server

I have a multi-line nvarchar that contains a string in the below format:
#String =
'ReportHeaderColor{R:98, B:183, G:178}
ReportHeaderFontColor{R:255, B:255, G:255}
ReportBodyHeaderColor{R:98, B:183, G:178}
ReportBodyFontColor{R:255, B:255, G:255}'
I want to be able to use a nvarchar value #Attribute = 'ReportHeaderFontColor' and extract just the line from #String that contains the #Attribute value

Just another approach
Example
Declare #String varchar(max)=
'ReportHeaderColor{R:98, B:183, G:178}
ReportHeaderFontColor{R:255, B:255, G:255}
ReportBodyHeaderColor{R:98, B:183, G:178}
ReportBodyFontColor{R:255, B:255, G:255}'
Declare #Find varchar(150) = 'ReportHeaderFontColor'
Select value
From string_split(replace(replace(#String,'}','}|'),char(13)+char(10),''),'|')
where charindex(#Find,value)>0
Results
value
ReportHeaderFontColor{R:255, B:255, G:255}

How about the following using apply to find the begin/end positions to find and substring to extract:
declare #Attribute nvarchar(100)= 'ReportHeaderFontColor',
#String nvarchar(max) =
'ReportHeaderColor{R:98, B:183, G:178}
ReportHeaderFontColor{R:255, B:255, G:255}
ReportBodyHeaderColor{R:98, B:183, G:178}
ReportBodyFontColor{R:255, B:255, G:255}';
with s as (select #string as string)
select Substring(string,b.pos,e.pos-b.pos+1)
from s
cross apply(values(charindex(Concat('ReportBodyHeaderColor','{'), string)))b(pos)
cross apply(values(CharIndex('}', string, b.pos)))e(pos)
where b.pos>0;
Result:
ReportHeaderFontColor{R:255, B:255, G:255}

you can split the string by line feed char(10) and then remove carriage return char(13) as follows:
Declare #Attribute nVarChar(50)= 'ReportHeaderFontColor'
Declare #String nVarChar(max) =
'ReportHeaderColor{R:98, B:183, G:178}
ReportHeaderFontColor{R:255, B:255, G:255}
ReportBodyHeaderColor{R:98, B:183, G:178}
ReportBodyFontColor{R:255, B:255, G:255}'
Select Replace(Value,Char(13),'') As Result
From String_Split(#String,Char(10))
Where Value Like Concat('%',#Attribute,'%')
Result
ReportHeaderFontColor{R:255, B:255, G:255}

Thank you for all the suggestions, unfortunately I am not able to use string_split as some of our clients are on systems older than SQL 2016.
After toying around for a little bit I was able to come up with the below solution which i placed inside a UDF and added some error checking:
declare #header_row nvarchar(max) =
'ReportHeaderColor{R:98, B:183, G:178}
ReportHeaderFontColor{R:255, B:255, G:255}
ReportBodyHeaderColor{R:98, B:183, G:178}
ReportBodyFontColor{R:255, B:255, G:255}'
declare #Attribute nvarchar(max) = 'ReportHeaderFontColor'
declare #String nvarchar(255)
-- check that the header row is not empty and actually contains the attribute
if (len(#header_row) = 0 or #header_row not like '%' + #Attribute + '%')
begin
select #String = null
end
else begin
select #String =
replace(replace(replace(
left(
substring(#header_row,charindex(#Attribute + '{', #header_row) + len(#Attribute + '{'), 999),charindex('}',
substring(#header_row,charindex(#Attribute + '{', #header_row) + len(#Attribute + '{'), 999))-1)
,'R:',''),'G:',''),'B:','')
-- if the string is not in the correct format(3 integers separated by a comma) set #String to null
if (select count(1)
from dbo.fn_ListToTable(#String,',') x
where ISNUMERIC(x.List) = 1 and x.List <= 255) <> 3
begin
set #String = null
end
end

Related

Concatenate two strings into one without duplicates

I have two strings:
DECLARE #str1 varchar(max) = '[First Name],[Last Name],[Middle Name]'
DECLARE #str2 varchar(max) = '[First Name],[Pin Code],[Address],[Last Name]'
Want to concatenate two strings into one without duplicates.
Expected Output:
str3
-------------------------------------------------------------
[First Name],[Last Name],[Middle Name],[Pin Code],[Address]
You can use STRING_SPLIT() function and DISTINCT as
DECLARE #str1 varchar(max) = '[First Name],[Last Name],[Middle Name]';
DECLARE #str2 varchar(max) = '[First Name],[Pin Code],[Address],[Last Name]';
SELECT DISTINCT *
FROM STRING_SPLIT(#Str1 +','+ #Str2, ',');
Or
DECLARE #str1 varchar(max) = '[First Name],[Last Name],[Middle Name]';
DECLARE #str2 varchar(max) = '[First Name],[Pin Code],[Address],[Last Name]';
SELECT DISTINCT *
FROM STRING_SPLIT(CONCAT(#Str1, ',', #Str2), ',');
to get it as one row
declare #result varchar(max) = '';
SELECT #result = #result + value
FROM STRING_SPLIT(CONCAT(#Str1, ',', #Str2), ',')
group by value;
SELECT #result;
Demo
and since you are working on SQL Server 2008 you need to create your own function such this one here.

Select query using varchar with 'in'

I have this query:
DECLARE #holdIds VARCHAR(MAX)
SET #holdIds = '1,2,3'
DECLARE #flagNames NVARCHAR(MAX);
SELECT
#flagNames = COALESCE(#flagNames + ',', '') + FlagName
FROM
BurnHoldStatus
WHERE
BurnHoldStatusID in (#holdIds);
SELECT #flagNames AS FlagName;
In this example the variable '#holdIds' has values '1,2,3' but could have just one value '1'.
When I run the query, an error appears:
Msg 245, Level 16, State 1, Line 6
Conversion failed when converting the varchar value '1,2,3' to data type int.
I try convert the value of '#holdIds' but not work.
Any idea?
Thanks.
[UPDATE]
I found the answer:
DECLARE #holdIds NVARCHAR(MAX);
SET #holdIds = '1,2,3';
DECLARE #holdIdList TABLE(id INT);
INSERT INTO #holdIdList
SELECT * FROM Split(#holdIds, ',');
DECLARE #flagNames NVARCHAR(MAX);
SELECT
#flagNames = COALESCE(#flagNames + ',', '') + FlagName
FROM
BurnHoldStatus, #holdIdList h
WHERE
BurnHoldStatusID = h.id;
SELECT #flagNames AS FlagName;
In this code I use an function 'Split' to split a string passing the divisor (i.e: ',').
Split function code:
ALTER FUNCTION [dbo].[Split]
(
#RowData nvarchar(MAX),
#SplitOn nvarchar(MAX)
)
RETURNS #RtnValue table
(
Data nvarchar(MAX)
)
AS
BEGIN
Declare #Cnt int
Set #Cnt = 1
While (Charindex(#SplitOn,#RowData)>0)
Begin
Insert Into #RtnValue (data)
Select
Data = ltrim(rtrim(Substring(#RowData,1,Charindex(#SplitOn,#RowData)-1)))
Set #RowData = Substring(#RowData,Charindex(#SplitOn,#RowData)+1,len(#RowData))
Set #Cnt = #Cnt + 1
End
Insert Into #RtnValue (data)
Select Data = ltrim(rtrim(#RowData))
Return
END
Thanks for Vercelli by show other post.
Thanks guys :)
The comment made by swe is correct. You could make the query dynamic, then insert #holdIds See below for a workaround:
DECLARE #holdIds VARCHAR(MAX)
SET #holdIds = '1,2,3'
SET #holdIds = (CHAR(39) + (REPLACE(#holdIds, ',', ''',''') + CHAR(39)))
You can do this, then set the entire query above as a varchar variable, then execute. There are certainly other workarounds as well but dynamic SQL will work.

Insert results of SELECT Statement into SQL input Parameter

I have a comma delimited list of column names that I am casting to XML and then selecting. I would like to then insert these into the #selectedRows input parameter, which will be called in a stored procedure. How do you insert these multiple values into the #selectedRows parameter? Thanks!
Convert Comma Delimited List to XML and Select:
DECLARE #xml as xml,#string as varchar(1000),#delimiter as varchar(10)
SET #string='Column1,Column2,Column3,Column4,Column5'
SET #delimiter =','
SET #xml = cast(('<X>'+replace(#string,#delimiter ,'</X><X>')+'</X>') as xml)
SELECT N.value('.', 'varchar(25)') as value FROM #xml.nodes('X') as T(N)
This will be in stored procedure:
Select #selectedRows
from Test
where TestField > TestField
you do not need to split the comma delimited string of column names, but you would need to use dynamic sql for this something like this....
Declare #Sql NVarChar(Max);
Declare #string VarChar(1000) = 'Column1,Column2,Column3,Column4,Column5';
SET #Sql = N' SELECT ' + #string
+ N' From Test '
+ N' where TestField > TestField'
Exec sp_executesql #Sql

Find column names in executed query sql server

I have a table that stores SQL queries. I retrieve a query according to a condition and store it in a variable:
---------------------------------------------------------
ID | Query
---------------------------------------------------------
1 | 'Select Id,Name from Student'
2 | 'Select Id,Name,Father_Name from Student'
3 | 'Select Id,Name,Email from Student_Detail'
....
---------------------------------------------------------
For example, a variable #sql might have the first query from above:
Declare #sql nvarchar(500)
set #sql = 'Select Id,Name from Student'
I execute this query using:
Exec(#sql)
The problem is, how do I know which columns are used in that query? I'm trying to achieve something like what ColdFusion does with query.ColumnList, which returns the column list used in that query.
Try this:
SELECT SUBSTRING(query,8,CHARINDEX('from',query)-9) AS ColumnList
FROM YourTable
this is a variant of mehdi lotfi solution but is equally weak in the sense that only gives you whatever is in between the select and from statements so if you have aliases or calculations or 'case' statements it will not work properly; it does work if the column list is straight forward comma separated columns:
SELECT LEFT(REPLACE(#SQL,'Select ',''), CHARINDEX(' from',REPLACE(#SQL,'Select ',''))) AS ColumnList
Finally i managed to solve at my own using this solution.
Declare #sql varchar(1000)
Declare #valueList nvarchar(500)
Declare #tbl Table(Name varchar(100))
Declare #selectPos Int
Declare #fromPos Int
Declare #len Int
Declare #pos Int
Declare #prevpos Int
Declare #Delimeter varchar(2)
set #sql = 'Select Id,Name,Father_Name from Student'
set #selectPos = CHARINDEX('Select ', #sql, 1)+7
set #fromPos = CHARINDEX('From ', #sql, 1)
set #len = #fromPos - #selectPos
set #valueList = SUBSTRING(#sql, #selectPos, #len)
set #Delimeter = ', '
set #pos = 1
set #prevpos = 0
while #pos > 0
Begin
set #pos = charIndex(#Delimeter, #valueList, #pos)
If #pos = 0
Begin
Insert into #tbl
Select SUBSTRING(#valueList,#prevPos + 1,LEN(#valueList) - #prevpos)
Break;
End
Insert into #tbl
Select SUBSTRING(#valueList,#prevPos + 1,#pos-#prevpos - 1)
set #prevpos = #pos
set #pos = #pos + 1
End
select * from #tbl

Return rows containing all words in a string

I want to retrieve all rows in which a certain column contains all words passed in a string parameter regardless of the order in which they appear.
If the parameter is 'hi abc' then I want this row: abc def hijk and not hijk lmnop qr
I managed to do it but I suspect it is not very good so I would like to see alternatives. How to better accomplish what my code below do?
create table t (s varchar(200));
insert into t (s) values
('abc def hijk'),
('hijk lmnop qr'),
('stu'),
('v xyz')
;
create function dbo.matchRows (#string varchar(max))
returns varchar(max)
begin
set #string = replace(#string, '''', '''''');
set #string = replace(#string, ' ', ' ');
set #string = replace(#string, ' ', ' ');
set #string = replace(#string, ' ', '%'' and s like ''%');
set #string = 's like ''%' + #string + '%''';
set #string = 'select * from t where ' + #string;
return #string;
end;
declare #query varchar(max);
set #query = (select dbo.matchRows('hi abc'));
execute (#query);
Something like this should work. It converts your search params into XML and then splits it into a table variable. After that, it searches your #t table for all of the split up parameters that you passed in (where the count of the found words equaling the number of search parameters makes it match all of them).
DECLARE #SearchStringParams varchar(max),
#Split char(1),
#Xml xml,
#NumOfSearchTerms Int
DECLARE #SplitTable table (valToSearchFor varchar(100));
SELECT #SearchStringParams = 'hi,abc',
#Split = ','
SELECT #Xml = CONVERT(xml,'<root><s>' + REPLACE(#SearchStringParams,#Split,'</s><s>') + '</s></root>')
INSERT #SplitTable
SELECT [Value] = T.c.value('.','varchar(20)')
FROM #Xml.nodes('/root/s') T(c)
SELECT #NumOfSearchTerms = ##ROWCOUNT
DECLARE #t table (searchWords varchar(200));
insert into #t (searchWords) values
('abc def hijk'),
('hijk lmnop qr'),
('stu'),
('v xyz')
;
select t.searchWords
from #t t inner join #SplitTable s
on t.searchWords like ('%' + s.valToSearchFor + '%')
group by t.searchWords
having count(t.searchWords) = #NumOfSearchTerms

Resources