(Patterns and Query Techniques).sql

Use tempdb
GO
---------------------------------------------------------------------
-- Precalculated Values; Sequence Tables
----------------------------------------------------------------------

;WITH
digits (i) as(--set up a set of numbers from 0-9
              SELECT i
              FROM  (VALUES (0),(1),(2),(3),(4),
                            (5),(6),(7),(8),(9)) as digits (i))
,sequence (i) as (
        SELECT D1.i + (10*D2.i) + (100*D3.i) + (1000*D4.i)
               --+ (10000*D5.i) + (100000*D6.i)
        FROM digits AS D1 CROSS JOIN digits AS D2 CROSS JOIN digits AS D3
                CROSS JOIN digits AS D4
              --CROSS JOIN digits AS D5 CROSS JOIN digits AS D6
                )
SELECT *
FROM  sequence
ORDER BY i
GO

CREATE SCHEMA tools
go
CREATE TABLE tools.sequence
(
    i   int CONSTRAINT PKtools_sequence PRIMARY KEY
)
GO

;WITH DIGITS (i) as(--set up a set of numbers from 0-9
        SELECT i
        FROM   (VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) as digits (i))
--builds a table from 0 to 99999
,sequence (i) as (
        SELECT D1.i + (10*D2.i) + (100*D3.i) + (1000*D4.i) + (10000*D5.i)
               --+ (100000*D6.i)
        FROM digits AS D1 CROSS JOIN digits AS D2 CROSS JOIN digits AS D3
                CROSS JOIN digits AS D4 CROSS JOIN digits AS D5
                /* CROSS JOIN digits AS D6 */)
INSERT INTO tools.sequence(i)
SELECT i
FROM   sequence
GO
DECLARE @string varchar(21) = 'This is my test value'
SELECT SUBSTRING(split.value,sequence.i,1) as [char],
       UNICODE(SUBSTRING(split.value,sequence.i,1)) as [Unicode]
FROM   tools.sequence
         cross join (select @string as value) as split
WHERE  sequence.i > 0
  AND  sequence.i <= len(@string)
GO

SELECT LastName, sequence.i as position,
              SUBSTRING(Person.LastName,sequence.i,1) as [char],
              UNICODE(SUBSTRING(Person.LastName,sequence.i,1)) as [Unicode]
FROM   AdventureWorks2008.Person.Person
         JOIN tools.sequence
               ON sequence.i <= LEN(Person.LastName )
  And  UNICODE(SUBSTRING(Person.LastName,sequence.i,1)) is not null
ORDER BY 1
GO
DECLARE @delimitedList VARCHAR(100) = '1,2,3,4,5'

SELECT word = SUBSTRING(',' + @delimitedList + ',',i + 1,
                  CHARINDEX(',',',' + @delimitedList + ',',i + 1) - i - 1)
FROM tools.sequence
WHERE i >= 1
  AND i < LEN(',' + @delimitedList + ',') - 1
  AND SUBSTRING(',' + @delimitedList + ',', i, 1) = ','
ORDER BY i
GO

DECLARE @delimitedList VARCHAR(100) = '1,2,3,4,5'
SELECT i
FROM tools.sequence
WHERE i >= 1
  AND i < LEN(',' + @delimitedList + ',') - 1
  AND SUBSTRING(',' + @delimitedList + ',', i, 1) = ','
ORDER BY i
GO

CREATE TABLE poorDesign
(
    poorDesignId    int,
    badValue        varchar(20)
)
INSERT INTO poorDesign
VALUES (1,'1,3,56,7,3,6'),
       (2,'22,3'),
       (3,'1')
GO

SELECT poorDesign.poorDesignId as betterDesignId,
       SUBSTRING(',' + poorDesign.badValue + ',',i + 1,
               CHARINDEX(',',',' + poorDesign.badValue + ',',i + 1) - i - 1)
                                       as betterScalarValue
FROM   poorDesign
         JOIN tools.sequence
            on i >= 1
              AND i < LEN(',' + poorDesign.badValue + ',') - 1
              AND SUBSTRING(',' + + poorDesign.badValue  + ',', i, 1) = ','
GO

SET ANSI_WARNINGS ON
GO
ALTER TABLE tools.sequence
  ADD i3 as cast( power(cast(i as bigint),3) as bigint) PERSISTED
  --Note that I had to cast i as bigint first to let the power function
  --return a bigint

GO

