Delimited Function in SQL to Split Data between semi-colon - sql

I have the data below.
I'm only interested on program B. How do I change it into the table below using SQL syntax?
Below is my syntax but it doesn't give me what I want.
SELECT
SUBSTRING(Program, 0, CHARINDEX(';', Program)),
SUBSTRING(
SUBSTRING(Program, CHARINDEX(';', Program) + 1, LEN(Program)),
0,
CHARINDEX(';', SUBSTRING(Program, CHARINDEX(';', Program) + 1,
LEN(Program)))),
REVERSE(SUBSTRING(REVERSE(Program), 0, CHARINDEX(';', REVERSE(Program)))),
File_Count
FROM DataBase1
WHERE Program LIKE '%B%'
Thanks guys for your help.
Adhi

Try this:
SELECT
CASE WHEN PATINDEX('%B[0-9][0-9]%', Program)>0 THEN SUBSTRING(Program, PATINDEX('%B[0-9][0-9]%', Program) - 1, 4)
WHEN PATINDEX('%B[0-9]%', Program)>0 THEN SUBSTRING(Program, PATINDEX('%B[0-9]%', Program) - 1, 3)
ELSE '' END
FROM DataBase1
First WHEN is responsible for extracting pattern B[0-9][0-9], i.e. when B is followed by two digits, second one is for extracting B followed by one digits. Default is returning empty string, when no match is found. If you are interested in extracting pattern B followed by three digits, you need to add another when (as the first case), enter pattern B[-9][0-9][0-9] instead of B[0-9][0-9] and change last number from 4 to 5 (length of string that is extracted).
PATINDEX returns position where the match is found.

If you use PostgreSql you can try next solution.
First create temp table with data:
CREATE TABLE temp.test AS (
SELECT 'A1, B1' AS program, 1 AS file_count
UNION
SELECT 'B2', 1
UNION
SELECT 'A2, B3', 1
UNION
SELECT 'B4', 1
UNION
SELECT 'A3, B5', 2
UNION
SELECT 'B6', 2
UNION
SELECT 'B7', 2
UNION
SELECT 'B8', 1
UNION
SELECT 'B9', 1
UNION
SELECT 'C1;D1;A4;B10', 1
UNION
SELECT 'C2;D2;B11', 1
UNION
SELECT 'C3,D3,A5,B12', 1
UNION
SELECT 'C4;B14;D4;B11,B13', 1
);
I suggested that in one program cell can contains several B values (last select).
After that use regexp_matches to find all B in cell and select for each file_count value(first inner select) and after that sum by each of program:
SELECT
b_program,
sum(file_count)
FROM (
SELECT
(SELECT regexp_matches(program, 'B\d+')) [1] AS b_program,
file_count
FROM temp.test
WHERE upper(program) LIKE '%B%') bpt
GROUP BY b_program
ORDER BY b_program;

Related

Oracle REGEXP_REPLACE function to find decimal and special characters

I am working with table data that contains strings with decimal and back-slash like below:
info
1/2.2.2
2/1.1.1
3/1.1.11
I need to use a regular expression to replace the data like below:
info
1/2.2
2/1.1
3/1.1
Don't use a (slow) regular expression, use simple (faster) string functions instead:
SELECT info,
CASE
WHEN INSTR(info, '.', 1, 2) > 0
THEN SUBSTR(info, 1, INSTR(info, '.', 1, 2) - 1)
ELSE info
END AS part
FROM table_name;
Which, for the sample data:
CREATE TABLE table_name (info) AS
SELECT '1/2.2.2' FROM DUAL UNION ALL
SELECT '2/1.1.1' FROM DUAL UNION ALL
SELECT '3/1.1.11' FROM DUAL UNION ALL
SELECT '3/1.1' FROM DUAL;
Outputs:
INFO
PART
1/2.2.2
1/2.2
2/1.1.1
2/1.1
3/1.1.11
3/1.1
3/1.1
3/1.1
If you want to update the table then:
UPDATE table_name
SET info = SUBSTR(info, 1, INSTR(info, '.', 1, 2) - 1)
WHERE INSTR(info, '.', 1, 2) > 0
fiddle
For the sake of argument, here's a solution using REGEXP_SUBSTR(). REGEXP_SUBSTR() returns NULL if the pattern is not found. Thanks to MT0 for the CTE so I didn't have to type it up :-)
WITH table_name(ID, info) AS (
SELECT 1, '1/2.2.2' FROM DUAL UNION ALL
SELECT 2, '2/1.1.1' FROM DUAL UNION ALL
SELECT 3, '3/1.1.11' FROM DUAL UNION ALL
SELECT 4, '3/1.1' FROM DUAL UNION ALL
SELECT 5, '4/4' FROM DUAL)
SELECT ID, REGEXP_SUBSTR(info, '\d/\d\.\d') DATA
from table_name;
ID DATA
---------- --------
1 1/2.2
2 2/1.1
3 3/1.1
4 3/1.1
5
5 rows selected.

