web-dev-qa-db-ja.com

SQL Server 2008の行の挿入と更新のタイムスタンプ

SQL Server 2008 R2のデータベーステーブルに2つの列を追加する必要があります。

  • createTS-行が挿入された日時
  • updateTS-行が更新された日時

いくつかの質問を聞きたいんです:

  1. これらのそれぞれにどの列データ型を使用する必要がありますか?
  2. createTSは、行の挿入時に一度だけ設定する必要があります。この列にdatetimeタイプを試して、getdate()Default ValueまたはBindingを追加したとき、列値が適切に設定されました。これがこのコラムの目的を達成する最良の方法ですか? timestampデータ型 を考慮しましたが、それは、私の意見では、ほぼ間違った名前です!
  3. updateTSは、行が更新される瞬間の日付と時刻に設定する必要があります。 SQL ServerにはON UPDATE CURRENT_TIMESTAMP(MySQLのように)がないため、トリガーを使用する必要があるようです。これは正しいですか、それをどうやってやるのですか?

したがって、この質問に答えたい人には出発点があります。これがテーブル作成スクリプトです。

CREATE TABLE [dbo].[names]
(
    [name] [nvarchar](64) NOT NULL,
    [createTS] [datetime] NOT NULL CONSTRAINT [DF_names_createTS]  DEFAULT (getdate()),
    [updateTS] [datetime] NOT NULL,
    CONSTRAINT [PK_names] PRIMARY KEY CLUSTERED 
    (
        [name] ASC
    )
    WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]
21
Web User

試してみる

CREATE TABLE [dbo].[Names]
(
    [Name] [nvarchar](64) NOT NULL,
    [CreateTS] [smalldatetime] NOT NULL CONSTRAINT CreateTS_DF DEFAULT CURRENT_TIMESTAMP,
    [UpdateTS] [smalldatetime] NOT NULL

)

PS smalldatetimeで十分だと思います。異なる決定をする場合があります。

「インパクトの瞬間」にこれを行うことはできませんか?

SQL Serverでは、これは一般的です:

Update dbo.MyTable 
Set 

ColA = @SomeValue , 
UpdateDS = CURRENT_TIMESTAMP
Where...........

SQL Serverには「タイムスタンプ」データ型があります。

しかし、それはあなたが考えるものではないかもしれません。

参照は次のとおりです。

http://msdn.Microsoft.com/en-us/library/ms182776(v = sql.90).aspx

ここに少しあります RowVersionタイムスタンプの同義語 )例:

CREATE TABLE [dbo].[Names]
(
    [Name] [nvarchar](64) NOT NULL,
    RowVers rowversion ,
    [CreateTS] [datetime] NOT NULL CONSTRAINT CreateTS_DF DEFAULT CURRENT_TIMESTAMP,
    [UpdateTS] [datetime] NOT NULL

)


INSERT INTO dbo.Names (Name,UpdateTS)
select 'John' , CURRENT_TIMESTAMP
UNION ALL select 'Mary' , CURRENT_TIMESTAMP
UNION ALL select 'Paul' , CURRENT_TIMESTAMP

select *  ,  ConvertedRowVers = CONVERT(bigint,RowVers) from [dbo].[Names]

Update dbo.Names Set Name = Name

select *  ,  ConvertedRowVers = CONVERT(bigint,RowVers) from [dbo].[Names]

たぶん完全な実用例:

DROP TABLE [dbo].[Names]
GO


CREATE TABLE [dbo].[Names]
(
    [Name] [nvarchar](64) NOT NULL,
    RowVers rowversion ,
    [CreateTS] [datetime] NOT NULL CONSTRAINT CreateTS_DF DEFAULT CURRENT_TIMESTAMP,
    [UpdateTS] [datetime] NOT NULL

)

GO

CREATE TRIGGER dbo.trgKeepUpdateDateInSync_ByeByeBye ON dbo.Names
AFTER INSERT, UPDATE
AS

BEGIN

Update dbo.Names Set UpdateTS = CURRENT_TIMESTAMP from dbo.Names myAlias , inserted triggerInsertedTable where 
triggerInsertedTable.Name = myAlias.Name

END


GO






INSERT INTO dbo.Names (Name,UpdateTS)
select 'John' , CURRENT_TIMESTAMP
UNION ALL select 'Mary' , CURRENT_TIMESTAMP
UNION ALL select 'Paul' , CURRENT_TIMESTAMP

select *  ,  ConvertedRowVers = CONVERT(bigint,RowVers) from [dbo].[Names]

Update dbo.Names Set Name = Name , UpdateTS = '03/03/2003' /* notice that even though I set it to 2003, the trigger takes over */

select *  ,  ConvertedRowVers = CONVERT(bigint,RowVers) from [dbo].[Names]

「名前」の値の一致はおそらく賢明ではありません。

この主流の例をSurrogateKeyで試してください

DROP TABLE [dbo].[Names]
GO


CREATE TABLE [dbo].[Names]
(
    SurrogateKey int not null Primary Key Identity (1001,1),
    [Name] [nvarchar](64) NOT NULL,
    RowVers rowversion ,
    [CreateTS] [datetime] NOT NULL CONSTRAINT CreateTS_DF DEFAULT CURRENT_TIMESTAMP,
    [UpdateTS] [datetime] NOT NULL

)

GO

CREATE TRIGGER dbo.trgKeepUpdateDateInSync_ByeByeBye ON dbo.Names
AFTER UPDATE
AS

BEGIN

   UPDATE dbo.Names
    SET UpdateTS = CURRENT_TIMESTAMP
    From  dbo.Names myAlias
    WHERE exists ( select null from inserted triggerInsertedTable where myAlias.SurrogateKey = triggerInsertedTable.SurrogateKey)

END


GO






INSERT INTO dbo.Names (Name,UpdateTS)
select 'John' , CURRENT_TIMESTAMP
UNION ALL select 'Mary' , CURRENT_TIMESTAMP
UNION ALL select 'Paul' , CURRENT_TIMESTAMP

select *  ,  ConvertedRowVers = CONVERT(bigint,RowVers) from [dbo].[Names]

Update dbo.Names Set Name = Name , UpdateTS = '03/03/2003' /* notice that even though I set it to 2003, the trigger takes over */

select *  ,  ConvertedRowVers = CONVERT(bigint,RowVers) from [dbo].[Names]
20
granadaCoder

トリガーを使用する代わりに、ほとんどの列を引数として取り、データベースへの最後のINSERTに含まれるCURRENT_TIMESTAMPを取得するINSERTsを処理するストアドプロシージャを作成することを検討できます。 CREATEについても同じことができます。また、ユーザーがストアドプロシージャ以外を使用してINSERTおよびCREATEステートメントを実行できないように設定することもできます。

私は実際に自分でこれを行っていないことを認めなければならないので、詳細はまったくわかりません。

2
nurdglaw