DECLARE @level int = 2 --sum of two cubes

;WITH cubes as
(SELECT i3
FROM   tools.sequence
WHERE  i >= 1 and i < 500) --<<<Vary for performance, and for cheating reasons,
                           --<<<max needed value

SELECT c1.i3 + c2.i3 as [sum of 2 cubes in N Ways]
FROM   cubes as c1
         cross join cubes as c2
WHERE c1.i3 <= c2.i3
GROUP by (c1.i3 + c2.i3)
HAVING count(*) = @level
ORDER BY 1

GO
----------------------------------------------------------------------
-- Precalculated Values; Calculations with Dates
----------------------------------------------------------------------

create table tools.calendar
(
        dateValue datetime NOT NULL CONSTRAINT PKtools_calendar PRIMARY KEY,
        dayName varchar(10) NOT NULL,
        monthName varchar(10) NOT NULL,
        year varchar(60) NOT NULL,
        day tinyint NOT NULL,
        dayOfTheYear smallint NOT NULL,
        month smallint NOT NULL,
        quarter tinyint NOT NULL
)
GO
WITH dates (newDateValue) as (
        select dateadd(day,i,'17530101') as newDateValue
        from tools.sequence
)
INSERT tools.calendar
        (dateValue ,dayName
        ,monthName ,year ,day
        ,dayOfTheYear ,month ,quarter
)
SELECT
        dates.newDateValue as dateValue,
        datename (dw,dates.newDateValue) as dayName,
        datename (mm,dates.newDateValue) as monthName,
        datename (yy,dates.newDateValue) as year,
        datepart(day,dates.newDateValue) as day,
        datepart(dy,dates.newDateValue) as dayOfTheYear,
        datepart(m,dates.newDateValue) as month,
        datepart(qq,dates.newDateValue) as quarter
 
FROM    dates
WHERE  dates.newDateValue between '20000101' and '20100101' --set the date range
ORDER  BY datevalue
GO

SELECT calendar.year, COUNT(*) as orderCount
FROM   AdventureWorks2008.Sales.SalesOrderHeader
         JOIN tools.calendar
               --note, the cast here could be a real performance killer
               --consider using date columns where
            ON CAST(SalesOrderHeader.OrderDate as date) = calendar.dateValue
GROUP BY calendar.year
ORDER BY calendar.year
GO

SELECT MAX(dateValue)
FROM   tools.calendar
WHERE  year = '2008'
GROUP  BY year, month
GO

SELECT calendar.dayName, COUNT(*) as orderCount
FROM   AdventureWorks2008.Sales.SalesOrderHeader
         JOIN tools.calendar
               --note, the cast here could be a real performance killer
               --consider using date columns where
            ON CAST(SalesOrderHeader.OrderDate as date) = calendar.dateValue
WHERE calendar.dayName in ('Tuesday','Thursday')
GROUP BY calendar.dayName
ORDER BY calendar.dayName
GO

WITH onlyWednesdays as --get all wednesdays
(
    SELECT *,
           ROW_NUMBER()  over (partition by calendar.year, calendar.month
                               order by calendar.day) as wedRowNbr
    FROM   tools.calendar
    WHERE  dayName = 'Wednesday'
),
secondWednesdays as --limit to second Wednesdays of the month
(
    SELECT *
    FROM   onlyWednesdays
    WHERE  wedRowNbr = 2
)
,finallyTuesdays as --finally limit to the Tuesdays after the second wed
(
    SELECT calendar.*,
           ROW_NUMBER() OVER (partition by calendar.year, calendar.month
                              order by calendar.day) as rowNbr
    FROM   secondWednesdays
             JOIN tools.calendar
                ON secondWednesdays.year = calendar.year
                    AND secondWednesdays.month = calendar.month
    WHERE  calendar.dayName = 'Tuesday'
      AND  calendar.day > secondWednesdays.day
)
--and in the final query, just get the one month
SELECT year, monthName, day
FROM   finallyTuesdays
WHERE  year = 2008
  AND  rowNbr = 1
GO