In SQL sort by Alphabets first then by Numbers

In H2 Database when i have applied order by on varchar column Numbers are coming first then Alphabets. But need to come Alphabets first then Numbers.
I have tried with
ORDER BY IF(name RLIKE '^[a-z]', 1, 2), name
but getting error like If condition is not available in H2.
My Column Data is Like
A
1-A
3
M
2-B
5
B-2
it should come like
A
B-2
M
1-A
2-B
3
5
try this out
SELECT MYCOLUMN FROM MYTABLE ORDER BY REGEXP_REPLACE (MYCOLUMN,'(*)(\d)(*)','}\2') , MYCOLUMN
One thing can be done is by altering the ASCII in order by clause.
WITH tab
AS (SELECT 'A' col FROM DUAL
UNION ALL
SELECT '1-A' FROM DUAL
UNION ALL
SELECT '3' FROM DUAL
UNION ALL
SELECT 'M' FROM DUAL
UNION ALL
SELECT '2-B' FROM DUAL
UNION ALL
SELECT '5' FROM DUAL
UNION ALL
SELECT 'B-2' FROM DUAL)
SELECT col
FROM tab
ORDER BY CASE WHEN SUBSTR (col, 1, 1) < CHR (58) THEN CHR (177) || col ELSE col END;
I have Used CHR(58) as ASCII value of numbers end at 57. and CHR(177) is used as this is the maximum in the ASCII table.
FYR : ASCII table
Given the example dataset, I'm not sure if you need further logic than this- so I'll refrain from making further assumptions:
DECLARE #temp TABLE (myval char(3))
INSERT INTO #temp VALUES
('A'), ('1-A'), ('3'), ('M'), ('2-B'), ('5'), ('B-2')
SELECT myval
FROM #temp
ORDER BY CASE WHEN LEFT(myval, 1) LIKE '[a-Z]'
THEN 1
ELSE 2
END
,LEFT(myval, 1)
Gives output:
myval
A
B-2
M
1-A
2-B
3
5

using charindex in a substring to trim a string

