Remove specific word in comma seperate string in MS SQL - sql-server

Here is my column looks like, named Sets.
My Column:
{C=Pass, D=Fail, E=Pass, F= Pass, G=Pass}
{C=Pass, D=Fail, E=NoApplication}
Expected
{C=Pass, E=Pass, F= Pass, G=Pass}
{C=Pass, E=NoApplication}
I wish to delete the "Fail" in my column.
Please help.

You can try this
UPDATE Use my approach within an updateable CTE
Changes the value in your table. Just replace #tbl with your actual table's name and `YourColumn with the column's name. Carefull with real data!
DECLARE #tbl TABLE(YourColumn VARCHAR(100));
INSERT INTO #tbl VALUES
('{C=Pass, D=Fail, E=Pass, F= Pass, G=Pass}')
,('{C=Pass, D=Fail, E=NoApplication}');
WITH Casted AS
(
SELECT CAST('<x>' + REPLACE(SUBSTRING(t.YourColumn,2,LEN(YourColumn)-2),', ','</x><x>') + '</x>' AS xml) AsXml
,t.YourColumn AS OldValue
FROM #tbl AS t
)
,UpdateableCTE AS
(
SELECT '{'
+ STUFF((
SELECT ', ' + a.value('.','nvarchar(100)')
FROM Casted.AsXml.nodes('/x') AS A(a)
WHERE RIGHT(a.value('.','nvarchar(100)'),4)<>'Fail'
FOR XML PATH('')
),1,2,'')
+ '}' AS NewValue
,OldValue
FROM Casted
)
UPDATE UpdateableCTE SET OldValue=NewValue;
SELECT * FROM #tbl;
The string is splitted into its elements. Then it is re-concatenated without the ones with "Fail".

You may looking for Update Command
UPDATE TableName
SET Name = CASE WHEN CHARINDEX('=Fail,',Name ) > 1
THEN STUFF(Name,CHARINDEX('=Fail,',Name)-1,LEN('=Fail,')+1,'')
ELSE Name
END

Related

SQL - String Manipulation

