web-dev-qa-db-ja.com

レコードが変更されたときに自動的に更新されるMS SQLの日時フィールドが必要

レコードが作成された日付を常に含む新しいDATETIMEフィールドをMS-SQLで作成する必要があり、レコードが変更されるたびに自動的に更新する必要があります。トリガーが必要だと言われているのを聞いたことがありますが、それは問題ありませんが、その書き方がわかりません。誰かがこれを達成するためのトリガーの構文を手伝うことができますか?

MySQLの用語では、このMySQLステートメントとまったく同じことを行う必要があります。

ADD `modstamp` timestamp NULL DEFAULT CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP

以下にいくつかの要件を示します。

  • レコードを書き込むアプリケーションロジックを制御していないため、行の変更時にフィールドを設定するようにUPDATEステートメントを変更することはできません。
  • 理想的には、テーブル内の他の列の名前(主キーなど)を知る必要はありません。
  • 非常に頻繁に発生するため、短くて効率的でなければなりません。
20
Jesse Barnum

実際、MSSQLにはUPDATEのデフォルト値を定義する方法がありません。

そのため、挿入するためのデフォルト値を持つ列を追加する必要があります。

ADD modstamp DATETIME2 NULL DEFAULT GETDATE()

そして、テーブルにトリガーを追加します。

CREATE TRIGGER tgr_modstamp
ON **TABLENAME**
AFTER UPDATE AS
  UPDATE **TABLENAME**
  SET ModStamp = GETDATE()
  WHERE **ID** IN (SELECT DISTINCT **ID** FROM Inserted)

はい、トリガーごとにID列を指定する必要があります。

注意:アプリケーションのコードがわからないテーブルに列を挿入するときは注意してください。アプリにフィールド定義のないINSERT VALUESコマンドがある場合、新しい列のデフォルト値でもエラーが発生します。

29
rkawano

さて、私はいつも何かが起こったときだけでなく、誰がそれをしたのかを常に追跡したいです!

[dwarfs]という名前の[tempdb]にテストテーブルを作成します。金融機関である以前の仕事では、挿入(作成)日付と更新(変更)日付を追跡します。

-- just playing
use tempdb;
go

-- drop table
if object_id('dwarfs') > 0
drop table dwarfs
go

-- create table
create table dwarfs
(
asigned_id int identity(1,1),
full_name varchar(16),
ins_date datetime,
ins_name sysname,
upd_date datetime,
upd_name sysname,
);
go

-- insert/update dates
alter table dwarfs
    add constraint [df_ins_date] default (getdate()) for ins_date;
alter table dwarfs
    add constraint [df_upd_date] default (getdate()) for upd_date;

-- insert/update names
alter table dwarfs
    add constraint [df_ins_name] default (coalesce(suser_sname(),'?')) for ins_name;

alter table dwarfs
    add constraint [df_upd_name] default (coalesce(suser_sname(),'?')) for upd_name;
go

更新用ですが、挿入および削除されたテーブルは存在します。更新のために挿入されたものに参加することを選択します。

-- create the update trigger
create trigger trg_changed_info on dbo.dwarfs
for update
as
begin

    -- nothing to do?
    if (@@rowcount = 0)
      return;

    update d
    set 
       upd_date = getdate(),
       upd_name = (coalesce(suser_sname(),'?'))
    from
       dwarfs d join inserted i 
    on 
       d.asigned_id = i.asigned_id;

end
go

最後になりましたが、コードをテストしてみましょう。誰でも未テストのTSQLステートメントを入力できます。しかし、チームには常にテストを強調しています!

-- remove data
truncate table dwarfs;
go

-- add data
insert into dwarfs (full_name) values
('bilbo baggins'),
('gandalf the grey');
go

-- show the data
select * from dwarfs;

-- update data
update dwarfs 
set full_name = 'gandalf'
where asigned_id = 2;

-- show the data
select * from dwarfs;

出力。挿入と削除の間は10秒しか待ちませんでした。良いことは、誰といつがキャプチャされることです。

enter image description here

12
CRAFTY DBA
Create trigger tr_somename 
On table_name
For update
As 
Begin
    Set nocount on; 
       Update t
        Set t.field_name = getdate()
        From table_name t inner join inserted I 
        On t.pk_column = I.pk_column
End
7
M.Ali

これは、SQL Server 2016以降のPERIOD FOR SYSTEM_TIME

これはテンポラルテーブル用に導入されたものですが、これを使用するためにテンポラルテーブルを使用する必要はありません。

以下に例を示します

CREATE TABLE dbo.YourTable
(  
    FooId INT PRIMARY KEY CLUSTERED,   
    FooName VARCHAR(50) NOT NULL,
    modstamp DATETIME2 GENERATED ALWAYS AS ROW START NOT NULL,   
    MaxDateTime2 DATETIME2 GENERATED ALWAYS AS ROW END HIDDEN NOT NULL,     
    PERIOD FOR SYSTEM_TIME (modstamp,MaxDateTime2)    
)  

INSERT INTO dbo.YourTable (FooId, FooName)
VALUES      (1,'abc');

SELECT *
FROM   dbo.YourTable;

WAITFOR DELAY '00:00:05'

UPDATE dbo.YourTable
SET    FooName = 'xyz'
WHERE  FooId = 1;

SELECT *
FROM   dbo.YourTable;

DROP TABLE dbo.YourTable; 

enter image description here

いくつかの制限があります。

  • 格納される時間はシステムによって更新され、常にUTCです。
  • 2番目の列を宣言する必要があります(MaxDateTime2上記)これは、このユースケースにはまったく不要です。ただし、非表示としてマークすると、無視しやすくなります。
6
Martin Smith
ALTER TRIGGER [trg_table_name_Modified]
ON [table_name]
AFTER UPDATE 
AS
Begin
    UPDATE table_name
    SET modified_dt_tm = GETDATE()  -- or use SYSDATETIME() for 2008 and newer
    FROM Inserted i
    WHERE i.ID = table_name.id

    end
2
Rolwin C