There is a column name from which I want to use to make a new column.
example:
name
asd_abceur1mz_a
asd_fxasdrasdusd3mz_a
asd_abceur10yz_a
asd_fxasdrasdusd15yz_a
The length of the column is not fixed so I assumed i have to use charindex to have a reference point from which I could trim.
What i want: at the end there is always z_a, and i need to place in a separate column the left part from z_a like this:
nameNew
eur1m
usd3m
eur10y
usd15y
The problem is that the number (in this example 1, 3, 10, 15) has 1 or two digits. I need to extract the information from name to nameNew.
After that i was thinking to make it easier to read and to output it like this:
eur_1m
usd_3m
eur_10y
usd_15y
I tried using a combination of substring and charindex, but so far without success.
SELECT *
, SUBSTRING(name, 1, ( CHARINDEX('z_a', NAME) - 1 )) AS nameNew
FROM myTable
This is for the first step, trimming the string, for the 2nd step (making it easier to read) I don't know how to target the digit and place an _.
Any help would be appreciated. Using sql server 2012
edit:
First of all thank you for your time and solutions. But your queries more or less even if they are working for 1 or 2 digits have the same problem. Consider this situation:
name
ab_dertEUR03EUR10YZ_A
if eur is two times in the string, then how can I eliminate this? Sorry for not includding this in my original post but i forgot that situation is possible and now that's a problem.
edit:
test your queries here, on this example:
http://www.sqlfiddle.com/#!3/21610/1
Please note that at the end it can be any combination of 1 or 2 digits and the letter y or m.
Ex: ab_rtgtEUR03EUR2YZ_A , ab_rtgtEUR03EUR2mZ_A, ab_rtgtEUR03EUR20YZ_A, ab_rtgtEUR03EUR20mZ_A
Some values for testing:
('ex_CHFCHF01CHF10YZ_A'), ('ab_rtgtEUR03EUR2YZ_A'), ('RON_asdRON2MZ_A'),
('tg_USDUSD04USD5YZ_A');
My understanding of your queries is that they perform something simillar to this (or at least they should)
ex_CHFCHF01CHF10YZ_A -> ex_CHFCHF01CHF10Y -> Y01FHC10FHCFHC -> Y01FHC -> CHF01Y -> CHF_01Y
RON_asdRON2MZ_A -> RON_asdRON2M -> M2NORdsa_ron -> M2NOR -> RON2M -> RON_2M
This works for one or two digits:
stuff(case
when name like '%[0-9][0-9]_z[_]a'
then left(right(name, 9), 6)
when name like '%[0-9]_z[_]a'
then left(right(name, 8), 5)
end, 4, 0, '_')
You can use a combination of substring , reverse and charindex.
SQL Fiddle
select substring(namenew,1,3) + '_' + substring(namenew, 4, len(namenew))
from (
select
case when name like '%[0-9][0-9]_z[_]a' then
reverse(substring(reverse(name), charindex('a_z',reverse(name)) + 3, 6))
when name like '%[0-9]_z[_]a' then
reverse(substring(reverse(name), charindex('a_z',reverse(name)) + 3, 5))
end as namenew
from myTable
) t
Try it like this:
declare #tbl TABLE(name VARCHAR(100));
insert into #tbl VALUES
('asd_abceur1mz_a')
,('asd_fxasdrasdusd3mz_a')
,('asd_abceur10yz_a')
,('asd_fxasdrasdusd15yz_a')
,('ab_dertEUR03EUR10YZ_A');
WITH CutOfThreeAtTheEnd AS
(
SELECT LEFT(name,LEN(name)-3) AS nameNew
FROM #tbl
)
,Max6CharsFromEnd AS
(
SELECT RIGHT(nameNew,6) AS nameNew
FROM CutOfThreeAtTheEnd
)
SELECT nameNew
,FirstNumber.Position
,Parts.*
,Parts.FrontPart + '_' + Parts.BackPart AS FinalString
FROM Max6CharsFromEnd
CROSS APPLY
(
SELECT MIN(x)
FROM
(
SELECT CHARINDEX('0',nameNew,1) AS x
UNION SELECT CHARINDEX('1',nameNew,1)
UNION SELECT CHARINDEX('2',nameNew,1)
UNION SELECT CHARINDEX('3',nameNew,1)
UNION SELECT CHARINDEX('4',nameNew,1)
UNION SELECT CHARINDEX('5',nameNew,1)
UNION SELECT CHARINDEX('6',nameNew,1)
UNION SELECT CHARINDEX('7',nameNew,1)
UNION SELECT CHARINDEX('8',nameNew,1)
UNION SELECT CHARINDEX('9',nameNew,1)
) AS tbl
WHERE x>0
) AS FirstNumber(Position)
CROSS APPLY(SELECT SUBSTRING(nameNew,FirstNumber.Position,1000) AS BackPart
,SUBSTRING(nameNew,FirstNumber.Position-3,3) AS FrontPart) AS Parts
this is the result:
nameNew Position BackPart FrontPart FinalString
ceur1m 5 1m eur eur_1m
dusd3m 5 3m usd usd_3m
eur10y 4 10y eur eur_10y
usd15y 4 15y usd usd_15y
EUR10Y 4 10Y EUR EUR_10Y

Check palindrome without using string functions with condition

