2013-06-14 6 views
19

ho bisogno di aggiungere due colonne di una tabella di database in SQL Server 2008 R2:SQL Server 2008 riga di inserimento e aggiornamento timestamp

  • createTS - data e l'ora in cui riga viene inserita
  • updateTS - data e ora di riga viene aggiornato

ho alcune domande:

  1. Quale tipo di dati della colonna devo utilizzare per ognuno di questi?
  2. createTS deve essere impostato solo una volta, quando viene inserita la riga. Quando ho provato il tipo datetime per questa colonna e ho aggiunto un valore predefinito o l'associazione di getdate(), il valore della colonna è stato impostato correttamente. È questo il modo migliore per realizzare lo scopo di questa colonna? Ho considerato il tipo di dati timestamp, ma questo è, a mio parere, quasi un termine improprio!
  3. updateTS deve essere impostato sulla data e l'ora del momento in cui la riga viene aggiornata. In SQL Server, non c'è ON UPDATE CURRENT_TIMESTAMP (come in MySQL), quindi sembra che debba ricorrere all'utilizzo di un trigger. È giusto e come potrei farlo?

cui v'è un punto di partenza per tutti coloro che vogliono rispondere a questa domanda, ecco lo script create table:

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] 
+3

Nota a margine: dovresti ** non ** rendere la tua chiave cluster (a) così ampia ('nvarchar (64)' = 128 byte !!) ed è anche (b) non consigliabile renderla una colonna a lunghezza variabile (dal momento che questi hanno spese generali aggiuntive). Una ** buona ** chiave di clustering sarebbe stretta, unica, statica (non cambia) e idealmente sempre crescente - un 'INT IDENTITY' è quasi perfetto, niente più di 8-16 byte è ** orrendo ** male come chiave di cluster ... –

risposta

19

provare

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

) 

PS Credo che uno smalldatetime è abbastanza buono Puoi decidere diversamente.

Non puoi farlo al "momento dell'impatto"?

in SQL Server, questo è comune:

Update dbo.MyTable 
Set 

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

SQL Server è un tipo di dati "timestamp".

Ma potrebbe non essere quello che pensi.

Qui è un riferimento:

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

Qui è un po 'RowVersion (timestamp) Esempio:

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] 

Forse un esempio funzionante completo:

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] 

corrispondenza su il valore "Nome" probabilmente non è saggio.

Prova questo esempio più mainstream con un 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] 
+0

Fare questo al momento dell'impatto è l'ideale, ma dal punto di vista applicativo, che garantisce cambiamenti in molti luoghi. Preferirei gestirlo a livello di database ... perché è percepito come una responsabilità del database per tenere traccia di tali informazioni. –

+0

Allora sei bloccato con un grilletto, come sospetti ... per quanto ne so. Se segui questa strada, assicurati di scrivere il codice di attivazione "set based", non il codice di trigger "riga per riga". – granadaCoder

+0

Ok ... Non conosco la distinzione tra codice di attivazione basato su set e riga per riga. –

2

Come alternativa all'utilizzo di un trigger, come si potrebbe prendere in considerazione la creazione di una stored procedure per gestire le INSERT s che prende la maggior parte delle colonne come argomenti e ottiene il CURRENT_TIMESTAMP che include nell'ultimo INSERT nel database. Potresti fare lo stesso per lo CREATE. Potresti anche essere in grado di impostare le cose in modo che gli utenti non possano eseguire le istruzioni INSERT e CREATE diverse dalle stored procedure.

Devo ammettere che non l'ho fatto in realtà, quindi non sono affatto sicuro dei dettagli.

+0

Le stored procedure esistenti sono un'estensione della logica di business dell'applicazione, quindi ci sono molte di quelle che devono essere aggiornate. Ecco perché i trigger potrebbero essere preferibili approccio, per quanto non mi piaccia impiegarli per questo caso d'uso molto fondamentale. –