using regex to find same digit phone numbers - sql

I need to find same digit phone numbers from a table and delete these. Phone Numbers are like below :
+999999999999
11111111
0000000000000
44444444
I am following this answer to solve this. I am trying :
select * from tblPhone where PhoneNo like '^([0-9a-z])\1+$'
But not succeed. PhoneNo is varchar. How I can achieve this ?

Try this:
select *
from tblPhone
where
substring(replace(PhoneNo,'+',''),1,len(replace(PhoneNo,'+',''))-1)
= substring(replace(PhoneNo,'+',''),2,len(replace(PhoneNo,'+','')))
The idea is that if substring from 1st to second-last position matches the one from 2nd to last, the string must be composed of identical characters.
Demo

Here is an idea. There is a problem with the first character, which can be a + or number. Let's substitute the second character for an empty string and look at the result:
where replace(PhoneNo, substring(PhoneNo, 2, 1), '') in ('+', '') and
(PhoneNo not like '%[^0-9]%' and PhoneNo like '[0-9]%'or
PhoneNo not like '+%[^0-9]%') and PhoneNo like '+%'
)

You can do a pattern matching in SQL Server using patindex but regular expressions as such are not directly supported. There is hope, however, if you use .Net and CLR user-defined functions.

create table #temp(col1 varchar(25))
insert into #temp values ('+9999999')
insert into #temp values ('+123456789')
insert into #temp values ('+444444444')
insert into #temp values ('+9840536987')
select * from #temp
begin tran
select * from #temp
delete from #temp
where cast(replace(replace(col1,'+',''),RIGHT(replace(col1,'+',''),1),0) as bigint) = 0
select * from #temp
rollback tran

You can try this:
SELECT *
FROM tblPhone
WHERE
CAST(PhoneNo AS BIGINT) = REPLICATE(RIGHT(PhoneNo, 1), LEN(CAST(PhoneNo AS BIGINT)))
OR
SELECT *
FROM tblPhone
WHERE REPLACE(PhoneNo, RIGHT(PhoneNo, 1),'') IN ('+','')

This generates the set all the possible invalid phone numbers (which is a very small number) and joins that to tblPhone. This is more efficient than doing string manipulations on every phone number in the table.
DELETE t1
FROM tblPhone t1
INNER JOIN (VALUES (''),('+')) t2(prefix)
CROSS JOIN (VALUES('0'),('1'),('2'),('3'),('4'),('5'),('6'),('7'),('8'),('9')) t3(digit)
CROSS JOIN (SELECT TOP (13) ROW_NUMBER() OVER(ORDER BY (SELECT 1)) FROM master.dbo.spt_values) t4(n)
ON PhoneNo = prefix+REPLICATE(digit,n)

Related

I need help parsing an HL7 string with TSQL

