2013-06-14 16 views
19

muszę dodać dwie kolumny do tabeli bazy danych w SQL Server 2008 R2:SQL Server 2008 Row Włóż i Aktualizacja znacznika czasu

  • createTS - datę i czas, kiedy rząd dodaje
  • updateTS - data i czas, kiedy rząd jest aktualizowana

mam kilka pytań:

  1. Jaki typ danych kolumny powinienem stosować dla każdego z nich?
  2. createTS należy ustawić tylko raz, po wstawieniu rzędu. Po wypróbowaniu typu datetime dla tej kolumny i dodaniu wartości domyślnej lub powiązania z getdate(), wartość kolumny została odpowiednio ustawiona. Czy jest to najlepszy sposób na wypełnienie celu tej kolumny? Rozważałem typ danych timestamp, ale to, moim zdaniem, prawie błędna nazwa!
  3. updateTS należy ustawić na datę i godzinę, w której wiersz jest aktualizowany. W SQL Serverze nie ma żadnego ON UPDATE CURRENT_TIMESTAMP (jak w MySQL), więc wygląda na to, że muszę uciec się do używania wyzwalacza. Czy to prawda i jak miałbym to zrobić?

Więc nie jest punktem wyjścia dla każdego, kto chciałby, aby odpowiedzieć na to pytanie, oto skrypt tworzenia tabeli:

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

Side uwaga: nie należy ** ** dokonać klastrowego klucza (a) to szeroka ('nvarchar (64)' = 128 bajtów !!) i to także (b) nie jest wskazane, aby to kolumny o zmiennej długości (ponieważ mają dodatkowy narzut). Klucz ** dobry ** klastrowania byłby wąski, unikalny, statyczny (nie zmienia się), a idealnie wzrastający - "IDENTYFIKACJA INT" jest prawie doskonała, wszystko powyżej 8-16 bajtów jest ** potwornie ** zły jak klucz do klastrowania ... –

Odpowiedz

19

spróbować

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

) 

PS myślę, że smalldatetime jest wystarczająco dobre. Możesz zdecydować inaczej.

Nie możesz tego zrobić w "momencie uderzenia"?

w SQL Server, to jest wspólne:

Update dbo.MyTable 
Set 

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

SQL Server ma "timestamp" typ danych.

Ale może nie być tak, jak myślisz.

Oto referencyjny:

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

Oto mały RowVersion (timestamp) przykład:

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] 

Może kompletnym przykładem pracy:

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] 

Matching na wartość "Nazwa" prawdopodobnie nie jest mądra.

Spróbuj bardziej powszechne przykład z 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

Dokonanie tego w momencie uderzenia jest idealne, ale z perspektywy aplikacji, które gwarantuje zmiany w wielu miejscach. Wolę sobie z tym poradzić na poziomie bazy danych ... ponieważ jest ona odpowiedzialna za bazę danych, aby śledzić te informacje. –

+0

Potem utkniesz z wyzwalaczem, jak podejrzewasz ... o ile wiem. Jeśli wybierzesz tę trasę, upewnij się, że piszesz kod aktywacyjny "ustawiony na podstawie", a nie kod "wiersz po wierszu". – granadaCoder

+0

Okay ... Nie znam rozróżnienia między kodem aktywacyjnym opartym na zestawie i wierszem. –

2

Jako alternatywę do stosowania spust, może chcesz rozważyć utworzenie procedurę przechowywaną, aby obsłużyć INSERT S, która bierze większość kolumn jako argumenty i dostaje CURRENT_TIMESTAMP, który zawiera w ostatecznej wersji INSERT do bazy danych. Możesz zrobić to samo dla CREATE. Możliwe jest również skonfigurowanie funkcji, aby użytkownicy nie mogli wykonywać instrukcji innych niż za pośrednictwem procedur składowanych.

muszę przyznać, że nie zostały faktycznie zrobić to sam, więc nie jestem wcale pewien szczegółów.

+0

Istniejące procedury przechowywane są rozszerzeniem logiki biznesowej aplikacji, więc jest wiele z tych, które wymagają aktualizacji, dlatego wyzwalacze mogą być preferowane podejście, tak samo jak nie lubię zatrudniać ich w tym bardzo podstawowym przypadku użycia. –

Powiązane problemy