Replace a specific character with blank - sql

How can I replace 'a' to blank?
`Name` `ID`
----------------------------------
`b,c,d,e,abb,a` `1`
`b,c,d,a,e,abb` `2`
`a,b,c,d,a,e,abb` `3`

One way to do it would be to add a , to the beginning and end of each Name, then replace every occurence of ',a,' with ',', then trim the result of the ,:
update table_name
set Name = trim(',' from replace(concat(',', Name, ','), ',a,', ','));
Fiddle
Or if you just want to do a select without changing the rows:
select trim(',' from replace(concat(',', Name, ','), ',a,', ',')) as Name, ID
from table_name;
To address #Iptr's comment, if there can be consecutive a such as a, a, ..., you could use STRING_SPLIT to get rows from comma-separated values, then filter out where the value is a, then STRING_AGG and group by to get the comma separated values back:
select ID, STRING_AGG(u.Value, ',') as Name
from table_name
cross apply STRING_SPLIT (Name, ',') u
where Value <> 'a'
group by ID
Fiddle

Here is a solution based on tokenization via XML/XQuery.
It will work starting from SQL Server 2012 onwards.
Steps:
We are tokenizing a string of tokens via XML.
XQuery FLWOR expression is filtering out the 'a' token.
Reverting it back to a string of tokens.
SQL
-- DDL and sample data population, start
DECLARE #tbl TABLE (ID INT IDENTITY PRIMARY KEY, tokens VARCHAR(1000));
INSERT INTO #tbl (tokens) VALUES
('b,c,d,e,abb,a'),
('b,c,d,a,e,abb'),
('a,b,c,d,a,e,abb');
-- DDL and sample data population, end
DECLARE #separator CHAR(1) = ',';
SELECT t.*
, REPLACE(c.query('
for $x in /root/r/text()
return if ($x = "a") then ()
else data($x)
').value('.', 'VARCHAR(MAX)'), SPACE(1), #separator) AS Result
FROM #tbl AS t
CROSS APPLY (SELECT TRY_CAST('<root><r><![CDATA[' +
REPLACE(tokens, #separator, ']]></r><r><![CDATA[') +
']]></r></root>' AS XML)) AS t1(c);
Output
+----+-----------------+-------------+
| ID | tokens | Result |
+----+-----------------+-------------+
| 1 | b,c,d,e,abb,a | b,c,d,e,abb |
| 2 | b,c,d,a,e,abb | b,c,d,e,abb |
| 3 | a,b,c,d,a,e,abb | b,c,d,e,abb |
+----+-----------------+-------------+

Try as follow:
select Replace(name, N'a', N'') as RepName , ID from yourTable

Try this.
SELECT ID,Name, REPLACE(Name, 'a', ' ')
FROM tableName;

Related

Extract string using SQL Server 2012

I have a string in the form of
<div>#FIRST#12345#</div>
How do I extract the number part from this string using T-SQL in SQL Server 2012? Note the number has variable length
Using just t-sql string functions you can try:
create table t(col varchar(50))
insert into t select '<div>#FIRST#12345#</div>'
insert into t select '<div>#THIRD#543#</div>'
insert into t select '<div>#SECOND#3690123#</div>'
select col,
case when p1.v=0 or p2.v <= p1.v then ''
else Substring(col, p1.v, p2.v-p1.v)
end ExtractedNumber
from t
cross apply(values(CharIndex('#',col,7) + 1))p1(v)
cross apply(values(CharIndex('#',col, p1.v + 1)))p2(v)
Output:
Caveat, this doesn't handle any "edge" cases and assumes data is as described.
Shooting from the hip due to a missing minimal reproducible example.
Assuming that it is XML data type column.
SQL
-- DDL and sample data population, start
DECLARE #tbl TABLE (ID INT IDENTITY PRIMARY KEY, xmldata XML);
INSERT INTO #tbl (xmldata) VALUES
('<div>#FIRST#12345#</div>'),
('<div>#FIRST#770770#</div>');
-- DDL and sample data population, end
SELECT t.*
, LEFT(x, CHARINDEX('#', x) - 1) AS Result
FROM #tbl t
CROSS APPLY xmldata.nodes('/div/text()') AS t1(c)
CROSS APPLY (SELECT REPLACE(c.value('.', 'VARCHAR(100)'), '#FIRST#' ,'')) AS t2(x);
Output
+----+---------------------------+--------+
| ID | xmldata | Result |
+----+---------------------------+--------+
| 1 | <div>#FIRST#12345#</div> | 12345 |
| 2 | <div>#FIRST#770770#</div> | 770770 |
+----+---------------------------+--------+

Select substring from column but each record has different pattern

I have column with different pattern of string for each records let's call it [Description]. Here's the sample of records
[Description]
-qwetw MANN/1234556/DATE/030621/B/C/ACC/DIFF+AA11000532
-qwerty 123456789/06/29/2021/ACC./DONE/CLOSED+06+AA11001234
-qwert 123456789101213/-/BACK/300621/Rekening/Tutup+06+ZZZ21001123A
I want only pick the last number order - so the output would be:
[Description]
-11000532
-11001234
-21001123
Is there any function how to get it?
Thanks
Please try the following solutions.
First solution is for SQL Server 2017 onwards.
It is working by implementing the following steps:
It is tokenizing column value as XML.
Last token is our goal, i.e. (/root/r[last()]/text())[1]
TRIM() removes unwanted chars.
Second solution is for SQL Server 2012. It is much more involving.
SQL 2017
-- DDL and sample data population, start
DECLARE #tbl TABLE (ID INT IDENTITY PRIMARY KEY, Tokens VARCHAR(4000));
INSERT INTO #tbl VALUES
('-qwetw MANN/1234556/DATE/030621/B/C/ACC/DIFF+AA11000532'),
('-qwert 123456789101213/-/BACK/300621/Rekening/Tutup+06+ZZZ21001123A'),
('-qwerty 123456789/06/29/2021/ACC./DONE/CLOSED+06+AA11001234');
-- DDL and sample data population, end
DECLARE #separator CHAR(1) = '+'
, #CharsToRemove VARCHAR(100) = 'AZ';
SELECT ID, tokens
, TRIM(#CharsToRemove FROM token) AS Result
FROM #tbl
CROSS APPLY (VALUES (TRY_CAST('<root><r><![CDATA[' +
REPLACE(tokens, #separator, ']]></r><r><![CDATA[') +
']]></r></root>' AS XML))) AS t(c)
CROSS APPLY (VALUES (c.value('(/root/r[last()]/text())[1]', 'VARCHAR(256)'))) AS t2(token);
SQL 2012
SELECT ID, tokens
, (
SELECT SUBSTRING(token, number, 1)
FROM #tbl AS c
CROSS APPLY (
SELECT DISTINCT number
FROM master..spt_values
WHERE number BETWEEN 1 AND LEN(token)
) V
WHERE c.ID = p.ID
FOR XML PATH('r'), TYPE, ROOT('root')
)
.query('for $x in /root/r
return if (xs:int($x) instance of xs:int) then $x
else ()')
.query('/r/text()').value('.', 'BIGINT') AS Result
FROM #tbl AS p
CROSS APPLY (VALUES (TRY_CAST('<root><r><![CDATA[' +
REPLACE(tokens, #separator, ']]></r><r><![CDATA[') +
']]></r></root>' AS XML))) AS t(c)
CROSS APPLY (VALUES (c.value('(/root/r[last()]/text())[1]', 'VARCHAR(256)'))) AS t2(token);
Output
+----+---------------------------------------------------------------------+----------+
| ID | tokens | Result |
+----+---------------------------------------------------------------------+----------+
| 1 | -qwetw MANN/1234556/DATE/030621/B/C/ACC/DIFF+AA11000532 | 11000532 |
| 2 | -qwert 123456789101213/-/BACK/300621/Rekening/Tutup+06+ZZZ21001123A | 21001123 |
| 3 | -qwerty 123456789/06/29/2021/ACC./DONE/CLOSED+06+AA11001234 | 11001234 |
+----+---------------------------------------------------------------------+----------+
Your example is tricky, as it is having alphabets also as part of the order number.
I am assuming your datatype is VARCHAR(4000) and accordingly, I have applied substring in the end with 4000, to make it simpler in the end.
DECLARE #table table(Description varchar(4000))
insert into #table values
('-qwetw MANN/1234556/DATE/030621/B/C/ACC/DIFF+AA11000532')
,('-qwert 123456789101213/-/BACK/300621/Rekening/Tutup+06+ZZZ21001123A')
,('-qwerty 123456789/06/29/2021/ACC./DONE/CLOSED+06+AA11001234');
SELECT SUBSTRING(REVERSE(SUBSTRING(REVERSE(Description),1,CHARINDEX('+',REVERSE(Description)))),PATINDEX('%[1-9]%',REVERSE(SUBSTRING(REVERSE(Description),1,CHARINDEX('+',REVERSE(Description))))),4000) as ordernumber FROM #table
ordernumber
11000532
21001123A
11001234

Query to update strings using string_split function

I am trying to update column in table where data is in below format:
Id | ColA
----------
1 Peter,John:Ryan,Jack:Evans,Chris
2 Peter,John:Ryan,Jack
3 Hank,Tom
4
5 Cruise,Tom
I need to split the string by ':' and remove ',' and need to reverse the name and again append the same data separated by: and finally data should be as shown
Id | ColA
----------
1 John Peter:Jack Ryan:Chris Evans
2 John Peter:Jack Ryan
3 Tom Hank
4
5 Tom Cruise
Please let me know how can we achieve this
I tried to use Replace and Substring but how can we do it if we have data some are separated by two colon and some are separated by single colon.
Is there any way to identify and achieve the data in the above formatted one.
Here is a solution for SQL Server 2008 onwards.
It is based on XML and XQuery.
Using XQuery's FLWOR expression allows to tokenize odd vs. even XML elements. The rest is just a couple of the REPLACE() function calls to compose the desired output.
SQL
-- DDL and sample data population, start
DECLARE #tbl TABLE (ID INT IDENTITY PRIMARY KEY, tokens VARCHAR(1024));
INSERT INTO #tbl (tokens) VALUES
('Peter,John:Ryan,Jack:Evans,Chris'),
('Peter,John:Ryan,Jack'),
('Hank,Tom'),
(''),
('Cruise,Tom');
-- DDL and sample data population, end
DECLARE #separator CHAR(1) = ':'
, #comma CHAR(1) = ',';
SELECT ID, tokens
, REPLACE(REPLACE(c.query('
for $x in /root/r[position() mod 2 eq 0]
let $pos := count(root/r[. << $x])
return concat($x, sql:variable("#comma"), (/root/r[$pos])[1])
').value('text()[1]', 'VARCHAR(8000)')
, SPACE(1), #separator), #comma, SPACE(1)) AS result
FROM #tbl
CROSS APPLY (SELECT CAST('<root><r><![CDATA[' +
REPLACE(REPLACE(tokens,#comma,#separator), #separator, ']]></r><r><![CDATA[') +
']]></r></root>' AS XML)) AS t1(c)
ORDER BY ID;
Output
+----+----------------------------------+----------------------------------+
| ID | tokens | result |
+----+----------------------------------+----------------------------------+
| 1 | Peter,John:Ryan,Jack:Evans,Chris | John Peter:Jack Ryan:Chris Evans |
| 2 | Peter,John:Ryan,Jack | John Peter:Jack Ryan |
| 3 | Hank,Tom | Tom Hank |
| 4 | | NULL |
| 5 | Cruise,Tom | Tom Cruise |
+----+----------------------------------+----------------------------------+
SQL #2 (don't try it, it won't work)
Unfortunately, SQL Server doesn't fully support even XQuery 1.0 standard. XQuery 3.1 is the latest standard. XQuery 1.0 functions fn:substring-after() and fn:substring-before() are badly missing.
In a dream world a solution would be much simpler, along the following:
SELECT *
, c.query('
for $x in /root/r
return concat(fn:substring-after($x, ","), ",", fn:substring-before($x, ","))
')
FROM #tbl
CROSS APPLY (SELECT TRY_CAST('<root><r><![CDATA[' +
REPLACE(tokens, #separator, ']]></r><r><![CDATA[') +
']]></r></root>' AS XML)) AS t1(c);
Please up-vote the following suggestion to improve SQL Server:
SQL Server vNext (post 2019) and NoSQL functionality
It became one of the most popular requests for SQL Server.
The current voting tally is 590 and counting.
Something like this should work:
CREATE TABLE YourTableNameHere (
Id int NULL
,ColA varchar(1000) NULL
);
INSERT INTO YourTableNameHere (Id,ColA) VALUES
(1, 'Peter,John:Ryan,Jack:Evans,Chris')
,(2, 'Peter,John:Ryan,Jack')
,(3, 'Hank,Tom')
,(4, '')
,(5, 'Cruise,Tom');
SELECT
tbl.Id
,STUFF((SELECT
CONCAT(':'
,RIGHT(REPLACE(ss.value, ',', ' '), LEN(REPLACE(ss.value, ',', ' ')) - CHARINDEX(' ', REPLACE(ss.value, ',', ' '), 1)) /*first name*/
,' '
,CASE WHEN CHARINDEX(',', ss.value, 1) > 1 THEN LEFT(REPLACE(ss.value, ',', ' '), CHARINDEX(' ', REPLACE(ss.value, ',', ' '), 1) - 1) /*last name*/ ELSE '' END)
FROM
YourTableNameHere AS tbl_inner
CROSS APPLY string_split(tbl_inner.ColA, ':') AS ss
WHERE
tbl_inner.Id = tbl.Id
FOR XML PATH('')), 1, 1, '') AS ColA
FROM
YourTableNameHere AS tbl;
This uses the string_split function within a FOR XML clause to split the values in ColA by the : character, then replace the , with a space, parse to the left and right of the space, then recombine the parsed values delimited by a : character.
One thing to note here, per Microsoft the output of string_split is not guaranteed to be in the same order as the input:
Note
The order of the output may vary as the order is not guaranteed to match the order of the substrings in the input string.
So in order to guarantee the output of this function is going to concatenate the names back in the same order that they existed in the input column you would either need to implement your own function to split the string or come up with some criteria for combining them in a certain order. For example, you could recombine them in alphabetical order by adding ORDER BY ss.value to the inner query for ColA in the final result set. In my testing using your input the final values were ordered the same as the input column, but it is worth noting that that behaviour is not guaranteed and in order to guarantee it then you need to do more work.

Sql Procedure to count words of a given string [duplicate]

I'm trying to count how many words there are in a string in SQL.
Select ("Hello To Oracle") from dual;
I want to show the number of words. In the given example it would be 3 words though there could be more than one space between words.
You can use something similar to this. This gets the length of the string, then substracts the length of the string with the spaces removed. By then adding the number one to that should give you the number of words:
Select length(yourCol) - length(replace(yourcol, ' ', '')) + 1 NumbofWords
from yourtable
See SQL Fiddle with Demo
If you use the following data:
CREATE TABLE yourtable
(yourCol varchar2(15))
;
INSERT ALL
INTO yourtable (yourCol)
VALUES ('Hello To Oracle')
INTO yourtable (yourCol)
VALUES ('oneword')
INTO yourtable (yourCol)
VALUES ('two words')
SELECT * FROM dual
;
And the query:
Select yourcol,
length(yourCol) - length(replace(yourcol, ' ', '')) + 1 NumbofWords
from yourtable
The result is:
| YOURCOL | NUMBOFWORDS |
---------------------------------
| Hello To Oracle | 3 |
| oneword | 1 |
| two words | 2 |
Since you're using Oracle 11g it's even simpler-
select regexp_count(your_column, '[^ ]+') from your_table
Here is a sqlfiddle demo
If your requirement is to remove multiple spaces too, try this:
Select length('500 text Oracle Parkway Redwood Shores CA') - length(REGEXP_REPLACE('500 text Oracle Parkway Redwood Shores CA',
'( ){1,}', '')) NumbofWords
from dual;
Since I have used the dual table you can test this directly in your own development environment.
DECLARE #List NVARCHAR(MAX) = ' ab a
x'; /*Your column/Param*/
DECLARE #Delimiter NVARCHAR(255) = ' ';/*space*/
DECLARE #WordsTable TABLE (Data VARCHAR(1000));
/*convert by XML the string to table*/
INSERT INTO #WordsTable(Data)
SELECT Data = y.i.value('(./text())[1]', 'VARCHAR(1000)')
FROM
(
SELECT x = CONVERT(XML, '<i>'
+ REPLACE(#List, #Delimiter, '</i><i>')
+ '</i>').query('.')
) AS a CROSS APPLY x.nodes('i') AS y(i)
/*Your total words*/
select count(*) NumberOfWords
from #WordsTable
where Data is not null;
/*words list*/
select *
from #WordsTable
where Data is not null
/from this Logic you can continue alon/

How can I count the number of words in a string in Oracle?

I'm trying to count how many words there are in a string in SQL.
Select ("Hello To Oracle") from dual;
I want to show the number of words. In the given example it would be 3 words though there could be more than one space between words.
You can use something similar to this. This gets the length of the string, then substracts the length of the string with the spaces removed. By then adding the number one to that should give you the number of words:
Select length(yourCol) - length(replace(yourcol, ' ', '')) + 1 NumbofWords
from yourtable
See SQL Fiddle with Demo
If you use the following data:
CREATE TABLE yourtable
(yourCol varchar2(15))
;
INSERT ALL
INTO yourtable (yourCol)
VALUES ('Hello To Oracle')
INTO yourtable (yourCol)
VALUES ('oneword')
INTO yourtable (yourCol)
VALUES ('two words')
SELECT * FROM dual
;
And the query:
Select yourcol,
length(yourCol) - length(replace(yourcol, ' ', '')) + 1 NumbofWords
from yourtable
The result is:
| YOURCOL | NUMBOFWORDS |
---------------------------------
| Hello To Oracle | 3 |
| oneword | 1 |
| two words | 2 |
Since you're using Oracle 11g it's even simpler-
select regexp_count(your_column, '[^ ]+') from your_table
Here is a sqlfiddle demo
If your requirement is to remove multiple spaces too, try this:
Select length('500 text Oracle Parkway Redwood Shores CA') - length(REGEXP_REPLACE('500 text Oracle Parkway Redwood Shores CA',
'( ){1,}', '')) NumbofWords
from dual;
Since I have used the dual table you can test this directly in your own development environment.
DECLARE #List NVARCHAR(MAX) = ' ab a
x'; /*Your column/Param*/
DECLARE #Delimiter NVARCHAR(255) = ' ';/*space*/
DECLARE #WordsTable TABLE (Data VARCHAR(1000));
/*convert by XML the string to table*/
INSERT INTO #WordsTable(Data)
SELECT Data = y.i.value('(./text())[1]', 'VARCHAR(1000)')
FROM
(
SELECT x = CONVERT(XML, '<i>'
+ REPLACE(#List, #Delimiter, '</i><i>')
+ '</i>').query('.')
) AS a CROSS APPLY x.nodes('i') AS y(i)
/*Your total words*/
select count(*) NumberOfWords
from #WordsTable
where Data is not null;
/*words list*/
select *
from #WordsTable
where Data is not null
/from this Logic you can continue alon/