DROP TABLE tools.calendar
go
CREATE TABLE tools.calendar
(
        dateValue date NOT NULL CONSTRAINT PKdate_dim PRIMARY KEY,
        dayName varchar(10) NOT NULL,
        monthName varchar(10) NOT NULL,
        year varchar(60) NOT NULL,
        day tinyint NOT NULL,
        dayOfTheYear smallint NOT NULL,
        month smallint NOT NULL,
        quarter tinyint NOT NULL,
        weekendFlag bit not null,

        --start of fiscal year configurable in the load process, currently
        --only supports fiscal months that match the calendar months.
        fiscalYear smallint NOT NULL,
        fiscalMonth tinyint NULL,
        fiscalQuarter tinyint NOT NULL,

        --used to give relative positioning, such as the previous 10 months
        --which can be annoying due to month boundries
        relativeDayCount int NOT NULL,
        relativeWeekCount int NOT NULL,
        relativeMonthCount int NOT NULL
)
GO

WITH dates (newDateValue) as (
        select dateadd(day,i,'17530101') as newDateValue
        from tools.sequence
)
INSERT tools.calendar
        (dateValue ,dayName
        ,monthName ,year ,day
        ,dayOfTheYear ,month ,quarter
        ,weekendFlag ,fiscalYear ,fiscalMonth
        ,fiscalQuarter ,relativeDayCount,relativeWeekCount
        ,relativeMonthCount)
SELECT
        dates.newDateValue as dateValue,
        datename (dw,dates.newDateValue) as dayName,
        datename (mm,dates.newDateValue) as monthName,
        datename (yy,dates.newDateValue) as year,
        datepart(day,dates.newDateValue) as day,
        datepart(dy,dates.newDateValue) as dayOfTheYear,
        datepart(m,dates.newDateValue) as month,
        case
                when month ( dates.newDateValue) <= 3 then 1
                when month ( dates.newDateValue) <= 6 then 2
                when month ( dates.newDateValue) <= 9 then 3
        else 4 end as quarter,

        case when datename (dw,dates.newDateValue) in ('Saturday','Sunday')
                then 1
                else 0
        end as weekendFlag,

        ------------------------------------------------
        --the next three blocks assume a fiscal year starting in July.
        --change if your fiscal periods are different
        ------------------------------------------------
        case
                when month(dates.newDateValue) <= 6
                then year(dates.newDateValue)
                else year (dates.newDateValue) + 1
        end as fiscalYear,

        case
                when month(dates.newDateValue) <= 6
                then month(dates.newDateValue) + 6
                else month(dates.newDateValue) - 6
         end as fiscalMonth,

        case
                when month(dates.newDateValue) <= 3 then 3
                when month(dates.newDateValue) <= 6 then 4
                when month(dates.newDateValue) <= 9 then 1
        else 2 end as fiscalQuarter,

        ------------------------------------------------
        --end of fiscal quarter = july
        ------------------------------------------------

        --these values can be anything, as long as the
        --provide contiguous values on year, month, and week boundaries
        datediff(day,'20000101',dates.newDateValue) as relativeDayCount,
        datediff(week,'20000101',dates.newDateValue) as relativeWeekCount,
        datediff(month,'20000101',dates.newDateValue) as relativeMonthCount

FROM    dates
WHERE  dates.newDateValue between '20000101' and '20100101' --set the date range
GO

SELECT calendar.fiscalYear, COUNT(*) as orderCount
FROM   AdventureWorks2008.Sales.SalesOrderHeader
         JOIN tools.calendar
               --note, the cast here could be a real performance killer
               --consider using date columns where
            ON CAST(SalesOrderHeader.OrderDate as date) = calendar.dateValue
WHERE    weekendFlag = 1
GROUP BY calendar.fiscalYear
ORDER BY calendar.fiscalYear
GO

DECLARE @interestingDate date = '20080107'

SELECT calendar.dateValue as previousTwoWeeks, currentDate.dateValue as today,
        calendar.relativeWeekCount
FROM   tools.calendar
           join (select *
                 from tools.calendar
                 where dateValue = @interestingDate) as currentDate
              on  calendar.relativeWeekCount < (currentDate.relativeWeekCount)
                  and calendar.relativeWeekCount >=
                                         (currentDate.relativeWeekCount -2)
GO

DECLARE @interestingDate date = '20080315'

SELECT MIN(calendar.dateValue), MAX(calendar.dateValue)
FROM   tools.calendar
           JOIN (SELECT *
                 FROM tools.calendar
                 WHERE dateValue = @interestingDate) as currentDate
              ON  calendar.relativeMonthCount < (currentDate.relativeMonthCount)
                  AND calendar.relativeMonthCount >=
                                       (currentDate.relativeMonthCount -12)
GO

DECLARE @interestingDate date = '20040827'

