SELECT DATEPARTdayofyear, CURRENT_TIMESTAMP AS DayCount;Result: DayCount ---321 SELECT DATEPARTweekday, CURRENT_TIMESTAMP AS DayWeek; Result: DayWeek ---7 An easy way to obtain just th
Trang 1SELECT LastName, DATENAME(yy,DateOfBirth) AS [Year], DATENAME(mm,DateOfBirth) AS [Month], DATENAME(dd,DateOfBirth) AS [Day], DATENAME(weekday, DateOfBirth) AS BirthDay FROM dbo.Guide
WHERE DateOfBirth IS NOT NULL;
- - - -
TABLE 9-2
DateTime Portions Used by Date Functions
There are two supported types: DateTime and DateTime2 DateTime2 is new to SQL Server 2008 and represents time to a much finer granularity: within 100 nanoseconds.
■ DatePart(date portion,date): Returns the ordinal number of the selected portion of the datetime value The following example retrieves the day of the year and the day of the week as integers:
Trang 2SELECT DATEPART(dayofyear, CURRENT_TIMESTAMP) AS DayCount;
Result:
DayCount
-321
SELECT DATEPART(weekday, CURRENT_TIMESTAMP) AS DayWeek;
Result:
DayWeek
-7
An easy way to obtain just the date, stripping off the time, is to use a couple of string
functions:
SELECT CONVERT(char(10), CURRENT_TIMESTAMP, 112) AS "DateTime";
■ DateAdd(DATE PORTION,AMOUNT,BEGINNING DATE)andDateDiff(DATE PORTION,
BEGINNING DATE,ENDING DATE): Performs addition and subtraction on datetime data,
which databases often need to do TheDATEDIFF()and theDATEADD()functions are
designed expressly for this purpose TheDATEDIFF()doesn’t look at the complete date, only
the date part being extracted:
select DATEDIFF(year,’september 4 2008’,’november 10 2009’)
Result
1
select DATEDIFF(month,’september 4 2008’,’november 10 2009’)
2
The following query calculates the number of years and days that my wife, Melissa, and I have been
married:
SELECT
DATEDIFF(yy,’19840520’, CURRENT_TIMESTAMP) AS MarriedYears,
DATEDIFF(dd,’19840520’, CURRENT_TIMESTAMP) AS MarriedDays;
Result:
MarriedYears MarriedDays
-
The next query adds 100 hours to the current millisecond:
SELECT DATEADD(hh,100, CURRENT_TIMESTAMP) AS [100HoursFromNow];
Result:
100HoursFromNow
-2009-11-21 18:42:03.507
The following query is based on theFamilysample database and calculates the mother’s age at the
birth of each child, using theDateDiff()function:
Trang 3USE Family;
SELECT Person.FirstName + ‘ ‘ + Person.LastName AS Mother, DATEDIFF(yy, Person.DateOfBirth,
Child.DateOfBirth) AS AgeDiff,Child.FirstName FROM Person
INNER JOIN Person AS Child
ON Person.PersonID = Child.MotherID ORDER By Age DESC;
TheDATEDIFF()function in this query returns the year difference betweenPERSON.DATEOFBIRTH,
which is the mother’s birth date, and the child’s date of birth Because the function is in a column
expression, it is calculated for each row in the result set:
- - -Audrey Halloway 33 Corwin
Elizabeth Campbell 31 Alexia Melanie Campbell 30 Adam
This section discusses functions that are new to SQL Server 2008 You will take a look at the functions
and then see the results of some queries
ToDateTimeOffset(expression,time_zone): Returns aDateTimeOffsetvalue
The following example gets the date and time for a given time zone:
SELECT TODATETIMEOFFSET(CURRENT_TIMESTAMP,’-07:00’);
Result:
2009-11-05 11:24:15.490 -07:00
String Functions
Like most modern programming languages, T-SQL includes many string-manipulation functions:
■ SUBSTRING(string, starting position,length): Returns a portion of a string The first parameter is the string, the second parameter is the beginning position of the substring to
be extracted, and the third parameter is the length of the string extracted:
SELECT SUBSTRING(’abcdefg’, 3, 2);
Result:
cd
Trang 4■ STUFF(string,insertion position,delete count,string inserted): The
STUFF()function inserts one string into another string The inserted string may delete a
specified number of characters as it is being inserted:
SELECT STUFF(’abcdefg’, 3, 2, ‘123’);
Result:
ab123efg
The following code sample uses nestedSTUFF()functions to format a U.S social security
number:
SELECT STUFF(STUFF(’123456789’, 4, 0, ‘-’), 7, 0, ‘-’);
Result:
123-45-6789
■ CHARINDEX(search string,string,starting position): Returns the character
position of a string within a string The third argument is optional and rarely used in practice
It defaults to 1
SELECT CHARINDEX(’c’, ‘abcdefg’, 1);
Result:
3
The user-defined functiondbo.pTitleCase()later in this section usesCHARINDEX()to
locate the spaces separating words
■ PATINDEX(pattern,string): Searches for a pattern, which may include wildcards, within
a string The following code locates the first position of either acor adin the string:
SELECT PATINDEX(’%[cd]%’, ‘abdcdefg’);
Result:
3
■ RIGHT(string,count)andLeft(string,count): Returns the rightmost or leftmost
part of a string:
SELECT LEFT(’Nielsen’,2) AS ‘ [Left] ‘,
RIGHT(’Nielsen’,2) AS [Right];
Result:
Left Right
-
Trang 5■ LEN(string): Returns the length of a string:
SELECT LEN(’Supercalifragilisticexpialidocious’) AS [Len];
Result:
Len -34
■ RTRIM(string)andLTrim(string): Removes leading or trailing spaces While it’s difficult to see in print, the three leading and trailing spaces are removed from the fol-lowing string They are often used together asRTRIM(LTRIM(string) I adjusted the column-header lines with the remaining spaces to illustrate the functions:
SELECT RTRIM(’ middle earth ‘) AS [RTrim], LTRIM(’ middle earth ‘) AS [LTrim];
Result:
- -middle earth middle earth
■ UPPER(string)andLower(string): Converts the entire string to uppercase or lowercase
There’s not much to know about these two functions, illustrated here:
SELECT UPPER(’one TWO tHrEe’) AS UpperCase, LOWER(’one TWO tHrEe’) AS LowerCase;
Result:
- -ONE TWO THREE one two three
■ REPLACE(string,string): TheReplace()function operates as a global search and replace within a string UsingREPLACE()within an update DML command can quickly fix problems in the data, such as removing extra tabs or correcting string patterns The follow-ing code sample adds apostrophes to theLastNamecolumn in theOBXKITESdatabase’s
CONTACTtable:
USE OBXKites;
Create test case by modifying one contact’s last name
UPDATE Contact SET LastName = ‘Adam’’s’
WHERE LastName = ‘Adams’;
Check the modified sample data and the replacement
SELECT LastName, REPLACE(LastName, ‘’’’, ‘’) AS Replaced
FROM Contact WHERE LastName LIKE ‘%’’%’;
Trang 6LastName Replaced
-
-Adam’s Adams
To demonstrate theREPLACE()function using an update command, the next query actually changes
the data in place and removes any apostrophes:
UPDATE Contact
SET LastName = REPLACE(LastName, ‘’’’, ‘’)
WHERE LastName LIKE ‘%’’%’;
Show that the modification was successful
SELECT LastName
FROM Contact
WHERE LastName LIKE ‘Adam%’;
Result:
LastName
-Adams
When working with string literals, it’s generally difficult to insert a quote into the string
without ending the string and causing a syntax error SQL Server handles this situation by
accepting two single quotes and converting them into one single quote within the string:
’Life’’s Great! ‘ is interpreted as Life’s Great!
■ dbo.pTitleCase(source,search,replace): T-SQL lacks a function to convert text to
title case (first letter of each word in uppercase, and the remainder in lowercase) Therefore,
the following user-defined function accomplishes that task:
CREATE FUNCTION dbo.pTitleCase (
@StrIn NVARCHAR(MAX))
RETURNS NVARCHAR(MAX)
AS
BEGIN;
DECLARE
@StrOut NVARCHAR(MAX),
@CurrentPosition INT,
@NextSpace INT,
@CurrentWord NVARCHAR(MAX),
@StrLen INT,
@LastWord BIT;
SET @NextSpace = 1;
SET @CurrentPosition = 1;
Trang 7SET @StrOut = ‘’;
SET @StrLen = LEN(@StrIn);
SET @LastWord = 0;
WHILE @LastWord = 0 BEGIN;
SET @NextSpace = CHARINDEX(’ ‘, @StrIn, @CurrentPosition + 1);
IF @NextSpace = 0 no more spaces found BEGIN;
SET @NextSpace = @StrLen;
SET @LastWord = 1;
END;
SET @CurrentWord = UPPER(SUBSTRING(@StrIn, @CurrentPosition, 1));
SET @CurrentWord = @CurrentWord + LOWER(SUBSTRING(@StrIn, @CurrentPosition+1,
@NextSpace - @CurrentPosition));
SET @StrOut = @StrOut + @CurrentWord;
SET @CurrentPosition = @NextSpace + 1;
END;
RETURN @StrOut;
END;
Running a user-defined function requires including the owner name in the function name:
SELECT dbo.pTitleCase(’one TWO tHrEe’) AS TitleCase;
Result:
TitleCase -One Two Three
The dbo.pTitleCase function does not take into consideration surnames with nonstandard capitalization, such as McDonald, VanCamp, or de Jonge It would be inadequate to hard-code a list of exceptions Perhaps the best solution is to store a list of exception phrases (Mc, Van, de,
and so on) in an easily updateable list.
The code for the pTitleCase user-defined function can be downloaded from www.SQLServerBible.com
Soundex Functions
Soundex is a phonetic pattern-matching system created for the American census Franklin Roosevelt
directed the United States Bureau of Archives to develop a method of cataloguing the population that
could handle variations in the spelling of similar surnames Margaret K Odell and Robert C Russell
developed Soundex and were awarded U.S patents 1261167 (1918) and 1435663 (1922) for their
efforts The census filing card for each household was then filed under the Soundex method Soundex
has been applied to every census since and has been post-applied to census records back to 1880
Trang 8The purpose of Soundex is to sort similar-sounding names together, which is very useful for dealing
with contact information in a database application For example, if I call a phone bank and give them
my name (Nielsen), they invariably spell it ‘‘Nelson’’ in the contact lookup form, but if the database uses
Soundex properly, then I’ll still be in the search-result list box
For more information concerning Soundex and its history, refer to the following websites:
■ www.nara.gov/genealogy/coding.html
■ www.amberskyline.com/treasuremaps/uscensus.html
■ www.bluepoof.com/soundex/
Here’s how Soundex works The first letter of a name is stored as the letter, and the following Soundex
phonetic sounds are stored according to the following code:
1= B, F, P, V
2= C, G, J, K, Q, S, X, Z
3= D, T
4= L
5= M, N
6= R
Double letters with the same Soundex code, A, E, I, O, U, H, W, Y, and some prefixes, are disregarded
Therefore, ‘‘Nielsen’’ becomes ‘‘N425’’ via the following method:
1 The N is stored.
2 The i and e are disregarded.
3 The l sound is stored as the Soundex code 4.
4 The s is stored as the Soundex code 2.
5 The e is ignored.
6 The n is stored as the Soundex code 5.
By boiling them down to a few consonant sounds, Soundex assigns ‘‘Nielsen,’’ ‘‘Nelson,’’ and ‘‘Neilson’’
the same code: N425
Following are additional Soundex name examples:
■ Brown = B650 (r = 6, n = 5)
■ Jeffers = J162 (ff = 1, r = 6, s = 2)
■ Letterman = L365 (tt = 3, r = 6, m = 5)
■ Nicholson = N242 (c = 2, l = 4, s = 2)
■ Nickols = N242 (c = 2, l = 4, s = 2)
SQL Server includes two Soundex-related functions,SOUNDEX()andDIFFERENCE()
Trang 9Using the SOUNDEX() function
TheSOUNDEX(string)function calculates the Soundex code for a string as follows:
SELECT SOUNDEX(’Nielsen’) AS Nielsen, SOUNDEX(’Nelson’) AS NELSON,
SOUNDEX(’Neilson’) AS NEILSON;
Result:
Nielsen NELSON NEILSON - -
Other, more refined, Soundex methods exist Ken Henderson, in his book The Guru’s Guide
to Transact SQL (Addison-Wesley, 2000), provides an improved Soundex algorithm and stored procedure If you are going to implement Soundex in a production application, I recommend
exploring his version Alternately, you can research one of the other refined Soundex methods on the
websites listed previously and write your own custom stored procedure.
There are two possible ways to add Soundex searches to a database The simplest method is to add the
SOUNDEX()function within theWHEREclause, as follows:
USE CHA2;
SELECT LastName, FirstName FROM dbo.Customer
WHERE SOUNDEX(’Nikolsen’) = SOUNDEX(LastName);
Result:
LastName FirstName - -Nicholson Charles
While this implementation has the smallest impact on the data schema, it will cause performance issues
as the data size grows because theSOUNDEX()function must execute for every row in the database,
and an index on the name column (if any) cannot be used with an efficient seek operation, but only
with a much more expensive scan A faster variation of this first implementation method pre-tests for
names with the same first letter, thus enabling SQL Server to use any indexes to narrow the search, so
fewer rows must be read and theSOUNDEX()function must be performed only for rows selected by
the index:
SELECT LastName, FirstName FROM dbo.Customer
WHERE SOUNDEX(’Nikolsen’) = SOUNDEX(LastName) AND LastName LIKE ‘N%’;
The first query executes in 37.7 milliseconds on my test server, while the improved second query
exe-cutes in 6.5 milliseconds I suspect that the performance difference would increase with more data
Trang 10The second implementation method is to write the Soundex value in a column and index it with a
non-clustered index Because the Soundex value for each row is calculated during the write, theSOUNDEX()
function does not need to be called for every row read by theSELECTstatement This is the method I
recommend for a database application that heavily depends on Soundex for contact searches
TheOBXKITESsample database demonstrates this method TheSoundexCodecolumn is persisted
cal-culated column, so it’s automatically calcal-culated for every insert and kept updated with every update
Searching for a row, or all the matching rows, based on the stored Soundex code is extremely fast
First determine the Soundex for ‘‘Smith’’:
USE OBXKites;
SELECT SOUNDEX(’Smith’);
Result:
-S530
Knowing the Soundex value for ‘‘Smith,’’ the Soundex search is now a fast index seek without ever
call-ing theSOUNDEX()function for the row being read during the select statement:
SELECT LastName, FirstName, SoundexCode
FROM Contact
WHERE SoundexCode = ‘S530’;
Result:
LastName FirstName SoundexCode
- -
Using the DIFFERENCE() Soundex function
The second SQL Server Soundex function,DIFFERENCE(), returns the Soundex difference between two
strings in the form of a ranking from 1 to 4, with 4 representing a perfect Soundex match:
USE CHA2
SELECT LastName, DIFFERENCE(’Smith’, LastName) AS NameSearch
FROM Customer
ORDER BY Difference(’Smith’, LastName) DESC;
Result:
LastName NameSearch