I have a column in a table that looks like this
Name
WALKER^JAMES^K^^
ANDERSON^MICHAEL^R^^
HUFF^CHRIS^^^
WALKER^JAMES^K^^
SWEARINGEN^TOMMY^L^^
SMITH^JOHN^JACCOB^^
I need to write a query that looks like this
Name
FirstName
LastName
MiddleName
WALKER^JAMES^K^^
JAMES
WALKER
K
ANDERSON^MICHAEL^R^^
MICHAEL
ANDERSON
R
HUFF^CHRIS^^^
CHRIS
HUFF
BUTLER^STEWART^M^^
STEWART
BUTLER
M
SWEARINGEN^TOMMY^L^^
TOMMY
SWEARINGEN
L
SMITH^JOHN^JACCOB^^
JOHN
SMITH
JACCOB
I need help generating the LastName column.
This is what I've tried so far
SUBSTRING
(
--SEARCH THE NAME COLUMN
Name,
--Starting after the first '^'
CHARINDEX('^', Name) + 1 ),
--Index of second ^ minus the index of the first ^
(CHARINDEX('^', PatientName, CHARINDEX('^', PatientName) +1)) - (CHARINDEX('^', PatientName))
)
This produces:
Invalid length parameter passed to the LEFT or SUBSTRING function.
I know this can work because if I change the minus sign to a plus sign it performs as expected.
It produces the right integer.
Where am I going wrong? Is there a better way to do this?
If you are using the latest SQL Server versions 2016 13.x or higher, you can maximize the use of string_split function with ordinal (position).
declare #strTable table(sqlstring varchar(max))
insert into #strTable (sqlstring) values ('WALKER^JAMES^K^^')
insert into #strTable (sqlstring) values ('ANDERSON^MICHAEL^R^^')
insert into #strTable (sqlstring) values ('HUFF^CHRIS^^^')
insert into #strTable (sqlstring) values ('SWEARINGEN^TOMMY^L^^');
with tmp as
(select value s, Row_Number() over (order by (select 0)) n from #strTable
cross apply String_Split(sqlstring, '^', 1))
select t2.s as FirstName, t1.s as LastName, t3.s as MiddleInitial from tmp t1
left join tmp t2 on t2.n-t1.n = 1
left join tmp t3 on t3.n-t1.n = 2
where t1.n = 1 or t1.n % 5 = 1
I recommend SUBSTRING() as it will perform the best. The challenge with SUBSTRING is it's hard to account to keep track of the nested CHARDINDEX() calls so it's better to break the calculation into pieces. I use CROSS APPLY to alias each "^" found and start from there to search for the next. Also allows to do NULLIF() = 0, so if it can't find the "^", it just returns a NULL instead of erroring out
Parse Delimited String using SUBSTRING() and CROSS APPLY
DROP TABLE IF EXISTS #Name
CREATE TABLE #Name (ID INT IDENTITY(1,1) PRIMARY KEY,[Name] varchar(255))
INSERT INTO #Name
VALUES ('WALKER^JAMES^K^^')
,('ANDERSON^MICHAEL^R^^')
,('HUFF^CHRIS^^^')
,('SWEARINGEN^TOMMY^L^^');
SELECT ID
,A.[Name]
,LastName = NULLIF(SUBSTRING(A.[Name],0,idx1),'')
,FirstName = NULLIF(SUBSTRING(A.[Name],idx1+1,idx2-idx1-1),'')
,MiddleInitial = NULLIF(SUBSTRING(A.[Name],idx2+1,idx3-idx2-1),'')
FROM #Name AS A
CROSS APPLY (SELECT idx1 = NULLIF(CHARINDEX('^',[Name]),0)) AS B
CROSS APPLY (SELECT idx2 = NULLIF(CHARINDEX('^',[Name],idx1+1),0)) AS C
CROSS APPLY (SELECT idx3 = NULLIF(CHARINDEX('^',[Name],idx2+1),0)) AS D

How to put a comma separated value from a column in a table into SQL IN operator?