I have a table EmployeeTable.
If I want only that records where employeename have character of 1 to 5
will be palindrome and there also condition like total character is more then 10 then 4 to 8 if character less then 7 then 2 to 5 and if character less then 5 then all char will be checked and there that are palindrome then only display.
Examples :- neen will be display
neetan not selected
kiratitamara will be selected
I try this something on string function like FOR first case like name less then 5 character long
SELECT SUBSTRING(EmployeeName,1,5),* from EmaployeeTable where
REVERSE (SUBSTRING(EmployeeName,1,5))=SUBSTRING(EmployeeName,1,5)
I want to do that without string functions,
Can anyone help me on this?
You need at least SUBSTRING(), I have a solution like this:
(In SQL Server)
DECLARE #txt varchar(max) = 'abcba'
;WITH CTE (cNo, cChar) AS (
SELECT 1, SUBSTRING(#txt, 1, 1)
UNION ALL
SELECT cNo + 1, SUBSTRING(#txt, cNo + 1, 1)
FROM CTE
WHERE SUBSTRING(#txt, cNo + 1, 1) <> ''
)
SELECT COUNT(*)
FROM (
SELECT *, ROW_NUMBER() OVER (ORDER BY cNo DESC) as cRevNo
FROM CTE t1 CROSS JOIN
(SELECT Max(cNo) AS strLength FROM CTE) t2) dt
WHERE
dt.cNo <= dt.strLength / 2
AND
dt.cChar <> (SELECT dti.cChar FROM CTE dti WHERE dti.cNo = cRevNo)
The result will shows the count of differences and 0 means no differences.
Note :
Current solution is Non-Case-Sensitive for change it to a Case-Sensitive you need to check the strings in a case-sensitive collation like Latin1_General_BIN
You can use this solution as a SVF or something like that.
I dont realy understand why you dont want to use string functions in your query, but here is one solution. Compute everything beforehand:
Add Column:
ALTER TABLE EmployeeTable
ADD SubString AS
SUBSTRING(EmployeeName,
(
CASE WHEN LEN(EmployeeName)>10
THEN 4
WHEN LEN(EmployeeName)>7
THEN 2
ELSE 1 END
)
,
(
CASE WHEN LEN(EmployeeName)>10
THEN 8
WHEN LEN(EmployeeName)>7
THEN 5
ELSE 5 END
)
PERSISTED
GO
ALTER TABLE EmployeeTable
ADD Palindrome AS
REVERSE(SUBSTRING(EmployeeName,
(
CASE WHEN LEN(EmployeeName)>10
THEN 4
WHEN LEN(EmployeeName)>7
THEN 2
ELSE 1 END
)
,
(
CASE WHEN LEN(EmployeeName)>10
THEN 8
WHEN LEN(EmployeeName)>7
THEN 5
ELSE 5 END
)) PERSISTED
GO
Then your query will looks like:
SELECT * from EmaployeeTable
where Palindrome = SubString
BUT!
This is not a good idea. Please tell us, why you dont want to use string functios.
You could do it building a list of palindrome words using a recursive query that generates palindrome words till a length o n characters and then selects employees with the name matching a palindrome word. This may be a really inefficient way, but it does the trick
This is a sample query for Oracle, PostgreSQL should support this feature as well with little differences on syntax. I don't know about other RDBMS.
with EmployeeTable AS (
SELECT 'ADA' AS employeename
FROM DUAL
UNION ALL
SELECT 'IDA' AS employeename
FROM DUAL
UNION ALL
SELECT 'JACK' AS employeename
FROM DUAL
), letters as (
select chr(ascii('A') + rownum - 1) as letter
from dual
connect by ascii('A') + rownum - 1 <= ascii('Z')
), palindromes(word, len ) as (
SELECT WORD, LEN
FROM (
select CAST(NULL AS VARCHAR2(100)) as word, 0 as len
from DUAL
union all
select letter as word, 1 as len
from letters
)
union all
select l.letter||p.word||l.letter AS WORD, len + 1 AS LEN
from palindromes p
cross join letters l
where len <= 4
)
SEARCH BREADTH FIRST BY word SET order1
CYCLE word SET is_cycle TO 'Y' DEFAULT 'N'
select *
from EmployeeTable
WHERE employeename IN (
SELECT WORD
FROM palindromes
)
DECLARE #cPalindrome VARCHAR(100) = 'SUBI NO ONIBUS'
SET #cPalindrome = REPLACE(#cPalindrome, ' ', '')
;WITH tPalindromo (iNo) AS (
SELECT 1
WHERE SUBSTRING(#cPalindrome, 1, 1) = SUBSTRING(#cPalindrome, LEN(#cPalindrome), 1)
UNION ALL
SELECT iNo + 1
FROM tPalindromo
WHERE SUBSTRING(#cPalindrome, iNo + 1, 1) = SUBSTRING(#cPalindrome, LEN(#cPalindrome) - iNo, 1)
AND LEN(#cPalindrome) > iNo
)
SELECT IIF(MAX(iNo) = LEN(#cPalindrome), 'PALINDROME', 'NOT PALINDROME')
FROM tPalindromo

Ignoring specific letters to find match in SQL Query

I want to query a table for all the values that are on a list on another table to find matches, but I know that some of the values in either table may be typed in incorrectly. One table may have '10Hf7K8' and another table may have '1OHf7K8' but I still want them to match.
Another example, if one table has 'STOP' but I know that in myTable, some of fields may say '5T0P' or 'ST0P' or '5TOP'. I want those to come up as results too. The same thing may occur for '2' and 'Z' if I want 'ZEPT' and '2EPT' to match.
So if I know to account for inconsistencies between '0' and 'O', '5' and 'S' and 'Z' and '2', and knowing that they will be in the same spot, but I do not know where exactly they will be in the word or how many letters the word will have, is it possible to make a query ignoring those letters?
Additional Information: These values are hundreds of serial keys that I have no way of confirming which is correct version between the two tables. I should not have used actual words for my example, these values can be any combination of letters and numbers in any order. There is no distinct pattern that I can hard code.
SOLUTION: Goat CO, Learning, and user3216429's answers contained the solution I needed. I was able to find matching values while keeping the underlying data.
Cleaning data is preferable, but could use nested REPLACE() statements if you can't alter the underlying data:
SELECT *
FROM Table1 a
JOIN Table2 b
ON REPLACE(REPLACE(REPLACE(a.field1,'2','Z'),'5','S'),'0','O') = REPLACE(REPLACE(REPLACE(b.field1,'2','Z'),'5','S'),'0','O')
Cleansing the data could be the same nested replace statement:
ALTER TABLE Table1 ADD cleanfield VARCHAR(25)
UPDATE Table1
SET cleanfield = REPLACE(REPLACE(REPLACE(dirtyfield,'2','Z'),'5','S'),'0','O')
Then you'd be able to join the tables on the clean field.
what you can and should do is to clean your data, replace all these 2,0,5 with Z,O and S.
But if you want to try some other solution, then you can try something like this
select case when
REPLACE(REPLACE(REPLACE('stop','0','o'),'5','s'),'2','Z') = REPLACE(REPLACE(REPLACE('5t0p','0','o'),'5','s'),'2','Z') then 1 else 2 end
Like previously said, if you have time, clean up the data.
If not, SQL SERVER supplies two string functions that might help.
The example is from my blog article. http://craftydba.com/?p=5211
The SOUNDEX() function turns a word into a 4 character value. The DIFFERENCE() function tells you how close two words are.
Your example seems to be one word. You might want to use a calculated column and index it so that the where clause is SARGABLE.
If you are using paragraphs, use a standard split function to turn your text paragraph into words. Use these functions to search the data. However, this will result in a non-SARGABLE expression.
-- Example returns 4, words are very close
select
soundex('Dog') as word_val1,
soundex('Dogs') as word_val2,
difference('Dog', 'Dogs') as how_close
-- Example returns 0, words are very different
select
soundex('Rattle-Snake') as word_val1,
soundex('Mongoose') as word_val2,
difference('Rattle-Snake', 'Mongoose') as how_close
output:
word_val1 word_val2 how_close
--------- --------- -----------
D200 D200 4
word_val1 word_val2 how_close
--------- --------- -----------
R340 M522 0
Last but not least, you an also look into FULL text indexing for speed. This requires some extra overhead (FTI structure and process to update FTI).
http://craftydba.com/?p=1421
select REPLACE(REPLACE( REPLACE([column_name],'O','0'),'Z','2'),'5','S')
from [table_name]
1) To filter out all rows containing all forms of STOP word (STOP, 5TOP, ST0P, 5T0P) you could use following query based on LIKE:
SELECT *
FROM (
SELECT 1, 'CocoJambo' UNION ALL
SELECT 2, '5T0P' UNION ALL
SELECT 3, ' 5TOP ' UNION ALL
SELECT 4, ' ST0P ' UNION ALL
SELECT 5, ' STOP ' UNION ALL
SELECT 6, 'ZTOP'
) x (ID, ColA)
WHERE x.ColA LIKE '%[5S]T[0O]P%';
Output:
ID ColA
----------- ---------
2 5T0P
3 5TOP
4 ST0P
5 STOP
2) Regarding your question:
For every table
first I would try to build a table with all patterns for every word and for every pattern I would store the proper/accurate word,
then I would try to replace every occurrence of pattern with the proper word
After this prepossessing of these two tables I will try to match both tables.
This script will replace only the first occurrence of pattern
SELECT x.*, oa.*,
CASE
WHEN oa.PatIx > 0 THEN STUFF( x.ColA , oa.PatIx , LEN(oa.Word), oa.Word )
ELSE x.ColA
END AS NewColA
FROM (
SELECT 1, 'CocoJambo' UNION ALL
SELECT 2, '5T0P' UNION ALL
SELECT 3, ' 5TOP ' UNION ALL
SELECT 4, ' ST0P ' UNION ALL
SELECT 5, ' STOP jambo jumbo 5TOP bOb ' UNION ALL
SELECT 6, 'ZTOP'
) x (ID, ColA)
OUTER APPLY (
SELECT *
FROM (
SELECT w.WordPattern, w.Word, PATINDEX( w.WordPattern , x.ColA ) AS PatIx
FROM #Words w
) y
WHERE y.PatIx > 0
) oa
Output:
ID ColA WordPattern Word PatIx NewColA
-- ----------------------------- ------------ ---- ----- ----------------------------
1 CocoJambo %b[o0]% bob 8 CocoJambob
2 5T0P %[5S]T[0O]P% STOP 1 STOP
3 5TOP %[5S]T[0O]P% STOP 2 STOP
4 ST0P %[5S]T[0O]P% STOP 3 STOP
5 STOP jambo jumbo 5TOP bOb %[5S]T[0O]P% STOP 4 STOP jambo jumbo 5TOP bOb
5 STOP jambo jumbo 5TOP bOb %b[o0]% bob 12 STOP jambobjumbo 5TOP bOb
6 ZTOP NULL NULL NULL ZTOP
Note: this solution it's just a proof of concept. It needs development.
Or you could try this solution which replaces all wrong words with the proper form:
CREATE TABLE dbo.Words ( Id INT IDENTITY PRIMARY KEY, WordSource NVARCHAR(50) NOT NULL, Word NVARCHAR(50) NOT NULL );
INSERT dbo.Words ( WordSource , Word ) VALUES ( N'5T0P' , N'STOP' );
INSERT dbo.Words ( WordSource , Word ) VALUES ( N'5TOP' , N'STOP' );
INSERT dbo.Words ( WordSource , Word ) VALUES ( N'ST0P' , N'STOP' );
INSERT dbo.Words ( WordSource , Word ) VALUES ( N'b0b' , N'bob' );
INSERT dbo.Words ( WordSource , Word ) VALUES ( N'bOb' , N'bob' );
GO
CREATE FUNCTION dbo.ReplaceWords (#ColA NVARCHAR(4000), #Num INT)
RETURNS TABLE
AS
RETURN
WITH CteRecursive
AS
(
SELECT w.Id, w.WordSource, w.Word, REPLACE(#ColA, w.WordSource, w.Word) AS NewColA
FROM dbo.Words w
WHERE w.Id = 1
UNION ALL
SELECT w.Id, w.WordSource, w.Word, REPLACE(prev.NewColA, w.WordSource, w.Word) AS NewColA
FROM CteRecursive prev INNER JOIN dbo.Words w ON prev.Id + 1 = w.Id
WHERE prev.Id + 1 <= #Num
)
SELECT r.NewColA
FROM CteRecursive r
WHERE r.Id = #Num
GO
-- Testing
SELECT * FROM dbo.ReplaceWords(N' ST0P jambo 5TOP bOb jumbo ', 5) f;
Output
NewColA
----------------------------
STOP jambo STOP bob jumbo
You can use previous function to replace all wrong words within every table and then you can compare both tables:
DECLARE #Num INT;
SET #Num = (SELECT COUNT(*) FROM dbo.Words);
SELECT x.*, rpl.NewColA
FROM (
SELECT 1, N'CocoJambo' UNION ALL
SELECT 2, N'5T0P' UNION ALL
SELECT 3, N' 5TOP ' UNION ALL
SELECT 4, N' ST0P ' UNION ALL
SELECT 5, N' STOP jambo jumbo 5TOP bOb ' UNION ALL
SELECT 6, N'ZTOP' UNION ALL
SELECT 7, N'' UNION ALL
SELECT 8, NULL
) x (ID, ColA)
OUTER APPLY dbo.ReplaceWords(x.ColA, #Num) rpl
Output:
ID ColA NewColA
-- ----------------------------- ----------------------------
1 CocoJambo CocoJambo
2 5T0P STOP
3 5TOP STOP
4 ST0P STOP
5 STOP jambo jumbo 5TOP bOb STOP jambo jumbo STOP bob
6 ZTOP ZTOP
7
8 NULL NULL