SELECT calendar.year, calendar.month, COUNT(*) as orderCount
FROM   AdventureWorks2008.Sales.SalesOrderHeader
         JOIN tools.calendar
           JOIN (select *
                 from tools.calendar
                 where dateValue = @interestingDate) as currentDate
               on  calendar.relativeMonthCount <=
                                           (currentDate.relativeMonthCount )
                    and calendar.relativeMonthCount >=
                                           (currentDate.relativeMonthCount -10)
            on cast(salesOrderHeader.shipDate as date)= calendar.dateValue
GROUP BY calendar.year, calendar.month
ORDER BY calendar.year, calendar.month
GO

-------------------------------------------------------------------
-- Storing User-Specified Data
-------------------------------------------------------------------

CREATE TABLE Equipment
(
    EquipmentId int NOT NULL
          CONSTRAINT PKEquipment PRIMARY KEY,
    EquipmentTag varchar(10) NOT NULL
          CONSTRAINT AKEquipment UNIQUE,
    EquipmentType varchar(10)
)
GO
INSERT INTO Equipment
VALUES (1,'CLAWHAMMER','Hammer'),
       (2,'HANDSAW','Saw'),
       (3,'POWERDRILL','PowerTool')
GO
-------------------------------------------------------------------
-- Storing User-Specified Data; Entity-Attribute-Value (EAV)
-------------------------------------------------------------------

CREATE TABLE EquipmentPropertyType
(
    EquipmentPropertyTypeId int NOT NULL
        CONSTRAINT PKEquipmentPropertyType PRIMARY KEY,
    Name varchar(15)
        CONSTRAINT AKEquipmentPropertyType UNIQUE,
    TreatAsDatatype sysname NOT NULL
)
INSERT INTO EquipmentPropertyType
VALUES(1,'Width','numeric(10,2)'),
      (2,'Length','numeric(10,2)'),
      (3,'HammerHeadStyle','varchar(30)')
GO
CREATE TABLE EquipmentProperty
(
    EquipmentId int NOT NULL
        CONSTRAINT Equipment$hasExtendedPropertiesIn$EquipmentProperty
           REFERENCES Equipment(EquipmentId),
    EquipmentPropertyTypeId int
        CONSTRAINT EquipmentPropertyTypeId$definesTypesFor$EquipmentProperty
           REFERENCES EquipmentPropertyType(EquipmentPropertyTypeId),
    Value sql_variant,
    CONSTRAINT PKEquipmentProperty PRIMARY KEY
                     (EquipmentId, EquipmentPropertyTypeId)
)
GO

