Database
 sql >> Teknologi Basis Data >  >> RDS >> Database

Melakukan Audit Perubahan Data Menggunakan Tabel Temporal

SQL Server 2016 telah memperkenalkan fitur yang disebut 'Tabel temporal versi sistem'. Menggunakan tabel normal, Anda dapat mengambil data saat ini; saat menggunakan tabel temporal versi sistem, Anda dapat mengambil data yang telah dihapus atau diperbarui di masa lalu. Untuk melakukan itu, tabel temporal akan membuat tabel riwayat. Tabel riwayat akan menyimpan data lama dengan “waktu_mulai ” dan “waktu_akhir ”. Yang menunjukkan periode waktu di mana catatan itu aktif.

Contoh:Jika Anda memperbarui harga produk dari 30 menjadi 50 dengan mengkueri tabel normal, Anda dapat mengambil harga produk yang diperbarui yaitu 50. Menggunakan tabel temporal, Anda dapat mengambil nilai lama yaitu 30.

Menggunakan tabel temporal, seseorang dapat melakukan:

  1. Lacak riwayat rekaman :kita dapat meninjau nilai catatan tertentu, yang telah diubah dari waktu ke waktu.
  2. Pemulihan Tingkat Rekam :jika kami menghapus catatan tertentu dari tabel atau catatan rusak, kami dapat mengambilnya dari tabel riwayat.

Tabel temporal menangkap tanggal-waktu catatan berdasarkan tanggal fisik (Tanggal Kalender) dari pembaruan dan penghapusan catatan. Saat ini, tidak mendukung pembuatan versi berdasarkan tanggal logis. Misalnya, jika Anda memperbarui nama produk menggunakan pernyataan UPDATE pada pukul 13.00, maka tabel temporal akan mempertahankan riwayat nama produk hingga pukul 13.00. Setelah itu, nama baru akan berlaku. Namun, bagaimana jika perubahan nama produk dimaksudkan mulai dari pukul 14:00? Ini berarti Anda harus memperbarui pernyataan tepat waktu dengan sempurna untuk membuatnya berfungsi dan Anda harus menjalankan pernyataan UPDATE pada pukul 14:00, bukan pukul 13:00.

Tabel temporal memiliki prasyarat berikut:

  1. Kunci utama harus ditentukan.
  2. Dua kolom harus ditentukan untuk mencatat waktu mulai dan waktu berakhir dengan tipe data datetime2. Kolom ini disebut kolom SYSTEM_TIME.

Mereka juga memiliki beberapa batasan:

  1. BUKAN pemicu dan OLTP Dalam Memori tidak diizinkan.
  2. Tabel riwayat tidak boleh memiliki batasan apa pun.
  3. Data dalam tabel riwayat tidak dapat diubah.

Membuat tabel versi sistem

Skrip berikut akan digunakan untuk membuat tabel sederhana versi sistem:

Gunakan DemoDatabaseGoCREATE TABLE dbo.Prodcuts ( Product_ID int identity (1,1) primary key , Product_Name varchar (500) , Product_Cost int , Quantity int , Product_Valid_From datetime2 DIHASILKAN SELALU ROW MULAI BUKAN NULL , Product_Valid AKHIR BUKAN NULL , PERIODE UNTUK SYSTEM_TIME (Product_Valid_From,Product_Valid_TO) )DENGAN (SYSTEM_VERSIONING =ON (HISTORY_TABLE =dbo.Product_Change_History));

Dalam skrip di atas, saya telah mendefinisikan HISTORY_TABLE bernama dbo. Produk_Perubahan_Riwayat. Jika Anda tidak menentukan nama untuk tabel histori, SQL Server akan secara otomatis membuat tabel histori dengan struktur berikut.

Dbo.MSSQL_TemporalHistoryFor_xxx, di mana xxx adalah ID objek.

Tabel temporal akan terlihat seperti yang ditunjukkan pada tangkapan layar di bawah ini:

Bagaimana kolom periode diperbarui saat mengeksekusi pernyataan DML di Tabel Temporal?

