INF: Creating a Four-Byte User-Defined DATE Data Type
ID: Q71441
|
The information in this article applies to:
-
Microsoft SQL Server for OS/2, version 4.2
-
Microsoft SQL Server version 4.2x
SUMMARY
Using the SQL Server DATETIME data type is one way to represent a date
in SQL Server. There are times, however, when it is necessary to store
the date without the time. In this case, it may be more efficient to
use an integer data type instead of the DATETIME data type, because
four of the eight bytes of storage used by DATETIME would be unused.
(Note: Current versions of Microsoft SQL Server do offer SMALLDATETIME;
however, the range of dates that can be represented is smaller and this
option may still be desired.)
The following example shows how to create a user-defined DATE datatype
as a 4 byte integer. The example consists of three steps: creating the
user-defined data type, creating a rule to validate the year, and
creating a trigger to validate the date. Note that there are two
different versions of the trigger.
MORE INFORMATION
The date is stored in a YYYYMMDD format directly into an integer. To
insert the date in different formats, create either a stored procedure
to convert the format to the storage format or convert the format to
the storage format within the C application. Note that the rule
validates the year and the integer is long enough to represent the
needed YYYYMMDD format.
The first trigger checks to see if the date inserted/updated is valid
by trying to convert the integer representation of the date to a
datetime datatype. If the conversion fails, everything is rolled
back, and the user is prompted with the following message:
The conversion from CHAR to DATETIME resulted in a DATETIME value
out of range
(MSG 242, LEVEL 16, STATE 0)
The second trigger validates the month and date, and gives more
control over the error messages by using RAISEERROR or PRINT to send
messages to the error and message handlers, respectively. Note
that for further optimization, you can place much of this trigger
in a stored procedure, allowing table(s) with multiple instances of
DATE data types to make use of one block of code.
======================================================================
/* Creates a 4 byte integer under the datetype data type */
SP_ADDTYPE datetype, int, null
go
/* Rule checks to see if the date being inserted is between */
/* the dates Jan 1, 1880 and Dec 31, 2099. These dates can */
/* be tailored to your needs */
CREATE RULE datetype_rule
AS @day between 18800101 and 20991231
go
/* binds the rule to the datatype */
SP_BINDRULE datetype_rule, datetype
go
/* Below is the first version of the validation trigger */
/* This trigger checks to validate the date. */
CREATE TRIGGER date_trigger
ON date_table
FOR insert, update
AS
SET arithignor on
declare @date datetime
/* Retrieve date from inserted table trying to convert it to */
/* a datetime data type. If the conversion fails, the insert */
/* or update will be rolled back. */
select @date=convert (datetime, convert (char(12), date_field_name))
from inserted
SET arithignor off
======================================================================
/* Below is the second version of the validation trigger. */
/* This trigger checks to validate both months and days, */
/* including the simple rule to validate for leap years. */
CREATE TRIGGER date_trigger
ON date_table
FOR insert, update
AS
declare @day_part tinyint /* holds DD part of YYYYMMDD */
declare @mon_part tinyint /* holds MM part of YYYYMMDD */
declare @yr_part smallint /* holds YYYY part of YYYYMMDD */
declare @date int /* gets date field from inserted table */
/* Retrieve date from inserted table
select @date=date_field_name from inserted
/* As stated earlier, you can place this portion in a stored procedure */
/* so that table(s) can make use of multiple DATE fields */
/* Check allows for NULL dates */
if @date != NULL
begin
/* retrieves month part out of YYYYMMDD format */
select @mon_part = ((@date%10000)/100)
/* validates month */
if @mon_part between 1 and 12
begin
/* retrieves day part out of YYYYMMDD format */
select @day_part = (@date % 100)
/* Validates days of 1..31 for months of 31 days */
if @mon_part in (1,3,5,7,8,10,12)
and @day_part not between 1 and 31
begin
print "invalid day in date, rolling back transaction"
rollback transaction
end
/* Validates days of 1..30 for months of 30 days */
else if @mon_part in (4,6,9,11) and @day_part not between 1 and 30
begin
print "invalid day in date, rolling back transaction"
rollback transaction
end
/* This portion checks to see if the Feb. date satisfies */
/* the Leap Year Rule. A year is a leap year if the year is */
/* divisible by four. However, if the year ends in 00, then it */
/* it is only a leap year if the year ending in 00 is divisible */
/* by 400. */
else if @mon_part = 2 and @day_part not between 1 and 28
begin
if @day_part = 29
begin
select @yr_part = @date/10000
if @yr_part % 4 = 0 begin
if @yr_part % 100 = 0 and @yr_part % 400 != 0
begin
print "invalid day, violates leap year rules, rolling back
transaction"
rollback transaction
end
end
else begin
print "invalid day, violates leap year rules, rolling back
transaction"
rollback transaction
end
end
else begin
print "invalid day in date, rolling back transaction"
rollback transaction
end
end
else begin
print "invalid day or month in date, rolling back transaction"
rollback transaction
end
end
else
begin
print "invalid month in date, rolling back transaction"
rollback transaction
end
end /* if not NULL */
Additional query words:
4.20 dblib
Keywords : kbprg SSrvDB_Lib SSrvGen SSrvTran_SQL
Version : 4.2
Platform : OS/2 WINDOWS
Issue type :