CREATE PROCEDURE EquipmentProperty$Insert
(
    @EquipmentId int,
    @EquipmentPropertyName varchar(15),
    @Value sql_variant
)
AS
    SET NOCOUNT ON
    DECLARE @entryTrancount int = @@trancount

    BEGIN TRY
        DECLARE @EquipmentPropertyTypeId int,
                @TreatASDatatype sysname

        SELECT @TreatASDatatype = TreatAsDatatype,
               @EquipmentPropertyTypeId = EquipmentPropertyTypeId
        FROM   EquipmentPropertyType
        WHERE  EquipmentPropertyType.Name = @EquipmentPropertyName

      BEGIN TRANSACTION
        --insert the value
        INSERT INTO EquipmentProperty(EquipmentId, EquipmentPropertyTypeId,
                    Value)
        VALUES (@EquipmentId, @EquipmentPropertyTypeId, @Value)

        --Then get that value from the table and cast it in a dynamic SQL
        -- call.  This will raise a trappable error if the type is incompatible
        DECLARE @validationQuery  varchar(max) =
              ' DECLARE @value sql_variant
                SELECT  @value = cast(value as ' + @TreatASDatatype + ')
                FROM    EquipmentProperty
                WHERE   EquipmentId = ' + cast (@EquipmentId as varchar(10)) + '
                  and   EquipmentPropertyTypeId = ' +
                       cast(@EquipmentPropertyTypeId as varchar(10)) + ' '

        EXEC (@validationQuery)
      COMMIT TRANSACTION
    END TRY
    BEGIN CATCH

        --if the tran is doomed, and the entryTrancount was 0
        --we have to rollback
        IF xact_state()= -1 and @entryTrancount = 0
            rollback transaction

      DECLARE @ERRORmessage nvarchar(4000)
      SET @ERRORmessage = 'Error occurred in procedure ''' +
                  object_name(@@procid) + ''', Original Message: '''
                 + ERROR_MESSAGE() + ''''
      RAISERROR (@ERRORmessage,16,1)
      RETURN -100

     END CATCH
GO
Exec EquipmentProperty$Insert 1,'Width','Claw' --width is numeric(10,2)
GO

EXEC EquipmentProperty$Insert @EquipmentId =1 ,
        @EquipmentPropertyName = 'Width', @Value = 2
EXEC EquipmentProperty$Insert @EquipmentId =1 ,
        @EquipmentPropertyName = 'Length',@Value = 8.4
EXEC EquipmentProperty$Insert @EquipmentId =1 ,
        @EquipmentPropertyName = 'HammerHeadStyle',@Value = 'Claw'
EXEC EquipmentProperty$Insert @EquipmentId =2 ,
        @EquipmentPropertyName = 'Width',@Value = 1
EXEC EquipmentProperty$Insert @EquipmentId =2 ,
        @EquipmentPropertyName = 'Length',@Value = 7
EXEC EquipmentProperty$Insert @EquipmentId =3 ,
        @EquipmentPropertyName = 'Width',@Value = 6
EXEC EquipmentProperty$Insert @EquipmentId =3 ,
        @EquipmentPropertyName = 'Length',@Value = 12.1
GO
SELECT Equipment.EquipmentTag,Equipment.EquipmentType,
       EquipmentPropertyType.name, EquipmentProperty.Value
FROM   EquipmentProperty
         JOIN Equipment
            on Equipment.EquipmentId = EquipmentProperty.EquipmentId
         JOIN EquipmentPropertyType
            on EquipmentPropertyType.EquipmentPropertyTypeId =
                                   EquipmentProperty.EquipmentPropertyTypeId
GO

SET ANSI_WARNINGS OFF --eliminates the NULL warning on aggregates.
SELECT  Equipment.EquipmentTag,Equipment.EquipmentType,
   MAX(CASE WHEN EquipmentPropertyType.name = 'Width' THEN Value END) AS Width,
   MAX(CASE WHEN EquipmentPropertyType.name = 'Length'THEN Value END) AS Length,
   MAX(CASE WHEN EquipmentPropertyType.name = 'HammerHeadStyle' THEN Value END)
                                                            AS 'HammerHeadStyle'
FROM   EquipmentProperty
         JOIN Equipment
            on Equipment.EquipmentId = EquipmentProperty.EquipmentId
         JOIN EquipmentPropertyType
            on EquipmentPropertyType.EquipmentPropertyTypeId =
                                     EquipmentProperty.EquipmentPropertyTypeId
GROUP BY Equipment.EquipmentTag,Equipment.EquipmentType
GO

SET ANSI_WARNINGS OFF
DECLARE @query varchar(8000)
SELECT  @query = 'select Equipment.EquipmentTag,Equipment.EquipmentType ' + (
                SELECT distinct
                    ',MAX(CASE WHEN EquipmentPropertyType.name = ''' +
                       EquipmentPropertyType.name + ''' THEN cast(Value as ' +
                       EquipmentPropertyType.TreatAsDatatype + ') END) AS [' +
                       EquipmentPropertyType.name + ']' AS [text()]
                FROM
                    EquipmentPropertyType
                FOR XML PATH('') ) + '
                FROM  EquipmentProperty
                             JOIN Equipment
                                on Equipment.EquipmentId =
                                     EquipmentProperty.EquipmentId
                             JOIN EquipmentPropertyType
                                on EquipmentPropertyType.EquipmentPropertyTypeId
                                   = EquipmentProperty.EquipmentPropertyTypeId
          GROUP BY Equipment.EquipmentTag,Equipment.EquipmentType  '
EXEC (@query)
GO

-------------------------------------------------------------------
-- Storing User-Specified Data; Adding Columns to a Table
-------------------------------------------------------------------

ALTER TABLE Equipment
    ADD Length numeric(10,2) SPARSE NULL
GO

CREATE PROCEDURE equipment$addProperty
(
    @propertyName   sysname, --the column to add
    @datatype       sysname, --the datatype as it appears in a column creation
    @sparselyPopulatedFlag bit = 1 --Add column as sparse or not
)
WITH EXECUTE AS SELF
AS
  --note: I did not include full error handling for clarity
  DECLARE @query nvarchar(max)

 --check for column existance
 IF NOT EXISTS (select *
               from   sys.columns
               where  name = @propertyName
                 and  OBJECT_NAME(object_id) = 'equipment')
  BEGIN
    --build the ALTER statement, then execute it
     SET @query = 'ALTER TABLE equipment ADD ' + quotename(@propertyName) + ' '
                + @datatype
                + case when @sparselyPopulatedFlag = 1 then ' SPARSE ' end
                + ' NULL '
     EXEC (@query)
  END
 ELSE
     RAISERROR ('The property you are adding already exists',16,1)
GO
--exec equipment$addProperty 'Length','numeric(10,2)',1 -- added manually
EXEC equipment$addProperty 'Width','numeric(10,2)',1
EXEC equipment$addProperty 'HammerHeadStyle','varchar(30)',1
GO

SELECT EquipmentTag, EquipmentType, HammerHeadStyle
       ,Length,Width
FROM   Equipment
GO

UPDATE Equipment
SET    Length = 7,
       Width =  1
WHERE  EquipmentTag = 'HANDSAW'
GO

SELECT EquipmentTag, EquipmentType, HammerHeadStyle
       ,Length,Width
FROM   Equipment
GO

ALTER TABLE Equipment
 ADD CONSTRAINT CHKEquipment$HammerHeadStyle CHECK
        ((HammerHeadStyle is NULL AND EquipmentType <> 'Hammer')
        OR EquipmentType = 'Hammer')
GO

UPDATE Equipment
SET    Length = 12.1,
       Width =  6,
       HammerHeadStyle = 'Wrong!'
WHERE  EquipmentTag = 'HANDSAW'
GO

UPDATE Equipment
SET    Length = 12.1,
       Width =  6
WHERE  EquipmentTag = 'POWERDRILL'

UPDATE Equipment
SET    Length = 8.4,
       Width =  2,
       HammerHeadStyle = 'Claw'
WHERE  EquipmentTag = 'CLAWHAMMER'

GO
SELECT EquipmentTag, EquipmentType, HammerHeadStyle
       ,Length,Width
FROM   Equipment
GO

SELECT name, is_sparse
FROM   sys.columns
WHERE  OBJECT_NAME(object_id) = 'Equipment'
GO

ALTER TABLE Equipment
    DROP CONSTRAINT CHKEquipment$HammerHeadStyle
ALTER TABLE Equipment
    DROP COLUMN HammerHeadStyle, Length, Width
GO
ALTER TABLE Equipment
  ADD SparseColumns xml column_set FOR ALL_SPARSE_COLUMNS

GO
EXEC equipment$addProperty 'Length','numeric(10,2)',1
EXEC equipment$addProperty 'Width','numeric(10,2)',1
EXEC equipment$addProperty 'HammerHeadStyle','varchar(30)',1
GO
ALTER TABLE Equipment
 ADD CONSTRAINT CHKEquipment$HammerHeadStyle CHECK
        ((HammerHeadStyle is NULL AND EquipmentType <> 'Hammer')
        OR EquipmentType = 'Hammer')
GO
UPDATE Equipment
SET    Length = 7,
       Width =  1
WHERE  EquipmentTag = 'HANDSAW'

GO
SELECT *
FROM   Equipment
GO

UPDATE Equipment
SET    SparseColumns = '<Length>12.10</Length><Width>6.00</Width>'
WHERE  EquipmentTag = 'PowerDrill'

UPDATE Equipment
SET    SparseColumns = '<Length>8.40</Length><Width>2.00</Width>
                        <HammerHeadStyle>Claw</HammerHeadStyle>'
WHERE  EquipmentTag = 'CLAWHAMMER'
GO
--------------------------------------------------------------------------------------
-- Commonly Implemented Objects
--------------------------------------------------------------------------------------

CREATE SCHEMA utility
GO
CREATE TABLE utility.ErrorLog(
        ERROR_NUMBER int NOT NULL,
        ERROR_LOCATION sysname NOT NULL,
        ERROR_MESSAGE varchar(4000),
        ERROR_DATE datetime NULL
              CONSTRAINT dfltErrorLog_error_date  DEFAULT (getdate()),
        ERROR_USER sysname NOT NULL
              --use original_login to capture the user name of the actual user
              --not a user they have impersonated
              CONSTRAINT dfltErrorLog_error_user_name DEFAULT (original_login())
)
GO

原文地址:https://www.cnblogs.com/dushu/p/2508822.html