Setiap kali kita menjalankan insert, update, dan delete query pada tabel temporal, kolom periode (SysStartDate dan SysEndDate) akan diperbarui.

Sisipkan Kueri

Saat kami melakukan operasi INSERT pada tabel temporal, sistem menetapkan nilai kolom SysStartTime ke waktu mulai transaksi saat ini dan menandai baris sebagai terbuka.

Mari sisipkan beberapa baris di ‘Produk ’ dan tinjau bagaimana data disimpan dalam tabel ini.

INSERT INTO prodcuts (nama_produk, biaya_produk, kuantitas) NILAI ( 'Mouse', 500, 10 ), ( 'Key-Board', 200, 5 ), ( 'Headset', 500, 1 ), ( 'Laptop' , 50000, 1 ) pilih * dari Produk

Seperti yang ditunjukkan pada tangkapan layar di atas, nilai 'Product_Valid_From ' kolomnya adalah '02-04-2018 06:55:04.4865670 ' yang merupakan tanggal penyisipan baris. Dan nilai 'Product_Valid_To ' kolomnya adalah '9999-12-31 23:59:59.9999999 ', yang menunjukkan bahwa baris terbuka.

Perbarui Kueri

Saat kami menjalankan kueri pembaruan apa pun di tabel temporal, sistem akan menyimpan nilai baris sebelumnya di tabel riwayat dan mengatur waktu transaksi saat ini sebagai Waktu Berakhir dan perbarui tabel saat ini dengan nilai baru. SysStartTime akan menjadi waktu mulai transaksi dan SysEndTime akan menjadi maksimum 9999-12-31.

Mari kita ubah biaya Produk ‘Mouse ' dari 500 hingga 250. Kami akan memeriksa output dari 'Produk '.

Mulai tran UpdatePriceUpdate Prodcuts set Product_cost=200 where Product_name='Mouse'Commit tran UpdatePriceselect * from Prodcuts where Product_name='Mouse'

Seperti yang dapat Anda lihat pada tangkapan layar di atas, nilai 'Product_Valid_From ' kolom telah diubah. Nilai baru adalah waktu transaksi saat ini (UTC). Dan nilai 'Product_Valid_To ’ kolom ‘9999-12-31 23:59:59.9999999 ’, yang menunjukkan bahwa baris terbuka dan telah memperbarui harga.

Mari kita amati keluaran Product_change_history tabel dengan menanyakannya.

pilih * dari Product_Change_History di mana Product_name='Mouse'

Seperti yang Anda lihat pada tangkapan layar di atas, baris telah ditambahkan di Riwayat_perubahan_produk tabel, yang memiliki baris versi lama. Nilai ‘Product_cost ' adalah 500, Nilai 'Product_valid_From ' adalah waktu saat catatan dimasukkan dan nilai Product_Valid_To kolom adalah ketika nilai kolom biaya_produk telah diperbarui. Versi baris ini dianggap telah ditutup.

Hapus Kueri

Saat kami menghapus record dari tabel temporal, sistem akan menyimpan versi baris saat ini di tabel histori dan mengatur waktu transaksi saat ini sebagai EndTime dan menghapus record dari tabel saat ini.

Mari kita hapus catatan 'Headset'.

Mulai tran DeletePrice hapus dari Prodcuts where product_name='Headset'Commit tran DeletePrice

Mari kita amati keluaran Product_change_history tabel dengan menanyakannya.

pilih * dari Product_Change_History di mana Product_name='Headset'

Seperti yang Anda lihat pada tangkapan layar di atas, baris telah ditambahkan di Product_change_history tabel, yang telah dihapus dari tabel saat ini. Nilai 'Product_valid_From ’ adalah waktu saat catatan dimasukkan dan nilai Product_Valid_To kolom adalah waktu ketika baris dihapus yang menunjukkan bahwa versi baris ditutup.

Mengaudit perubahan data untuk waktu tertentu