I have a table which has a column in which I am storing a comma separated text with single quotes for each of the comma separated values. These values are employee IDs. This is how it looks
Now, I have a SQL query wherein I need to put the value from this column into a SQL IN operator. Something like this:
select *
from EMPLOYEE_MASTER
where EMPLOYEEID IN (select CM_CONFIG_VALUE
from ADL_CONFIG_MAST_T
where CM_CONFIG_KEY like 'ATT_BIOMETRIC_OU_ID'
)
But this, does not work, the query when executed returns 0 rows whereas if I execute the query normally like below, it works.
select *
from EMPLOYEE_MASTER
where EMPLOYEEID IN('9F3DD4B791554DDE','C9B90D62851D43AB','828CB9E6204B4DDC')
Please suggest what I should do here. I have tried using substring to remove the first and the last character as well assuming that single quotes might be the issue, but that does not work either.
select * from EMPLOYEE_MASTER where EMPLOYEEID IN(select EMPLOYEEID from ADL_CONFIG_MAST_T where CM_CONFIG_KEY like 'ATT_BIOMETRIC_OU_ID')
column should be same in where COLUMNNAME IN (select COLUMNNMAE from tablename)
You can create a temp varible and then use exec command to get the desired result.
declare #temp varchar(200)
select #temp=CM_CONFIG_VALUE
from ADL_CONFIG_MAST_T
where CM_CONFIG_KEY like 'ATT_BIOMETRIC_OU_ID'
exec('select *
from EMPLOYEE_MASTER
where EMPLOYEEID IN (' + #temp + ')')
Try This:
DECLARE #ID VARCHAR(500);
DECLARE #Number VARCHAR(500);
DECLARE #comma CHAR;
SET #comma = ','
SET #ID = (select CM_CONFIG_VALUE
from ADL_CONFIG_MAST_T
where CM_CONFIG_KEY like %ATT_BIOMETRIC_OU_ID% + #comma);
Create table #temp (EMPLOYEEID varchar(500))
WHILE CHARINDEX(#comma, #ID) > 0
BEGIN
SET #Number = SUBSTRING(#ID, 0, CHARINDEX(#comma, #ID))
SET #ID = SUBSTRING(#ID, CHARINDEX(#comma, #ID) + 1, LEN(#ID))
Insert into #temp
select #Number
END
select *
from EMPLOYEE_MASTER
where EMPLOYEEID IN(select EMPLOYEEID from #temp)
The reason you are not getting it in your query is because your inner query returns only one row. So your query searches for '9F3DD4B791554DDE','C9B90D62851D43AB','828CB9E6204B4DDC' as as single record.
If your compatibility level is greater than or equal to 130 you can use STRING_SPLIT() function. Then your query would be
SELECT *
FROM EMPLOYEE_MASTER
WHERE EMPLOYEEID IN
(SELECT value AS empid
FROM ADL_CONFIG_MAST_T CROSS APPLY string_split(CM_CONFIG_VALUE, ',' )
WHERE CM_CONFIG_KEY LIKE 'ATT_BIOMETRIC_OU_ID' )
What this actually does is, it splits the CM_CONFIG_VALUE with ',' and returns them as rows. This is the value column I have referred. Then you use them with the IN clause.
Hope this helps!
Direct IN condition will not work here. You have split your string before searching. You can do that with XML options in SQL SERVER 2014
SELECT *
FROM EMP
WHERE EMPID IN (
SELECT a.c.value('.', 'VARCHAR(1000)')
FROM (
SELECT x = CAST('<a>' +
REPLACE(REPLACE(CM_CONFIG_VALUE , ',', '</a><a>'),'''','') + '</a>' AS XML )
FROM ADL_CONFIG_MAST_T
-- WHERE <your_condition>
) m
CROSS APPLY x.nodes('/a') a(c))
CHECK DEMO HERE
For the version 2016 and above you can use STRING_SPLIT with Compatibility level 130

Select rows using in with comma-separated string parameter

I'm converting a stored procedure from MySql to SQL Server. The procedure has one input parameter nvarchar/varchar which is a comma-separated string, e.g.
'1,2,5,456,454,343,3464'
I need to write a query that will retrieve the relevant rows, in MySql I'm using FIND_IN_SET and I wonder what the equivalent is in SQL Server.
I also need to order the ids as in the string.
The original query is:
SELECT *
FROM table_name t
WHERE FIND_IN_SET(id,p_ids)
ORDER BY FIND_IN_SET(id,p_ids);
The equivalent is like for the where and then charindex() for the order by:
select *
from table_name t
where ','+p_ids+',' like '%,'+cast(id as varchar(255))+',%'
order by charindex(',' + cast(id as varchar(255)) + ',', ',' + p_ids + ',');
Well, you could use charindex() for both, but the like will work in most databases.
Note that I've added delimiters to the beginning and end of the string, so 464 will not accidentally match 3464.
You would need to write a FIND_IN_SET function as it does not exist. The closet mechanism I can think of to convert a delimited string into a joinable object would be a to create a table-valued function and use the result in a standard in statement. It would need to be similar to:
DECLARE #MyParam NVARCHAR(3000)
SET #MyParam='1,2,5,456,454,343,3464'
SELECT
*
FROM
MyTable
WHERE
MyTableID IN (SELECT ID FROM dbo.MySplitDelimitedString(#MyParam,','))
And you would need to create a MySplitDelimitedString type table-valued function that would split a string and return a TABLE (ID INT) object.
A set based solution that splits the id's into ints and join with the base table which will make use of index on the base table id. I assumed the id would be an int, otherwise just remove the cast.
declare #ids nvarchar(100) = N'1,2,5,456,454,343,3464';
with nums as ( -- Generate numbers
select top (len(#ids)) row_number() over (order by (select 0)) n
from sys.messages
)
, pos1 as ( -- Get comma positions
select c.ci
from nums n
cross apply (select charindex(',', #ids, n.n) as ci) c
group by c.ci
)
, pos2 as ( -- Distinct posistions plus start and end
select ci
from pos1
union select 0
union select len(#ids) + 1
)
, pos3 as ( -- add row number for join
select ci, row_number() over (order by ci) as r
from pos2
)
, ids as ( -- id's and row id for ordering
select cast(substring(#ids, p1.ci + 1, p2.ci - p1.ci - 1) as int) id, row_number() over (order by p1.ci) r
from pos3 p1
inner join pos3 p2 on p2.r = p1.r + 1
)
select *
from ids i
inner join table_name t on t.id = i.id
order by i.r;
You can also try this by using regex to get the input values from comma separated string :
select * from table_name where id in (
select regexp_substr(p_ids,'[^,]+', 1, level) from dual
connect by regexp_substr(p_ids, '[^,]+', 1, level) is not null );

Extracting from text using tsql

I have the following string format in a Sql table column
[CID]: 267 [MID]: 319A [Name]: RJR
How can I extract only the value of MID which is 319A in select query so I can use the MID in a join.
In other words I need to extract the MID value from this text field to use it in a join. I copy/pasted the value and it looks like there are /n (new line) characters after each value.
Thanks in advance
you may try this one.
declare
#t varchar(100)
set #t = '[CID]: 267 [MID]: 319A [Name]: RJR';
select ltrim(rtrim(substring(#t,charindex('[MID]:',#t)+6,(charindex('[NAME]',#t))-(charindex('[MID]:',#t)+6))))
---------------------------------------------------------
319A
ltrim and rtrim will trim your 319A value.
you can try without them at start if you like.
Cheers
http://www.simple-talk.com/sql/t-sql-programming/tsql-regular-expression-workbench/
to add regex support to sql server
Rubular Regex to get you started:
\[MID\]: (.*) \[Name]:
Not clean at ALL, but if you need it in SQL, here you go:
Use
SUBSTRING ( value_expression , start_expression , length_expression )
and
LOCATE( string1, string2 [, start] )
together:
SUBSTRING(INPUT,
((SELECT LOCATE( 'MID]: ', INPUT ))+6),
((SELECT LOCATE( '[Name]', INPUT )) - ((SELECT LOCATE( 'MID]: ', INPUT ))+6))
depending where is taking place? If it is in a batch process, I would export those fields with an ID, write a perl one liner that extracts them, and then load them back to the db. it would be so much faster than using these functions.
if it is screen event, then I suggest breaking them into 3 columns instead, itll actully save you space.
Don't really think you need all these trimming and substring-ing functions.
USE tempdb;
GO
CREATE TABLE #t1
(
a INT,
b VARCHAR(64)
);
INSERT #t1 SELECT 1, '[CID]: 267 [MID]: 319A [Name]: RJR'
UNION ALL SELECT 2, '[CID]: 26232 [MID]: 229dd5A [Name]: RJ'
UNION ALL SELECT 3, 'Garbage that will not match';
CREATE TABLE #t2
(
c INT,
d VARCHAR(32)
);
INSERT #t2 SELECT 4, '319A'
UNION ALL SELECT 5, '229dd5A'
UNION ALL SELECT 6, 'NO MATCH';
SELECT t1.a, t1.b, t2.c, t2.d
FROM #t1 AS t1
INNER JOIN #t2 AS t2
ON t1.b LIKE '%`[MID`]: ' + t2.d + ' %' ESCAPE '`'
GO
DROP TABLE #t1, #t2;
If you have no idea how many spaces might be between [MID]: and the start of your value, or the end of your value and the start of the next [, and assuming there are no spaces in the values you want to match, you could use:
ON REPLACE(t1.b, ' ', '') LIKE '%`[MID`]:' + t2.d + '`[%' ESCAPE '`'

SQL Server, combining LIKE and IN?

Is there an easy way to combine LIKE and IN in one statement in SQL Server, without using a lot of AND and OR?
e.g. I know in MySQL you can do it this way:
SELECT * FROM table1 WHERE column1 REGEXP 'value1|value2|value3'
Not really.
There is no alternation operator in the LIKE pattern syntax. If on 2008 you can use
SELECT *
FROM table1
WHERE EXISTS(SELECT *
FROM (VALUES ('value1'),
('value2'),
('value3')) Vals(val)
WHERE column1 LIKE '%' + val + '%')
You can also use Regular Expressions in SQL Server but not natively. You need to enable CLR and install an assembly for this.
Yes there is.
Given the following table:
--- (a) Test Table
DECLARE #EAV TABLE (
entity int,
attr varchar(50),
val varchar(50)
)
INSERT INTO #EAV (entity, attr, val) VALUES
(1, 'mobileNo', '016-222-9000'),
(2, 'mobileNo', '016-254-5000'),
(3, 'mobileNo', '012-378-4550'),
(4, 'mobileNo', '019-456-2258'),
(5, 'mobileNo', '017-378-8888'),
(6, 'mobileNo', '010-111-9999')
You can achieve this using the following SQL:
--- (b) Code for LIKE ... IN
DECLARE #patterns varchar(100) = '016%, %378%' --- the patterns
SELECT pattern=p.value, x.entity, x.attr, x.val
--from Meta.StrSplit(#patterns,',') p
FROM string_split(#patterns, ',') p
CROSS APPLY #EAV x
WHERE x.val like LTRIM(RTRIM(p.value)) --- trim needed to strip off trailing & leading blanks that mess up pattern
To provide a complete answer:
------------------------------------------
---- Wrap this into a function
------------------------------------------
CREATE OR ALTER FUNCTION dbo.InLike (#string varchar(400), #listPatterns varchar(400))
RETURNS TABLE AS
RETURN (
SELECT Pattern=p.Value
--FROM Meta.StrSplit(#listPatterns, ',') p
FROM STRING_SPLIT(#listPatterns, ',') p
WHERE #string LIKE p.[Value]
)
GO
And here are some usage examples:
---- USAGE (a) JOIN
SELECT *
FROM #EAV x
CROSS APPLY dbo.InLike(x.val,'016%, %888%') p
---- USAGE (b) CASE statement
SELECT *
, NumberCategory = CASE
WHEN EXISTS (SELECT 1 FROM dbo.InLike(x.val,'016%, %888%')) THEN 'Special Numbers'
ELSE 'Ordinary Numbers'
END
FROM #EAV x
---- USAGE (c) IF statement
declare #MobileNo varchar(50) = '016-888-0000'
IF EXISTS (SELECT 1 FROM Meta.InLike (#MobileNo, '016%,%888%'))
PRINT #MobileNo + ' is special number'
ELSE PRINT #MobileNo + 'is NOT special number'
---- USAGE (d) WHERE condition
SELECT * FROM #EAV x
WHERE
EXISTS (SELECT 1 FROM dbo.InLike(x.val,'016%, %888%'))
Another option would be to put the search values in a table and build a dynamic SQL to do the work. It is not recommended but sometimes helps...