Context:
I have a view in SQL Server that tracks parameters a user inputs when they run an SSRS report (ReportServer.dbo.ExecutionLog). About 50 report parameters are saved as a string in a single column with ntext datatype. I would like to break this single column up into multiple columns for each parameter.
Details:
I query the report parameters like this:
SELECT ReportID, [Parameters]
FROM ReportServer.dbo.ExecutionLog
WHERE ReportID in (N'redacted')
and [Status] in (N'rsSuccess')
ORDER BY TimeEnd DESC
And here's a small subset of what the results look like:
alpha=123&bravo=9%2C33%2C76%2C23&charlie=91&delta=29&echo=11%2F2%2F2018%2012%3A00%3A00%20AM&foxtrot=11%2F1%2F2030%2012%3A00%3A00%20AM
Quesitons:
How can I get the results to look like this:
SQL Server 2017 is Python friendly. Is Python a better language to use in this scenario just for parsing purposes?
I've seen similar topics posted here, here & here. The parameters are dynamic so parsing via SQL string functions that involve counting characters doesn't apply. This question is relevant to more people than just me because there's a large population of people using SSRS. Tracking & formatting parameters in a more digestible way is valuable for all users of SSRS.
Here is a way using the built in STRING_SPLIT. I'm just not sure what the logic is for the stuff AFTER the date, so I would discarded it but I left it for you to decide.
DEMO
declare #table table (ReportID int identity(1,1), [Parameters] varchar(8000))
insert into #table
values
('alpha=123&bravo=9%2C33%2C76%2C23&charlie=91&delta=29&echo=11%2F2%2F2018%2012%3A00%3A00%20AM&foxtrot=11%2F1%2F2030%2012%3A00%3A00%20AM')
,('alpha=457893&bravo=9%2C33%2C76%2C23&charlie=91&delta=29&echo=11%2F2%2F2018%2012%3A00%3A00%20AM&foxtrot=11%2F1%2F2030%2012%3A00%3A00%20AM')
select
ReportID
,[Parameters]
,alpha = max(iif(value like 'alpha%',substring(value,charindex('=',value) + 1,99),null))
,bravo = max(iif(value like 'bravo%',substring(value,charindex('=',value) + 1,99),null))
,charlie = max(iif(value like 'charlie%',substring(value,charindex('=',value) + 1,99),null))
,delta = max(iif(value like 'delta%',substring(value,charindex('=',value) + 1,99),null))
,echo = max(iif(value like 'echo%',substring(value,charindex('=',value) + 1,99),null))
,foxtrot = max(iif(value like 'foxtrot%',substring(value,charindex('=',value) + 1,99),null))
from #table
cross apply string_split(replace(replace([Parameters],'%2C',','),'%2F','/'),'&')
group by ReportID, [Parameters]
Or, if they aren't static you can use a dynamic pivot. It'll take some massaging to get your columns in the correct order.
DEMO
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
SET #cols = STUFF((SELECT distinct ',' + QUOTENAME(substring([value],0,charindex('=',[value])))
from myTable
cross apply string_split(replace(replace([Parameters],'%2C',','),'%2F','/'),'&')
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
select #cols
set #query = 'SELECT ReportID, ' + #cols + ' from
(
select ReportID
, ColName = substring([value],0,charindex(''='',[value]))
, ColVal = substring([value],charindex(''='',[value]) + 1,99)
from myTable
cross apply string_split(replace(replace([Parameters],''%2C'','',''),''%2F'',''/''),''&'')
) x
pivot
(
max(ColVal)
for ColName in (' + #cols + ')
) p '
execute(#query)
Split the string on the ampersand character.
Further split each row into two columns on the equals character.
In the second column, replace %2C with the comma character, and %2F with the forward-slash character, and so on with any other replacements as needed.
Use a dynamic-pivot to query the above in the format that you want.
Here's a method that starts with a lot of replaces.
To url-decode the string and transform it into an XML type.
Then it uses the XML functions to get the values for the columns.
Example snippet:
declare #Table table ([Parameters] varchar(200));
insert into #Table ([Parameters]) values
('alpha=123&bravo=9%2C33%2C76%2C23&charlie=91&delta=29&echo=11%2F2%2F2018%2012%3A00%3A00%20AM&foxtrot=11%2F1%2F2030%2012%3A00%3A00%20AM');
select
x.query('/x[key="alpha"]/val').value('.', 'int') as alpha,
x.query('/x[key="bravo"]/val').value('.', 'varchar(30)') as bravo,
x.query('/x[key="charlie"]/val').value('.', 'varchar(30)') as charlie,
x.query('/x[key="delta"]/val').value('.', 'varchar(30)') as delta,
convert(date, x.query('/x[key="echo"]/val').value('.', 'varchar(30)'), 103)as echo,
convert(date, x.query('/x[key="foxtrot"]/val').value('.', 'varchar(30)'), 103) as foxtrot
from #Table
cross apply (select cast('<x><key>'+
replace(replace(replace(replace(replace(
replace([Parameters],
'%2C',','),
'%2F','/'),
'%20',' '),
'%3A',':'),
'=','</key><val>'),
'&','</val></x><x><key>')
+'</val></x>' as XML) as x) ca
Test on db<>fiddle here

SQL Server Regular expression extract pattern from DB colomn

I have a question about SQL Server: I have a database column with a pattern which is like this:
up to 10 digits
then a comma
up to 10 digits
then a semicolon
e.g.
100000161, 100000031; 100000243, 100000021;
100000161, 100000031; 100000243, 100000021;
and I want to extract within the pattern the first digits (up to 10) (1.) and then a semicolon (4.)
(or, in other words, remove everything from the semicolon to the next semicolon)
100000161; 100000243; 100000161; 100000243;
Can you please advice me how to establish this in SQL Server? Im not very familiar with regex and therefore have no clue how to fix this.
Thanks,
Alex
Try this
Declare #Sql Table (SqlCol nvarchar(max))
INSERT INTO #Sql
SELECT'100000161,100000031;100000243,100000021;100000161,100000031;100000243,100000021;'
;WITH cte
AS (SELECT Row_number()
OVER(
ORDER BY (SELECT NULL)) AS Rno,
split.a.value('.', 'VARCHAR(1000)') AS Data
FROM (SELECT Cast('<S>'
+ Replace( Replace(sqlcol, ';', ','), ',',
'</S><S>')
+ '</S>'AS XML) AS Data
FROM #Sql)AS A
CROSS apply data.nodes('/S') AS Split(a))
SELECT Stuff((SELECT '; ' + data
FROM cte
WHERE rno%2 <> 0
AND data <> ''
FOR xml path ('')), 1, 2, '') AS ExpectedData
ExpectedData
-------------
100000161; 100000243; 100000161; 100000243
I believe this will get you what you are after as long as that pattern truly holds. If not it's fairly easy to ensure it does conform to that pattern and then apply this
Select Substring(TargetCol, 1, 10) + ';' From TargetTable
You can take advantage of SQL Server's XML support to convert the input string into an XML value and query it with XQuery and XPath expressions.
For example, the following query will replace each ; with </b><a> and each , to </a><b> to turn each string into <a>100000161</a><a>100000243</a><a />. After that, you can select individual <a> nodes with /a[1], /a[2] :
declare #table table (it nvarchar(200))
insert into #table values
('100000161, 100000031; 100000243, 100000021;'),
('100000161, 100000031; 100000243, 100000021;')
select
xCol.value('/a[1]','nvarchar(200)'),
xCol.value('/a[2]','nvarchar(200)')
from (
select convert(xml, '<a>'
+ replace(replace(replace(it,';','</b><a>'),',','</a><b>'),' ','')
+ '</a>')
.query('a') as xCol
from #table) as tmp
-------------------------
A1 A2
100000161 100000243
100000161 100000243
value extracts a single value from an XML field. nodes returns a table of nodes that match the XPath expression. The following query will return all "keys" :
select
a.value('.','nvarchar(200)')
from (
select convert(xml, '<a>'
+ replace(replace(replace(it,';','</b><a>'),',','</a><b>'),' ','')
+ '</a>')
.query('a') as xCol
from #table) as tmp
cross apply xCol.nodes('a') as y(a)
where a.value('.','nvarchar(200)')<>''
------------
100000161
100000243
100000161
100000243
With 200K rows of data though, I'd seriously consider transforming the data when loading it and storing it in indivisual, indexable columns, or add a separate, related table. Applying string manipulation functions on a column means that the server can't use any covering indexes to speed up queries.
If that's not possible (why?) I'd consider at least adding a separate XML-typed column that would contain the same data in XML form, to allow the creation of an XML index.

T-SQL, Select string between 4th and 5th comma

How to get the string between 5th and 6th comma, without using a function, because I am selecting other columns as well, so using a function will not help me
This is the string value
"RBC,Dev,PROM0006581,T85230,P0263240,**Dev**,CHG0048754_DYN_DIF,Code changes as part of DYN -Tiered/Scaled & Bonus Interest for DIF Products
"
can someone please help me
You can do following:
DECLARE #Values VARCHAR(MAX) = 'RBC,Dev,PROM0006581,T85230,P0263240,**Dev**,CHG0048754_DYN_DIF,Code changes as part of DYN -Tiered/Scaled & Bonus Interest for DIF Products'
IF OBJECT_ID('TEMPDB..#Values') IS NOT NULL DROP TABLE #Values;
CREATE TABLE #Values (ID INT IDENTITY(1,1),Item VARCHAR(100));
DECLARE #Insert VARCHAR(MAX) = 'INSERT INTO #Values VALUES ('''+REPLACE(#Values,',','''),(''')+''');';
EXEC (#Insert);
SELECT * FROM #Values
Resulting:
And
SELECT Item FROM #Values WHERE ID=5
Resulting
This should get you what you're looking for...
IF OBJECT_ID('tempdb..#TestData', 'U') IS NOT NULL
DROP TABLE #testData;
CREATE TABLE #TestData (
String VARCHAR(1000) NOT NULL
);
INSERT #TestData (String) VALUES ('RBC,Dev,PROM0006581,T85230,P0263240,**Dev**,CHG0048754_DYN_DIF,Code changes as part of DYN -Tiered/Scaled & Bonus Interest for DIF Product');
SELECT *,
RequestedValue = SUBSTRING(td.String, c4.Comma + 1, ISNULL(c5.Comma - c4.Comma - 1, 1000))
FROM
#TestData td
CROSS APPLY ( VALUES (NULLIF(CHARINDEX(',', td.String, 1), 0)) ) c1 (Comma)
CROSS APPLY ( VALUES (NULLIF(CHARINDEX(',', td.String, c1.Comma + 1), 0)) ) c2 (Comma)
CROSS APPLY ( VALUES (NULLIF(CHARINDEX(',', td.String, c2.Comma + 1), 0)) ) c3 (Comma)
CROSS APPLY ( VALUES (NULLIF(CHARINDEX(',', td.String, c3.Comma + 1), 0)) ) c4 (Comma)
CROSS APPLY ( VALUES (NULLIF(CHARINDEX(',', td.String, c4.Comma + 1), 0)) ) c5 (Comma);
HTH, Jason
Here is a simple in-line and XML Safe approach (not just &'s).
Grabbing the 5th value. Not 100% sure if this needs to be adjusted up or down
Sample Data
Declare #YourTable table (ID int,SomeColumn varchar(max))
Insert Into #YourTable values
(1,'RBC,Dev,PROM0006581,T85230,P0263240,**Dev**,CHG0048754_DYN_DIF,Code changes as part of DYN -Tiered/Scaled & Bonus Interest for DIF Products')
The Query
Select ID
,SomeValue = Cast('<x>' + replace((Select replace(SomeColumn,',','|||') as [*] For XML Path('')),'|||','</x><x>')+'</x>' as xml).query('.').value('/x[5]','varchar(max)')
From #YourTable
Returns
ID SomeValue
1 P0263240
There is one solution that involve replacing comma , with xml tags and thereby converting column into an XML datatype.
Below query will give you 6th item (i.e between 5th and 6th comma as you want)
select *
, Column2 = convert(XML,'<s>' + REPLACE(REPLACE(MyColumn,'&','&'),',','</s><s>') + '</s>').value('/s[6]','varchar(200)')
FROM [dbo].[Table1]
SQL Fiddle Demo
But you have to escape any reserved XML character in your data by replacing it with entity references otherwise XML cast will fail. like & is replaced with &amp in the above query
XML reserved character on Technet
Updated Query
As #John mentioned in his answer FOR XML Path is a neat and elegant way to escape special XML characters.So my updated query would be.
SELECT *
, Column2 = convert(XML,'<s>' + REPLACE((SELECT ISNULL(MyColumn,'') FOR XML Path('')),',','</s><s>') + '</s>').value('/s[6]','varchar(200)')
FROM [dbo].[Table1]
Write a table-valued function that accepts the string and a delimiter character as parameters and returns the parsed elements of the string and the element's position as a two-column table. You can then JOIN to an invocation of that function, which SQL will treat just like a table, so if you want the text between the 5th and 6th comma then you'd put "and position = 6" in the JOIN clause.

How to correctly format For XML path results

I have to querys and their purpose is to retrieve all entries that fall in the where clause (which isnt important in this instance) and combines them into a stingle column here called ActualDropOffDateTimeUTC however the issue i am having is that i am receiving the correct result with the inclusion of the XML tags.
How to format data so the result is equal to (example):
2016-11-29T20:56:00 - 2016-11-30T09:27:00
How I actually recieve the data:
<ActualDropOffDateTimeUTC>2016-11-29T20:56:00</ActualDropOffDateTimeUTC><ActualDropOffDateTimeUTC>2016-11-30T09:27:00</ActualDropOffDateTimeUTC>
Below I have two attempts to do this under the column name of ActualDropOffDateTimeUTC and SecondAttempt
(
SELECT DISTINCT
ActualDropOffDateTimeUTC
FROM [dbo].[BookingJourneyLinkedCitySprintJobs]
WHERE
BookingReference = BJ.BookingReference AND BookingJourneyReference = BJ.BookingJourneyReference AND IsCurrentRevision = 1
FOR XML PATH('')
) as ActualDropOffDateTimeUTC,
(
SELECT
STUFF(
(
SELECT ' ' + ActualDropOffDateTimeUTC
FROM [dbo].[BookingJourneyLinkedCitySprintJobs]
WHERE
BookingReference = BJ.BookingReference AND BookingJourneyReference = BJ.BookingJourneyReference AND IsCurrentRevision = 1
FOR XML PATH(''),TYPE
).value('.','NVARCHAR(MAX)'
),1,1,''
)
) AS SecondAttempt
ActualDropOffDateTimeUTC Result:
<ActualDropOffDateTimeUTC>2016-11-29T20:56:00</ActualDropOffDateTimeUTC><ActualDropOffDateTimeUTC>2016-11-30T09:27:00</ActualDropOffDateTimeUTC>
SecondAttempt result:
016-11-29T20:56:002016-11-30T09:27:00
Desired Output:
2016-11-29T20:56:00 - 2016-11-30T09:27:00
I think I understand what you are trying to do:
declare #t table(d nvarchar(100));
insert into #t values('2016-11-29T20:56:00'),('2016-11-30T09:27:00');
select stuff((
select ' - ' + d
from #t
for xml path('')
)
,1,3,'')
Source Data:
Row 1: 2016-11-29T20:56:00
Row 2: 2016-11-30T09:27:00
Query Output:
2016-11-29T20:56:00 - 2016-11-30T09:27:00

Get a word in a table that contains similar words in SQL Server

I have two type of strings in a column.
DECLARE #t table(parameter varchar(100))
INSERT #t values
('It contains eact01' ),
('It contains preact01')
I'm trying to get the strings that contain the word 'eact01'.
My problem is that using the following SELECT, I get also the variables that contain 'preact01', because it contain 'eact01'.
SELECT * FROM #t WHERE parameter LIKE '%eact01%'
How could I get only the row containing 'eact01'?
This should find all combinations, any character not being a letter or a number considerer this as a spit character or a new word.
SELECT *
FROM #t
WHERE
parameter like '%[^0-9a-z]eact01'
or parameter like '%[^0-9a-z]eact01[^0-9a-z]%'
or parameter like 'eact01[^0-9a-z]%'
or parameter = 'eact01'
Try this-
select *
from #t
where
parameter='eact01'
OR parameter like '%[^0-9a-z]eact01%'
OR parameter like 'eact01[^0-9a-z]%'
OR parameter like '%[^0-9a-z]eact01[^0-9a-z]%'
The easiest way is just add space:
SELECT * FROM #t WHERE parameter LIKE '% eact01%' or parameter LIKE 'eact01%'
You need a string splitter for this. Here is one taken from Aaron Bertrand's article:
CREATE FUNCTION dbo.SplitStrings_XML
(
#List NVARCHAR(MAX),
#Delimiter NVARCHAR(255)
)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN
(
SELECT Item = y.i.value('(./text())[1]', 'nvarchar(4000)')
FROM
(
SELECT x = CONVERT(XML, '<i>'
+ REPLACE(#List, #Delimiter, '</i><i>')
+ '</i>').query('.')
) AS a CROSS APPLY x.nodes('i') AS y(i)
);
Then, you can use EXISTS:
SELECT *
FROM #t
WHERE EXISTS(
SELECT 1
FROM dbo.SplitStrings_XML(parameter, ' ') s
WHERE s.Item = 'eact01'
)

Resources