sql query to fix phone number problem in table - asp.net

I have a table which contains a phone number column. There is no restrictions on how to enter the phone numbers. Currently the phone numbers are in the following format
123-456-7890
(123)-456-7890
1234567890
I would like to update the table and bring all phone numbers in 123-456-7890 format. I have over 20k records. Can I do that using SQL Query or I have to use regular expression in ASP or PHP?
Edit: Note best answer is for modified question, with phone number (123)-456-78790 changed to (123)456-7890

If they are strictly in one of those 3 formats, you can do it in SQL easy enough by using SUBSTRING and testing the LEN of each item.
If there are other formats, I'd suggest doing this in a language that is better at text-manipulation, such as .net.
Edit to add:
Given your comment that it'll only be those 3 formats for now, you can do this:
declare #t table (x varchar(20))
insert into #t
select '123-456-7890'
union select '(123)456-7890'
union select '1234567890'
select
case
when len(x) = 10 then
substring(x, 1, 3) + '-' + substring(x, 4, 3) + '-' + substring(x, 7, 4)
when len(x) = 13 then
substring(x, 2, 3) + '-' + substring(x, 6, 8)
else x
end
from #t

This will work:
First replace the parentheses and hyphens, then add them back in.
DECLARE #Number varchar(25)
SELECT #Number = '(123)-456-7890'
SELECT SUBSTRING(REPLACE(REPLACE(REPLACE(#Number, '(', ''), ')', ''), '-', ''), 1, 3)
+ '-'
+ SUBSTRING(REPLACE(REPLACE(REPLACE(#Number, '(', ''), ')', ''), '-', ''), 4, 3)
+ '-'
+ SUBSTRING(REPLACE(REPLACE(REPLACE(#Number, '(', ''), ')', ''), '-', ''), 7, 4)
Note
You could create a scalar function to replace all the hyphens and parentheses... It would be more readable then:
DECLARE #Number varchar(25)
SELECT #Number = '(123)-456-7890'
SELECT SUBSTRING(StripCharacters(#Number), 1, 3)
+ '-'
+ SUBSTRING(StripCharacters(#Number), 4, 3)
+ '-'
+ SUBSTRING(StripCharacters(#Number), 7, 4)

Succinct and without temp tables:
UPDATE Phones
SET phone =
SUBSTRING(REPLACE(REPLACE(REPLACE(phone,'-',''),')',''),'(',''),1,3) + '-'
+ SUBSTRING(REPLACE(REPLACE(REPLACE(phone,'-',''),')',''),'(',''),4,3) + '-'
+ SUBSTRING(REPLACE(REPLACE(REPLACE(phone,'-',''),')',''),'(',''),7,4)

Here is a great example:
Shows how to create User Defined Functions, custom formatting function for telephone numbers in TSQL

I would load every phone number and strip them.
So remove all periods, commas, hyphens, - basically anything that isn't a number.
Then reinsert them in the format you're looking for.
you can do this through a query, or server side language.

If you only have 20K records then just go with whatever is easier for you. Personally, I would pull all the data and then reinsert it using a server side language. PHP, ASP, or SQL it doesn't really matter if this is a one time thing. Just be sure to set up some formatting restrictions on new inserts though.

Look at this quick example:
CREATE TABLE #temp
(
phonenumber VARCHAR(15)
)
INSERT INTO #temp
( phonenumber )
VALUES ( '555-578-5899'
INSERT INTO #temp
( phonenumber )
VALUES ( '(555)-896-3269' )
INSERT INTO #temp
( phonenumber )
VALUES ( '123-456-2129')
update #temp
set phonenumber=replace(phonenumber,'(','')
update #temp
set phonenumber=replace(phonenumber,')','')
update #temp
set phonenumber=replace(phonenumber,'-','')
-- That will eliminate all (,- and ) from the table
update #temp
set phonenumber=left(phonenumber,3)+'-'+substring(phonenumber,4,3)
+'-'+right(phonenumber,4)
SELECT * FROM #temp
DROP TABLE #temp

Related

Julia dataframe to database ODBC , not slow solution

I want to insert a Dataframe in a table using ODBC.jl , the table already exists and it seems that i can't use the function ODBC.load with it (even with the append=true).
usually i insert DataFrames with copyIn by loading the dataframe as a csv but with just ODBC it seems i can't do that .
The last thing i found is :
stmt = ODBC.prepare(dsn, "INSERT INTO cool_table VALUES(?, ?, ?)")
for row = 1:size(df, 1)
ODBC.execute!(stmt, [df[row, x] for x = 1:size(df, 2)])
end
but this is line by line , it's incredibly long to insert everything .
I tried also to do it myself like this :
_prepare_field(x::Any) = x
_prepare_field(x::Missing) = ""
_prepare_field(x::AbstractString) = string(''', x, ''')
row_names = join(string.(Tables.columnnames(table)), ",")
row_strings = imap(Tables.eachrow(table)) do row
join((_prepare_field(x) for x in row), ",") * "\n"
end
query = "INSERT INTO $tableName($row_names) VALUES $row_strings"
#debug "Inserting $(nrow(df)) in $tableName)"
DBInterface.execute(db.conn, query)
but it throw me an error because of some "," not at the right place at like col 9232123
which i can't find because i have too many lines , i guess it's the _prepare_field that doesn't cover all possible strings escape but i can't find another way .
Did i miss something and there is a easier way to do it ?
Thank you

How to Concatenate strings conditionally for display in SSRS

In SSRS, how could I create a field, similar to a "comments" field in a record that would list a set of strings, conditionally, depending on how a set of questions on a VB.NET web form are answered?
Say, 5 questions have RadioButtonLists with "Y", "N", and "N/A" as the three answer items. The answers go into a SQL (Server 2008R2) table as a "Review" record.
Question #2 and #4 are answered "N", the rest are answered "Y" or "N/A."
I'm trying to get that comments field in SSRS to be populated with similar to the following:
Q2: 1100 - No Documentation in file.
Q4: 4100 - No Case note.
In SQL I've tried declaring a variable to hold a string and concatenating question string values based on field contents. I tried nested IIF expressions in the SSRS column, but I can't figure out how to do what you can do in C# or VB like string1 = string1 + string2 or string1 += string2, in order to selectively add the strings to a variable to then display.
I need an SSRS report for each of the forms and each record needs that comments field listing the "Findings" or questions with "N" answers.
After your comments, I think I understand better. You want a comments column with the No values concatenated together with line breaks. You will have to adjust the below to match your tables but hopefully this helps.
select [AssignedOneActivity],
Comments = STUFF( (
SELECT char(10) + char(13) + a2.[AssignedOneActivity] + ': ' + a2.answer
FROM dbo.[WIA_Youth] a2
where a.ReviewID = a2.ReviewID
FOR XML PATH(''), TYPE
).value('.', 'nvarchar(max)'), 1, 2, ''
)
from dbo.[WIA_Youth] a
However, I now read that your storing your Q+A in columns. so maybe this would be better:
select
reviewid,
Comments =
case when [AssignedOneActivity] = 'N' then 'Q1: No answers' + char(10) + char(13) else '' end +
case when [AssignedTwoActivity] = 'N' then 'Q2: No answers' + char(10) + char(13) else '' end +
case when [AssignedThreeActivity] = 'N' then 'Q3: No answers' + char(10) + char(13) else '' end
from dbo.wia_youth

Change phone number format

I have phone number field in database. It has already data.
I want to change my phone number format to "XXX-XXX-XXXX"
Current database has no any phone format.
So there may be garbage data. I have already applied validation for new records but now I want to change my existing data also.
Is there any specific way through that I can change my existing data. And make all phone numbers to follow this format.
Please advice.
Create function to remove the non-numeric data and do the formatting
CREATE FUNCTION [UDF_STRIP_NONNUMERIC_DATA](#str VARCHAR(8000))
RETURNS VARCHAR(8000)
AS
BEGIN
WHILE Patindex('%[^0-9]%', #str) > 0
BEGIN
SET #str = Stuff(#str, Patindex('%[^0-9]%', #str), 1, '')
END
RETURN #str
END
You can use STUFF function to inset the - between phone number
Select left(Stuff(Stuff(dbo.[UDF_STRIP_NONNUMERIC_DATA](Phone),4,0,'-'),8,0,'-'),12)
From yourtable
If you are using SQL SERVER 2012+ use can use FORMAT function (thanks to LukStorms, who mentioned it in comment)
SELECT Format(Cast(dbo.[Udf_strip_nonnumeric_data](Phone) AS BIGINT), '###-###-####')
FROM yourtable
To update
Update yourtable
SET phone = left(Stuff(Stuff(dbo.[UDF_STRIP_NONNUMERIC_DATA](Phone),4,0,'-'),8,0,'-'),12)
Demo
declare #str varchar(100)= '9225-123-4567'
select left(Stuff(Stuff(dbo.[UDF_STRIP_NONNUMERIC_DATA](#str),4,0,'-'),8,0,'-'),12)
Result : 922-512-3456
declare #phone varchar(24)
set #phone = '(334)789-4532'
--set #phone = '314789-4532'
--set #phone = '3457894532'
--set #phone = '534-789-4532'
SELECT
LEFT(N,3) + '-' + SUBSTRING(N,4,3) + '-' + RIGHT(N,4)
FROM
(SELECT CAST(CAST((
SELECT SUBSTRING(#phone, Number, 1)
FROM master..spt_values
WHERE Type='p' AND Number <= LEN(#phone) AND
SUBSTRING(#phone, Number, 1) LIKE '[0-9]' FOR XML Path(''))
AS xml) AS varchar(MAX)) as N) as N
Ok, to replace all non-numeric characters, look at this.
Here is a sample script (copied from that link) to show you how it works (You'll need to modify this to fit your table name and column names:
-- Step 1: creates table to use to hold every char in every phone number
if object_id('dbo.tally') is not null drop table dbo.tally
select top 10000 --change to fit max length of phone number
identity(int,1,1) as n
into dbo.tally
from master.dbo.syscolumns sc1,
master.dbo.syscolumns sc2
-- add pk to maximize performance
alter table dbo.tally
add constraint pk_tally_n
primary key clustered (n) with fillfactor = 100
-- Step 2: Create temporary table holding three bad phone numbers
declare #phonetable table
(uniqueid int identity(1,1),
phone_number varchar(500))
insert into #phonetable (phone_number)
select '01234-567-890' union
select '012345 6789ext' union
select 'n/a' union select '...12345.....';
-- Step 3: identify, for every character, whether it is a number or not,
and remove the non-numeric ones
with cte (uniqueid, phone_number, goodchar, badchar) as
( select uniqueid, phone_number,
case when substring(phone_number,N,1) not like '%[^0-9]%'
then substring(phone_number,N,1) end as goodchar,
case when substring(phone_number,N,1) like '%[^0-9]%'
then substring(phone_number,N,1) end as badchar
from #phonetable , Tally
where phone_number like '%[^0-9]%' and N <= len(phone_number) )
select distinct phone_number,
isnull( stuff (
( SELECT '' + goodchar
FROM cte t1
where t1.UniqueID = t2.UniqueID
FOR XML PATH ( '' ) ) , 1 , 0 , '' ) ,'')
as clean_phone_number from cte t2
to display the numbers with formatting, just extract the appropriate pieces and re-concatenate them with the dashes.
Select case len(phone)
When 10 then left(phone, 3) + '-' +
substring(phone, 4,3) + '-' +
substring(phone, 7,4)`
When 7 then left(phone, 3) + '-' +
substring(phone, 4,4)
Else '' end
To create a computed column
Alter table Add Column FormattedPhone as
case len(phone)
When 10 then left(phone, 3) + '-' +
substring(phone, 4,3) + '-' +
substring(phone, 7,4)`
When 7 then left(phone, 3) + '-' +
substring(phone, 4,4)
Else '' end
If you don't mind a UDF
Select [dbo].[udf-Str-Format-Phone]('334)789-4532')
Returns
334-789-4532
The UDF
CREATE FUNCTION [dbo].[udf-Str-Format-Phone] (#S varchar(max))
Returns varchar(25)
AS
Begin
Declare #Return varchar(25)
;with cte0(N) As (Select 1 From (Values(1),(1),(1),(1),(1)) N(N))
, cteN(N) As (Select Top (Len(#S)) Row_Number() over (Order By (Select NULL)) From cte0 N1, cte0 N2)
, cteS(S) As (Select Substring(#S,N,1) From cteN Where Substring(#S, N, 1) LIKE '[0-9]' FOR XML Path(''))
Select #Return = IIf(Len(S)>=10,Stuff(stuff(S,4,0,'-'),8,0,'-'),Stuff(S,4,0,'-')) From cteS
Return #Return
End
-- Syntax : Select [dbo].[udf-Str-Format-Phone]('(334)789-4532') -- Returns 334-789-4532
-- Syntax : Select [dbo].[udf-Str-Format-Phone]('Phone:7894532') -- Returns 789-4532

How to remove an extra char which is coming in XMLAGG() output

Im using Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
We replaced LISTAGG() with XMLAGG() to avoid concatenation error.
when i check the lenght of charecters from both of the fuction output, XMLAGG() giving an extra char in length.
Could you please suggest me how can i overcome this issue.
Please find the below sql and out put
XMLAGG():
SELECT TO_CHAR (
SUBSTR (
XMLAGG (XMLELEMENT (e, table_name, CHR (13)).EXTRACT (
'//text()') ORDER BY tablespace_name).GetClobVal (),
1,
2000))
AS str_concate,
LENGTH (
TO_CHAR (
SUBSTR (
XMLAGG (XMLELEMENT (e, table_name, CHR (13)).EXTRACT (
'//text()') ORDER BY tablespace_name).GetClobVal (),
1,
2000)))
AS str_length
FROM all_tables
WHERE table_name = 'TEST_LOAD
OUTPUT:
STR_CONCATE STR_LENGTH
TEST_LOAD TEST_LOAD 26
LISTAGG()
SELECT LISTAGG (SUBSTR (table_name, 1, 2000), CHR (13))
WITHIN GROUP (ORDER BY tablespace_name)
AS str_concate,
LENGTH (
LISTAGG (SUBSTR (table_name, 1, 2000), CHR (13))
WITHIN GROUP (ORDER BY tablespace_name))
AS str_length
FROM all_tables
WHERE table_name = 'TEST_LOAD';
OUTPUT:
STR_CONCATE STR_LENGTH
TEST_LOAD TEST_LOAD 25
In case of XMLELEMENT, you actually create node of XML tree with two children: table_name and CHR(13). (May be it finally looks like single node since both are texts but it is not important.) It is expansion of value_expr nonterminal. The substantial thing is the node is not aware of other nodes and CHR(13) is added to every node as its suffix or, in other words, terminator.
In case of LISTAGG, you describe aggregation of multiple elements. In this case, your CHR(13) serves as delimiter (see syntax diagram) which is put between elements. It is separator rather than terminator.
Since XMLAGG does not suffer with 4000 char limit, I usually prefer XMLAGG.
If separator is needed, I recommend to prepend it before each value and cut first occurence using substr. Appending after is possible but makes expression harder.
substr(
xmlagg(
xmlelement(e, ', ' || table_name).extract('//text()')
order by tablespace_name
).getclobval(),
3 -- length(', ')+1
)

Split FirstName and LastName in sqlite

I have a table in sqlite db called [tblbook] with a column [authors]. What I am trying to do in the sql is to split the author values to firstname and the lastname and sort it on lastname. I did find this great code:
SELECT substr(BookAuthor, 1, NULLIF(CHARINDEX(' ', BookAuthor) - 1, -1)) AS [FirstName],
substr(BookAuthor, CHARINDEX(' ', BookAuthor) + 1, LEN(BookAuthor)) AS [LastName]
FROM tblBook where _id=3
It works perfectly on MSSQL but sqlite doesn't have the charindex function hence it fails.
Could anyone please be kind and advise me what should be the best approach to achieve this.
Another way (a little shorter) to write this would be
SELECT
substr(BookAuthor, 1, instr(BookAuthor, ' ') - 1) AS first_name,
substr(BookAuthor, instr(BookAuthor, ' ') + 1) AS last_name
FROM tblBook where id=3
ORDER BY last_name
This would apply for version 3.7.15 and beyond.
Unfortunately this functionality is missing from SQLite:
http://www.sqlite.org/lang_corefunc.html
Index of substring in SQLite3?
Maybe you can feed your custom string position function to SQLite using http://www.sqlite.org/c3ref/create_function.html
But if you really need it, there is a complex, ineffective workaround:
http://sqlfiddle.com/#!7/e03a4/3
1: create a numbers table/view
2: join authors to numbers table, and choose the MIN position of the space
3: now you can split the names
SELECT
substr( name, 1, pos-1) AS first_name,
substr( name, pos+1) AS last_name
FROM (
SELECT
author.name,
numbers.x AS pos
FROM author
INNER JOIN numbers
WHERE substr( author.name, numbers.x, 1) = ' '
GROUP BY author.name
) AS a
ORDER BY last_name;

Resources