Untuk mengaudit perubahan data untuk tabel tertentu, kita harus melakukan analisis tabel temporal berbasis waktu. Untuk melakukannya, kita harus menggunakan 'UNTUK SISTEM_TIME ' dengan sub-klausa khusus temporal di bawah untuk data kueri di seluruh tabel saat ini dan riwayat. Izinkan saya menjelaskan keluaran kueri menggunakan sub-klausa yang berbeda. Di bawah ini adalah pengaturannya:

  1. Saya memasukkan produk bernama 'Flat Washer 8' dengan Harga jual 0,00 di tabel temporal pada 09:02:25.
  2. Saya mengubah Daftar Harga pada 10:13:56. Harga Baru 500,00.

SEJAK

Klausa ini akan digunakan untuk mengambil status catatan untuk waktu tertentu dalam SEPERTI sub-klausa. Untuk memahaminya, mari kita jalankan beberapa query:

Pertama, kita akan mengeksekusi kueri menggunakan AS OF klausa dengan ”SystemTime =10:15:59 ”.

pilih Nama, ListPrice,rowguid,Product_Valid_From,Product_Valid_TO dari DemoDatabase.dbo.tblProduct FOR system_time pada '2018-04-20 10:15:56where name ='Flat Washer 8'

Sekarang seperti yang Anda lihat pada tangkapan layar di atas, kueri mengembalikan satu baris dengan nilai yang diperbarui “ListPrice ” dan nilai Product_Valid_To adalah tanggal maksimum.

Mari kita jalankan kueri lain menggunakan AS OF c lause dengan “SystemTime =09:10:56: ”.

Sekarang seperti yang Anda lihat pada tangkapan layar di atas, nilai “ListPrice ” adalah 0,00.

Dari Sampai

Klausa ini akan mengembalikan baris aktif antara dan . Untuk memahaminya, mari jalankan kueri berikut menggunakan From..To subklausa dengan “SystemTime Dari ‘2018-04-20 09:02:25’ hingga ‘2018-04-20 10:14:56 ‘”.

pilih Nama, ListPrice,rowguid,Product_Valid_From,Product_Valid_TO,ListPrice dari DemoDatabase.dbo.tblProduct FOR system_time from '2018-04-20 09:02:25 to '2018-04-20 10:13:56 di mana name ='Flat Washer 8'

Tangkapan layar berikut menunjukkan hasil kueri:

ANTARA Dan

Klausa ini mirip dengan FROM.. Ke ayat. Satu-satunya perbedaan adalah bahwa itu akan menyertakan catatan yang aktif pada . Untuk memahaminya, mari kita jalankan query berikut:

pilih Nama, ListPrice,rowguid,Product_Valid_From,Product_Valid_TO,ListPrice dari DemoDatabase.dbo.tblProduct FOR system_time antara '2018-04-20 09:02:25.1265684' dan '2018-04-20 10:13:56.1265684' di mana name ='Flat Washer 8'

Tangkapan layar berikut menunjukkan hasil kueri:

Termasuk DALAM (, )

Sub-klausul ini akan mencakup catatan yang menjadi aktif dan berakhir dalam rentang tanggal yang ditentukan. Itu tidak termasuk catatan aktif. Untuk memahaminya, jalankan kueri di bawah ini menggunakan “Contained IN ‘2018-04-20 09:02:25sampai ‘2018-04-20 10:14:56’

pilih Nama, ListPrice,rowguid,Product_Valid_From,Product_Valid_TO,ListPrice dari DemoDatabase.dbo.tblProduct FOR system_time Contained IN( '2018-04-20 09:02:25' , '2018-04-20 10:13:56 ') di mana name ='Flat Washer 8'

Tangkapan layar berikut menunjukkan hasil kueri:

Skenario

Sebuah organisasi menggunakan perangkat lunak inventaris. Perangkat lunak inventaris tersebut menggunakan tabel produk yang merupakan tabel temporal versi sistem. Karena bug aplikasi, beberapa produk dihapus, dan harga produk juga salah diperbarui.

Sebagai DBA, kami harus menyelidiki masalah ini dan memulihkan data yang salah diperbarui dan dihapus dari tabel.

