IT Community - Software Programming, Web Development and Technical Support

Phone Numbers in SQL Server – Formatting

This is a discussion on Phone Numbers in SQL Server – Formatting within the Database Support forums, part of the Web Development category; Introduction I discussed various ways of persisting a simple telephone number in SQL Server. Simply displaying the raw data stored ...


Go Back   IT Community - Software Programming, Web Development and Technical Support > Web Development > Database Support

Register FAQ Members List Calendar Mark Forums Read
  #1 (permalink)  
Old 09-21-2007, 01:43 PM
Sundaram Sundaram is offline
D-Web Sr.Programmer
 
Join Date: Mar 2007
Location: chennai
Posts: 117
Sundaram is on a distinguished road
Send a message via MSN to Sundaram Send a message via Yahoo to Sundaram
Default Phone Numbers in SQL Server – Formatting

Introduction

I discussed various ways of persisting a simple telephone number in SQL Server. Simply displaying the raw data stored in SQL Server would not be suitable for human consumption so some form of data formatting must be done. Data formatting is usually performed in the user interface layer, for example by the ASPX page or the Winforms application. Often it is convenient to have SQL Server format the data in a view to be passed into another document like a report that might have a difficult time formatting the number correctly. In this article, I will discuss a couple methods that can be used to format the number for presentation to the user on SQL Server.

The UDF

SQL Server 2000 introduced the ability to create User Defined Functions, Using a custom formatting function for telephone numbers is perfect example of where to use UDF's. The code below can be used to create a telephone number formatting function in TSQL.

Quote:
-- =============================================
-- Author: Sundaram
-- Create date: Sept 22, 2007
-- Description: Formats a telephone number to North American Numbering Plan standard
-- =============================================
CREATE FUNCTION [dbo].[FORMATPHONENUMBER]
(
@Number money
)
RETURNS varchar(25)
AS
BEGIN

-- Declare the return variable here
DECLARE @Formatted varchar(25) -- Formatted number to return
DECLARE @CharNum varchar(18) -- Character type of phone number
DECLARE @Extension int -- Phone extesion
DECLARE @Numerator bigint -- Working number variable

IF @Number IS NULL
BEGIN
--Just return NULL if input string is NULL
RETURN NULL
END

-- Just enough room, since max phone number digits is 14 + 4 for extension is 18
SET @Numerator = CAST(@Number * 10000 AS bigint) -- Get rid of the decimal
SET @Extension = CAST(RIGHT(@Numerator, 4) AS int) -- Cast to int to strip off leading zeros
SET @CharNum = CAST(LEFT(@Numerator , LEN(@Numerator) - 4) AS varchar(18)) -- Strip off the extension

IF LEN(@CharNum) = 10 -- Full phone number, return (905) 555-1212
BEGIN

SET @Formatted = '(' + LEFT(@CharNum, 3) + ') ' + SUBSTRING(@CharNum,4,3) + '-' + RIGHT(@CharNum, 4)

IF @Extension > 0 -- Add Extension
BEGIN
SET @Formatted = @Formatted + ' ext '+ CAST(@Extension AS varchar(4))
END

RETURN @Formatted
END

IF LEN(@CharNum) = 7 -- No Area Code, return 555-1212
BEGIN
SET @Formatted = LEFT(@CharNum, 3) + '-' + RIGHT(@CharNum, 4)
IF @Extension > 0 -- Add Extension
BEGIN
SET @Formatted = @Formatted + ' ext '+ CAST(@Extension AS varchar(6))
END

RETURN @Formatted
END

IF LEN(@CharNum) = 11 -- Full phone number with access code, return 1 (905) 555-1212 (19055551212)
BEGIN

SET @Formatted = LEFT(@CharNum, 1) + ' (' + SUBSTRING(@CharNum, 2, 3) + ') ' + SUBSTRING(@CharNum,4,3) + '-' + RIGHT(@CharNum, 4)

IF @Extension > 0 -- Add Extension
BEGIN
SET @Formatted = @Formatted + ' ext '+ CAST(@Extension AS varchar(4))
END

RETURN @Formatted
END


-- Last case, just return the number unformatted (unhandled format)
SET @Formatted = @CharNum
IF @Extension > 0 -- Just the Extension
BEGIN
SET @Formatted = @Formatted + ' ext '+ CAST(@Extension AS varchar(4))
RETURN 'ext '+ CAST(@Extension AS varchar(4))

END

RETURN @Formatted

END
The CLR Version

SQL Server 2005 added the ability to write your own DLL's in the .NET programming language of your choice, so I also wrote the equivalent function in C#. To do this in Visual Studio 2005, start a new SQL Server project, and add a new User-Defined Function. Paste this code into it.

Quote:
using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.Text.RegularExpressions;

