Jeffery 的个人资料http://www.facebook.com/...照片日志列表更多 ![]() | 帮助 |
|
|
7月29日 Why doesn't SQL Server allow me to separate DATE and TIME?Admittedly, this is one of the rare features that Access boasts over SQL Server. The ANSI-92 standard states that compliant database should support the following DATE/TIME datatypes: DATE + TIME DATE TIME Unfortunately, SQL Server only supports the first type of column, with the DATETIME (sub-millisecond accuracy) and SMALLDATETIME (minute accuracy) datatypes. If you only insert partial information (such as '10/31/2001' or '3:25 PM'), SQL Server will fill in the rest for you. Try the following script, to see what I mean: SET NOCOUNT ON CREATE TABLE #foo ( dt DATETIME ) GO INSERT #foo(dt) VALUES('20011031') INSERT #foo(dt) VALUES('3:25 PM') SELECT dt FROM #foo DROP TABLE #foo GO Here are the results: dt ----------------------- 2001-10-31 00:00:00.000 1900-01-01 15:25:00.000 Notice that SQL Server inserts midnight when time information is missing, and 1900-01-01 when date information is missing. So what do you do when you're only interested in one or the other? There are several camps on this one. One is to store the date and/or time information as a CHAR or VARCHAR column. This makes comparisons and sorting very difficult. Another camp suggests storing the extraneous information and ignoring it. Often "ignoring" means "converting", so to get just the date or time from the above table, you would do this: SELECT dateonly = CONVERT(CHAR(8),dt,112) FROM #foo SELECT timeonly = CONVERT(CHAR(8),dt,8) FROM #foo Results: dateonly -------- 20011031 19000101 timeonly -------- 00:00:00 15:25:00 Unfortunately, this type of conversion will not take advantage of any index on the DATETIME column. A similar approach is to store a standard value for the part you're not interested in, and handle that part of the data at the application level. Another way to store only time, and do so efficiently, is to use an integer column. You multiply the number of hours by 100, and add the minutes. For example: SET NOCOUNT ON CREATE TABLE #foo ( tm SMALLINT ) INSERT #foo VALUES ( -- e.g. 1527 = 3:27 PM / 15:27 100 * DATEPART(HOUR, GETDATE()) + DATEPART(MINUTE,GETDATE()) ) SELECT tm FROM #foo DROP TABLE #foo You multiply the hours by 100, then add the minutes, thus getting the time in military format. You could leave the formatting up to the application, or retrieve a nicely formatted time by running this query against #foo (I think this would be prettier in an application that's not so strongly typed): SELECT timeonly = CAST( LEFT(tm, LEN(tm)-2) + ':' + RIGHT(tm, 2) AS VARCHAR(5) ) FROM #foo Results: timeonly -------- 1:17 Similarly, to store only date as an integer, you multiply the year by 10000, add the month (multiplied by 100), and then add the day: SET NOCOUNT ON CREATE TABLE #foo ( dt INT ) INSERT #foo VALUES ( DATEPART(YEAR, GETDATE()) * 10000 + DATEPART(MONTH, GETDATE()) * 100 + DATEPART(DAY, GETDATE()) ) SELECT dt FROM #foo DROP TABLE #foo Getting this one into date format is about as pretty as the previous example: SELECT CONVERT ( CHAR(8), CONVERT ( DATETIME, CONVERT ( CHAR(8), dt ), 112 ) ) FROM #foo Results: dateonly ---------- 20011031 7月27日 Want a great Streaming Music ProgramI found this great program that puts together a custom internet radio station for you.
Check out www.pandora.com
This program will take a single request of an artist or song and create an entire radio station of music that you will love, from various artists; some of which you probably never heard of. 7月26日 SQL Tips, tricks, AdviseI am a SQL server architect and programmer. I enjoy discovering new methods and approaches to everyday problems in using SQL Server. If anyone requires assistance, advise, or simply would like to know how to deal with or approach a problem please let me know. I would be happy to assist and publish these methods here on my blog. I can cover anything related to SQL server 2000, 2005 and I am presently playing with MS SQL 2008. 7月22日 Ever need to use a time dimension within SQL server?I wrote this code to determine if a given time / date fell within the scope of a set period. This was used in a scheduling system to determine availability of a desired appointment time. After searching the net I was unable to find pre-constructed code. Being that the time / date format in SQL server can be a real pain to work with I thought I would publish my work for the benefit of others.
The following code will provide an accurate time dimension.
/*************************************** Note: This script does hours and minutes. If seconds are needed, Author: Jeffery Williams You May need to use a dimention to calculate if a scheudule rides into a ****************************************/ if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[dimHour]') and OBJECTPROPERTY(id, N'IsUserTable') = 1) CREATE TABLE dimHour DECLARE @startdate DATETIME SET @startdate = '1/1/2005 12:00:00 AM' WHILE @date <= @enddate SET @date = DATEADD(mi, 1, @date) -- ** Modify the datepart to ss if seconds are needed END 7月19日 Deal with NULLs and Uniqueness in Microsoft SQL ServerHow do you apply uniqueness to only non-NULL values? Find out the answer here. As an example lets say you have a field in a table that requires a unique constraint. In this row however you have some records with a NULL value. With SQL server you can not directly apply a unique constraint the this row because of the NULL records that exist.
This particular issue of uniqueness around NULLs is somewhat controversial within the SQL community. Because NULL = NULL is false, how can two NULLs not be unique? In the case of SQL Server, as you've discovered, two NULLs are not considered unique, but in other databases, notably Oracle, they are. Be that as it may, there are a couple of ways to deal with this problem. I'll show you both. Just to set the stage clearly for the problem, here's a table: CREATE TABLE Employee ( CREATE UNIQUE INDEX IDX_Employee_SSN Notice that I've created a unique index on the SSN. So now insert some rows: INSERT INTO Employee (LastName, FirstName, SSN) INSERT INTO Employee (LastName, FirstName, SSN) The second insert fails because the second null SSN violates the uniqueness constraint. The first solution I have to this is to use a view to get rid of the nulls, and then index the view. So the first step is to remove the unique index I created earlier, then create a view and put a unique index on the view: DROP INDEX IDX_Employee_SSN ON dbo.Employee; CREATE VIEW Employee_SSN_NOT_NULL CREATE UNIQUE CLUSTERED INDEX Employee_SSN_Unique Notice the view I've created has the "WITH SCHEMABINDING" clause on it, which tells SQL Server that the underlying table cannot be modified in a way that affects the view without first dropping the view. SQL Server requires that constraint so I can execute the final statement of the three, adding an index to the view. And it's that index that provides the uniqueness constraint, but only on the rows in Employee that have an SSN. This is a somewhat elaborate way to address the issue, but it certainly works. Some folks don't like it because they use views for other things and don't want views for uniqueness cluttering up their schema. There is a simpler, somewhat "hackier" way to work around the problem, using a thing called the "nullbuster" as coined by Steve Kass. The simplest way to understand the nullbuster in action is to look at the code: CREATE TABLE Employee ( CREATE UNIQUE INDEX IDX_Employee_SSN So once again I've created the Employee table and added an index with a unique constraint on it. The difference is the nullbusterSSN column. The nullbusterSSN column is a derived column that uses a CASE statement to check to see if SSN is NULL. If it is, nullbusterSSN contains the EmployeeID. If SSN is not NULL, then nullbusterSSN contains 0. The unique index I created is a composite index containing both SSN and nullbusterSSN. The result is that you can have as many NULL SSNs as you like and the unique constraint won't fire, but as soon as you try and write two rows with the same non-NULL SSN, you'll hit the uniqueness constraint. So now instead of having an extra view in the database schema, I have an extra column in the table. This might annoy you even more; it's very much a personal choice. Both approaches work equally well. Choose whichever one you prefer. We could build a more elaborate schema that had a separate table for SSNs and dealt with uniqueness that way, but I find that even more complicated and fraught with peril. As soon as you introduce another table, you run the risk that an employee has more than one SSN assigned to them. I'd prefer either one of these hacks to that. |
|
|