Untuk mensimulasikan skenario di atas, mari buat tabel dengan beberapa data yang berarti. Saya akan membuat tabel temporal baru bernama ‘tblProduct ’ pada basis data Demo yang merupakan tiruan dari [Produksi].[Produk] tabel database AdventureWorks2014.

Untuk melakukan tugas di atas, saya telah mengikuti langkah-langkah di bawah ini:

  1. Ekstrak “buat skrip tabel” [Produksi]. [Produk] dari database AdventureWorks2014.
  2. Menghapus semua “batasan dan indeks” dari skrip.
  3. Mempertahankan struktur kolom tidak berubah.
  4. Untuk mengubahnya menjadi tabel temporal, saya menambahkan kolom SysStartTime dan SysEndTime.
  5. Mengaktifkan System_Versioning.
  6. Tabel riwayat yang ditentukan.
  7. Mengeksekusi script pada database edemo.

Berikut scriptnya:

GUNAKAN [DemoDatabase]GOCREATE TABLE [tblProduct]( [ProductID] [int] IDENTITY(1,1) Primary Key, [Name] varchar(500) NOT NULL, [ProductNumber] [nvarchar](25) NOT NULL, [Warna] [nvarchar](15) NULL, [SafetyStockLevel] [smallint] NOT NULL, [ReorderPoint] [smallint] NOT NULL, [StandardCost] [uang] NOT NULL, [ListPrice] [uang] NOT NULL, [Ukuran] [nvarchar](5) NULL, [SizeUnitMeasureCode] [nchar](3) NULL, [WeightUnitMeasureCode] [nchar](3) NULL, [Weight] [desimal](8, 2) NULL, [DaysToManufacture] [int] NOT NULL, [ProductLine] [nchar](2) NULL, [Class] [nchar](2) NULL, [Gaya] [nchar](2) NULL, [ProductSubcategoryID] [int] NULL, [ProductModelID] [int] NULL , [Tanggal Mulai Jual] [tanggalwaktu] NOT NULL, [TanggalSellEndDate] [datetime] NULL, [DiscontinuedDate] [datetime] NULL, [rowguid] [uniqueidentifier] ROWGUIDCOL NOT NULL, [ModifiedDate] [datetime] NOT NULL, Product_Valid_From datetime ROW MULAI BUKAN NULL , Product_Valid_TO datetime2 SELALU DIHASILKAN SEBAGAI BARISAN AKHIR BUKAN NULL , PERIODE UNTUK S YSTEM_TIME (Product_Valid_From,Product_Valid_TO) )DENGAN (SYSTEM_VERSIONING =ON (HISTORY_TABLE =dbo.Product_History));GO

Saya telah mengimpor data dari tabel produk database “AdventureWorks2014” ke tabel produk “DemoDatabase” dengan menjalankan skrip berikut:

masukkan ke DemoDatabase.dbo.tblProduct(Name,ProductNumber,Warna,SafetyStockLevel,ReorderPoint,StandardCost,ListPrice,Ukuran,SizeUnitMeasureCode,WeightUnitMeasureCode,Berat,HariUntukManufaktur,ProductLine,ProductLine,SellateGaya Tertanggal,Baris Tertanggal,Tanggal Modifikasi)pilih 50Nama teratas,Nomor Produk,Warna,Level Stok Keamanan,Titik Pemesanan Ulang,Biaya Standar,HargaDaftar,Ukuran,Kode UkuranUnitUkuran,Kode PengukuranUnit Berat,Berat,HariUntukManufaktur,ProdukLine,Gaya Subkategori,Lanjutan AdventureWorks2014.Production.Product

Saya menghapus catatan nama produk yang dimulai dengan 'Thin-Jam Hex Nut' dari tblProduct. Saya juga mengubah harga produk yang namanya dimulai dengan Flat Washer di ‘tblProduct ’ tabel dengan mengeksekusi query berikut:

hapus dari DemoDatabase.dbo.Product di mana nama seperti '%Thin-Jam Hex Nut%'tunggu penundaan '00:01:00'update DemoDatabase.dbo.tblProduct set ListPrice=500.00 di mana nama seperti '%Flat Washer%' 