public partial class UserDefinedFunctions
{
[Microsoft.SqlServer.Server.SqlFunction(IsDetermini stic=true, IsPrecise=true)]
public static SqlString FormatNAPhoneNumber(SqlMoney Number)
{
// Return Null if number is null
if (Number.IsNull)
return SqlString.Null;

string phoneNumber = Number.ToString();
string [] phone = phoneNumber.Split(new Char [] {'.'});
string charnum = phoneNumber; //Default to unformatted number

int extension = int.Parse(phone[1]);

switch (phone[0].Length)
{
case 10: //Format standard North American phone number '(416) 555-1212' or '(415) 555-1212 ext1234'
{

if (extension > 0)
{
charnum = string.Format("({0}) {1}-{2} ext{3}",
phone[0].Substring(0, 3),
phone[0].Substring(3, 3),
phone[0].Substring(6),
extension.ToString());

// charnum = Regex.Replace(phone[0], @"(\d{3})(\d{3})(\d{4})", "($1) $2-$3"); //Test Regex performance
// charnum = "(" + phone[0].Substring(0, 3) + ") " + phone[0].Substring(3, 3) + //Test standard string concat
// phone[0].Substring(6) + " ext" + extension.ToString();

return new SqlString(charnum);
}
else
{
charnum = string.Format("({0}) {1}-{2}",
phone[0].Substring(0, 3),
phone[0].Substring(3, 3),
phone[0].Substring(6));

// charnum = Regex.Replace(phone[0], @"(\d{3})(\d{3})(\d{4})", "($1) $2-$3");
// charnum = "(" + phone[0].Substring(0, 3) + ") " + phone[0].Substring(3, 3) + phone[0].Substring(6);
return new SqlString(charnum);

}
break;
}
case 7: // Format without the area code '555-1212' or '555-1212 ext1234'
{
if (extension > 0)
{
charnum = string.Format("{0}-{1} ext{2}",
phone[0].Substring(0, 3),
phone[0].Substring(3),
extension.ToString());
return new SqlString(charnum);
break;
}
else
{
charnum = string.Format("{0}-{1}",
phone[0].Substring(0, 3),
phone[0].Substring(3));
return new SqlString(charnum);
break;
}
}
case 11: // Format with dialing prefix '1 (416) 555-1212' or '1 (416) 555-1212 ext1234'
{
// return new SqlString(phone[0] + " and " + phone[1]);
if (extension > 0)
{
charnum = string.Format("{0} ({1}) {2}-{3} ext{4}",
phone[0].Substring(0, 1),
phone[0].Substring(1, 3),
phone[0].Substring(4, 3),
phone[0].Substring(7),
extension.ToString());
return new SqlString(charnum);
}
else
{
charnum = string.Format("{0} ({1}) {2}-{3}",
phone[0].Substring(0, 1),
phone[0].Substring(1, 3),
phone[0].Substring(4, 3),
phone[0].Substring(7));
return new SqlString(charnum);
}
}
default: //Just return the number as a string, no formatting
{
return new SqlString(charnum);
break;
}
}
}
}
I did some quick benchmarking to see how it affected performance against a simple table containing the phone number datatype. The table contains a small set of 580 rows and the SQL SELECT command was executed 1,000 times, which generated 580,000 calls to the function. The SELECT command was executed without bringing the dataset back to client so that the network time was minimized. Execution times are in milliseconds. Your numbers may vary, but use these numbers as a relative comparison of the different methods.

The Suprise!


To my surprise, the .NET function call ran twice as fast as the native TSQL function! My first guess would be that the native TSQL functions would certainly run faster by eliminating the overhead of the .NET engine and interface. It seems Microsoft has done their homework on .NET integration. This is another good example of where testing shows results that are often counter to what you would expect.

The C# version also has various lines commented out if you choose to use the RegEx library or the simple string concatenate operator for formatting the telephone number. One way to handle international phone numbers would be to store the RegEx pattern and evaluator strings in a table keyed by country. This table could then be linked to the phone number and the appropriate formatting codes passed to the function. I didn't go this far with the design, but I did try using the RegEx method of formatting to test the performance over the using the String.Format method. As you can see it performed about the same as the TSQL version, so the overhead of the RegEx object was significant.

Conclusion

Using TSQL to write user defined functions can be awkward if it requires a fair amount of string manipulation or complicated logic. Using the .NET CLR integration allows you to easily use the full power of the .Net library and probably get better performance than with TSQL.

In my first article, it was stated that the small details make all the difference. By paying attention to proper design and doing a little bit of testing, we have cut the data footprint of storing a phone number in half as well as cutting the CPU requirements for formatting the number in half. Small changes like these can make all the difference when it comes to how well your applications can scale.
Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
Sponsored Links
Reply


Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On


Similar Threads
Thread Thread Starter Forum Replies Last Post
classic asp date formatting ramesh123 ASP and ASP.NET Programming 1 02-14-2008 08:13 PM
Better Formatting? Booom Discussweb HQ 2 02-10-2008 02:23 AM
Validating Numbers ragavraj PHP Programming 1 11-07-2007 07:12 AM
Add two numbers without using addition operator Murali C and C++ Programming 0 10-31-2007 08:15 AM
Greatest of Three Numbers Without Using Two Variable Murali C and C++ Programming 1 10-29-2007 10:50 PM


All times are GMT -7. The time now is 07:06 AM.


Copyright ©2004 - 2007, DiscussWeb. All Rights Reserved.

SEO by vBSEO 3.0.0