Kami mengetahui waktu ketika data dihapus. Oleh karena itu untuk mengidentifikasi, data apa yang telah dihapus, kami akan menggunakan sub-klausa Contained-IN. Seperti yang saya sebutkan di atas, itu akan memberi saya daftar catatan yang memiliki versi baris yang menjadi aktif dan berakhir dalam rentang tanggal yang ditentukan. Kemudian, jalankan kueri di bawah ini:

deklarasikan @StartDateTime datetimedeclare @EndDateTime datetimeset @StartDateTime=convert (datetime2, getdate()-1)set @EndDateTime=convert (datetime2, getdate())pilih ProductID, Name, ProductNumber,Product_Valid_From, Product_Valid_TO dari Product For TIME DI ( @StartDateTime , @EndDateTime)

Dengan mengeksekusi kueri di atas, 22 baris telah diambil.

The Tertampung-IN klausa akan mengisi baris yang diperbarui dan dihapus selama waktu tertentu.

Mengisi data yang Dihapus:

Untuk mengisi record yang dihapus, kita harus melewati record yang telah diupdate selama waktu yang ditentukan dalam klausa Contained-IN. Dalam skrip di bawah ini, "Di mana ” akan melewatkan produk yang ada di tblProduct meja. Kami akan menjalankan kueri berikut:

deklarasikan @StartDateTime datetimedeclare @EndDateTime datetimeset @StartDateTime=convert(datetime2,getdate()-1)set @EndDateTime=convert(datetime2,getdate())pilih ProductID, Nama, ProductNumber,Product_Valid_From, Product_Valid_TO Dari SYtblProduk IN ( @StartDateTime , @EndDateTime) Dimana Nama tidak ada (Pilih Nama dari tblProduct)

Kueri di atas telah melewatkan catatan yang telah diperbarui; karenanya mengembalikan 13 baris. Lihat tangkapan layar di bawah ini:

Dengan menggunakan metode di atas, kita akan bisa mendapatkan daftar produk yang telah dihapus dari tblProduct tabel.

Mengisi catatan yang Diperbarui

Untuk mengisi catatan yang diperbarui, kita harus melewati catatan yang telah dihapus selama waktu yang ditentukan dalamContained-IN ayat. Dalam skrip di bawah ini, "Di mana ” klausa akan menyertakan produk yang ada di tblProduct meja. Kami akan menjalankan kueri berikut:

 menyatakan @StartDateTime datetimedeclare @EndDateTime datetimeset @StartDateTime=convert(datetime2,getdate()-1)set @EndDateTime=convert(datetime2,getdate())pilih ProductID, Nama, ProductNumber,Product_Valid_From, Product_Valid_To dari SYtblProduct Fortain IN ( @StartDateTime , @EndDateTime) Tempat Nama di (Pilih Nama dari tblProduct)

Kueri di atas telah melewatkan catatan yang telah diperbarui sehingga mengembalikan 9 baris. Lihat tangkapan layar di bawah ini:

Dengan menggunakan metode di atas, kita akan dapat mengidentifikasi record yang telah diperbarui dengan nilai yang salah dan record yang telah dihapus dari tabel temporal.

Ringkasan

Dalam artikel ini, saya telah membahas:

  1. Pengenalan tabel temporal tingkat tinggi.
  2. Menjelaskan, bagaimana kolom periode akan diperbarui dengan mengeksekusi kueri DML.
  3. Demo untuk mengambil daftar produk yang telah dihapus dan diperbarui dengan harga yang salah, dari tabel temporal. Laporan ini dapat digunakan untuk tujuan audit.

  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Ekspresi Tabel Umum:Kapan dan Bagaimana Menggunakannya

  2. Melihat Kinerja Cuplikan Basis Data

  3. Model Data untuk Perdagangan Saham, Dana, dan Mata Uang Kripto

  4. Bagaimana Mengurai String Seperti Pro Menggunakan Fungsi SQL SUBSTRING()?

  5. Serialisasi Penghapusan Dari Indeks Columnstore Clustered