Database
 sql >> Baza danych >  >> RDS >> Database

Wykonywanie audytu zmian danych przy użyciu tabeli czasowej

SQL Server 2016 wprowadził funkcję o nazwie „Tabela czasowa w wersji systemowej”. Używając normalnej tabeli, możesz pobrać aktualne dane; podczas korzystania z tabeli czasowej z wersjonowaniem systemu można odzyskać dane, które zostały usunięte lub zaktualizowane w przeszłości. Aby to zrobić, tabela czasowa utworzy tabelę historii. Tabela historii będzie przechowywać stare dane z „czas_początku ” i „czas_zakończenia ”. Co wskazuje okres czasu, przez który rekord był aktywny.

Przykład:Jeśli zaktualizujesz cenę produktu z 30 do 50, wysyłając zapytanie do normalnej tabeli, możesz pobrać zaktualizowaną cenę produktu, która wynosi 50. Używając tabeli tymczasowej, możesz pobrać starą wartość, która wynosi 30.

Korzystając z tabel czasowych można wykonać:

  1. Śledź historię rekordu :możemy przejrzeć wartość konkretnego rekordu, która zmieniła się w czasie.
  2. Odzyskiwanie na poziomie rekordu :jeśli usunęliśmy określony rekord z tabeli lub rekord jest uszkodzony, możemy go pobrać z tabeli historii.

Tabele czasowe rejestrują datę i godzinę rekordu na podstawie dat fizycznych (daty kalendarza) aktualizacji i usunięcia rekordu. Obecnie nie obsługuje wersjonowania na podstawie dat logicznych. Na przykład, jeśli zaktualizujesz nazwę produktu za pomocą instrukcji UPDATE o godzinie 13:00, tabela czasowa będzie przechowywać historię nazwy produktu do godziny 13:00. Po tym będzie obowiązywać nowa nazwa. Co jednak, jeśli zmiana nazwy produktu miała rozpocząć się od godziny 14:00? Oznacza to, że musisz idealnie zaktualizować oświadczenie na czas, aby działało, i powinieneś wykonać instrukcję UPDATE o 14:00 zamiast o 13:00.

Tabele czasowe mają następujące wymagania wstępne:

  1. Należy zdefiniować klucz podstawowy.
  2. Należy zdefiniować dwie kolumny, aby rejestrować czas rozpoczęcia i czas zakończenia z typem danych datetime2. Te kolumny są nazywane kolumnami SYSTEM_TIME.

Mają też pewne ograniczenia:

  1. Wyzwalacze INSTEAD OF i OLTP w pamięci są niedozwolone.
  2. Tabele historii nie mogą mieć żadnego ograniczenia.
  3. Danych w tabeli historii nie można modyfikować.

Tworzenie tabeli z wersjonowaniem systemu

Poniższy skrypt zostanie użyty do utworzenia prostej tabeli z wersjami systemowymi:

Użyj DemoDatabaseGoCREATE TABLE dbo.Prodcuts ( Product_ID int identity (1,1) klucz podstawowy , Product_Name varchar (500) , Product_Cost int , Quantity int , Product_Valid_From datetime2 NOT NULL , OKRES DLA SYSTEM_TIME (Product_Valid_From,Product_Valid_TO)) Z (SYSTEM_VERSIONING =ON (HISTORY_TABLE =dbo.Product_Change_History));

W powyższym skrypcie zdefiniowałem HISTORY_TABLE o nazwie dbo. Product_Change_Historia. Jeśli nie określisz nazwy tabeli historii, SQL Server automatycznie utworzy tabelę historii o następującej strukturze.

Dbo.MSSQL_TemporalHistoryFor_xxx, gdzie xxx to identyfikator obiektu.

Tabela czasowa będzie wyglądać tak, jak pokazano na poniższym zrzucie ekranu:

W jaki sposób zostaną zaktualizowane kolumny okresu podczas wykonywania instrukcji DML w tabeli czasowej?

Za każdym razem, gdy wykonujemy wstawianie, aktualizowanie i usuwanie zapytania w tabeli czasowej, kolumny okresu (SysStartDate i SysEndDate) zostaną zaktualizowane.

Wstaw zapytanie

Kiedy wykonujemy operację INSERT na tabeli czasowej, system ustawia wartość kolumny SysStartTime na czas rozpoczęcia bieżącej transakcji i oznacza wiersz jako otwarty.

Wstawmy kilka wierszy w „Produkty ’ i sprawdź, jak dane są przechowywane w tej tabeli.

WSTAW DO produktów (nazwa_produktu, koszt_produktu, ilość) WARTOŚCI ( 'Mysz', 500, 10 ), ( 'Klawiatura', 200, 5 ), ( 'Zestaw słuchawkowy', 500, 1 ), ( 'Laptop' , 50000, 1 ) wybierz * z produktów

Jak pokazano na powyższym zrzucie ekranu, wartość „Product_Valid_From Kolumna to „2018-04-02 06:55:04.4865670 ’, który jest datą wstawienia wiersza. Oraz wartość „Product_Valid_To” ” kolumna to „9999-12-31 23:59:59,9999999 ’, co oznacza, że ​​wiersz jest otwarty.

Zaktualizuj zapytanie

Kiedy wykonujemy dowolne zapytanie aktualizujące w tabeli tymczasowej, system zapisze wartości poprzedniego wiersza w tabeli historii i ustawi bieżący czas transakcji jako EndTime i zaktualizuj bieżącą tabelę o nową wartość. SysStartTime będzie godzina rozpoczęcia transakcji i SysEndTime będzie maksymalny 9999-12-31.

Zmieńmy koszt produktu „Mysz ’ od 500 do 250. Sprawdzimy wynik ‘Produkt „.

Rozpocznij transakcję UpdatePriceUpdate Prodcuts set Product_cost=200 gdzie Product_name='Mysz'Potwierdź trans UpdatePriceselect * z Prodcuts gdzie Product_name='Mysz'

Jak widać na powyższym zrzucie ekranu, wartość „Product_Valid_From Kolumna została zmieniona. Nowa wartość to aktualny czas transakcji (UTC). Oraz wartość „Product_Valid_To” ” to kolumna „9999-12-31 23:59:59,9999999 ”, co oznacza, że ​​wiersz jest otwarty i zaktualizował cenę.

Przyjrzyjmy się wynikom Product_change_history tabeli, wysyłając zapytanie.

wybierz * z Product_Change_History, gdzie Product_name='Mysz'

Jak widać na powyższym zrzucie ekranu, wiersz został dodany w Historia_zmiany_produktu tabela, która ma starą wersję wiersza. Wartość „Koszt_produktu ” to 500, wartość „Product_valid_From ’ to czas wstawienia rekordu i wartość Product_Valid_To kolumna to wartość kolumny Product_cost został zaktualizowany. Ta wersja wiersza jest uważana za zamkniętą.

Usuń zapytanie

Kiedy usuniemy rekord z tabeli tymczasowej, system przechowa bieżącą wersję wiersza w tabeli historii i ustawi bieżący czas transakcji jako EndTime i usunie rekord z bieżącej tabeli.

Usuńmy rekord „zestawu słuchawkowego”.

Rozpocznij usuwanie DeletePrice z produktów, gdzie product_name='Headset'Zatwierdź trans DeletePrice

Przyjrzyjmy się wynikom Product_change_history tabeli, wysyłając zapytanie.

wybierz * z Product_Change_History, gdzie Product_name='Zestaw słuchawkowy'

Jak widać na powyższym zrzucie ekranu, wiersz został dodany w Historia_zmiany_produktu tabela, która została usunięta z bieżącej tabeli. Wartość „Produkt_ważny_Od ’ to czas wstawienia rekordu i wartość Product_Valid_To kolumna to czas, w którym wiersz został usunięty, co oznacza, że ​​wersja wiersza jest zamknięta.

Kontrola zmian danych w określonym czasie

Aby przeprowadzić audyt zmian danych dla określonej tabeli, powinniśmy przeprowadzić analizę czasową tabel czasowych. Aby to zrobić, musimy użyć „FOR SYSTEM_TIME ’ klauzula z poniższymi podklauzulami specyficznymi dla czasu do danych zapytania w tabelach bieżących i historycznych. Pozwólcie, że wyjaśnię wynik zapytań przy użyciu różnych podrozdziałów. Poniżej znajduje się konfiguracja:

  1. Wstawiłem produkt o nazwie „Płaska podkładka 8” z ceną katalogową 0,00 w tabeli czasowej o 09:02:25.
  2. Zmieniłem cenę katalogową o 10:13:56. Nowa cena to 500,00.

OD

Ta klauzula zostanie użyta do pobrania stanu rekordów dla danego czasu w AS OF podpunkt. Aby to zrozumieć, wykonajmy kilka zapytań:

Najpierw wykonamy zapytanie za pomocą AS OF klauzula z „SystemTime =10:15:59 ”.

wybierz Name, ListPrice,rowguid,Product_Valid_From,Product_Valid_TO z DemoDatabase.dbo.tblProduct FOR system_time na dzień „2018-04-20 10:15:56where name =„Płaska podkładka 8”

Teraz, jak widać na powyższym zrzucie ekranu, zapytanie zwróciło jeden wiersz ze zaktualizowaną wartością „ListPrice ” i wartość Product_Valid_To to maksymalna data.

Wykonajmy kolejne zapytanie, używając AS OF c lause z „SystemTime =09:10:56: ”.

Teraz, jak widać na powyższym zrzucie ekranu, wartość „ListPrice ” to 0,00.

Od do

Ta klauzula zwróci wiersze aktywne między i . Aby to zrozumieć, wykonaj następujące zapytanie za pomocą Od...Do podklauzula z „SystemTime Od ‘2018-04-20 09:02:25’ do ‘2018-04-20 10:14:56 „”.

 wybierz Name, ListPrice,rowguid,Product_Valid_From,Product_Valid_TO,ListPrice z DemoDatabase.dbo.tblProduct FOR system_time od „2018-04-20 09:02:25 do „2018-04-20 10:13:56 gdzie nazwa =„Płaska podkładka 8”

Poniższy zrzut ekranu przedstawia wynik zapytania:

POMIĘDZY i

Ta klauzula jest podobna do OD... Do klauzula. Jedyną różnicą jest to, że będzie zawierał rekordy, które były aktywne w . Aby to zrozumieć, wykonajmy następujące zapytanie:

 wybierz Name, ListPrice,rowguid,Product_Valid_From,Product_Valid_TO,ListPrice z DemoDatabase.dbo.tblProduct FOR system_time między „2018-04-20 09:02:25.1265684” a „2018-04-20 10:13:56.1265684” gdzie name =„Płaska podkładka 8”

Poniższy zrzut ekranu przedstawia wynik zapytania:

Wliczone w (, )

Ta podklauzula będzie zawierać rekordy, które stały się aktywne i zakończyły się w określonym zakresie dat. Nie obejmuje aktywnych rekordów. Aby to zrozumieć, wykonaj poniższe zapytanie, używając „Zawarte w ‘2018-04-20 09:02:25do ‘2018-04-20 10:14:56’

wybierz Name, ListPrice,rowguid,Product_Valid_From,Product_Valid_TO,ListPrice z DemoDatabase.dbo.tblProduct FOR system_time zawarte w ( '2018-04-20 09:02:25' , '2018-04-20 10:13:56 ') gdzie name ='Płaska Podkładka 8'

Poniższy zrzut ekranu przedstawia wynik zapytania:

Scenariusz

Organizacja korzysta z oprogramowania do inwentaryzacji. To oprogramowanie inwentaryzacyjne wykorzystuje tabelę produktów, która jest tabelą czasową wersji systemu. Z powodu błędu aplikacji kilka produktów zostało usuniętych, a ceny produktów również niewłaściwie zaktualizowane.

Jako administratorzy baz danych musimy zbadać ten problem i odzyskać dane, które zostały błędnie zaktualizowane i usunięte z tabeli.

Aby zasymulować powyższy scenariusz, stwórzmy tabelę z pewnymi znaczącymi danymi. Zamierzam utworzyć nową tabelę czasową o nazwie „tblProduct ’ w bazie danych Demo, która jest klonem [Produkcja].[Produkty] tabela bazy danych AdventureWorks2014.

Aby wykonać powyższe zadanie, wykonałem poniższe kroki:

  1. Wyodrębnione „utwórz skrypt tabeli” [Produkcja]. [Produkty] z bazy danych AdventureWorks2014.
  2. Usunięto wszystkie „ograniczenia i indeksy” ze skryptu.
  3. Zachowaj niezmienioną strukturę kolumn.
  4. Aby przekonwertować go na tabelę czasową, dodałem kolumny SysStartTime i SysEndTime.
  5. Włączone System_Versioning.
  6. Określona tabela historii.
  7. Wykonał skrypt w bazie danych edemo.

Poniżej znajduje się skrypt:

 USE [DemoDatabase] GOCREATE TABLE [tblProduct]( [ProductID] [int] IDENTITY (1,1) Klucz podstawowy, [Name] varchar(500) NOT NULL, [ProductNumber] [nvarchar](25) NOT NULL, [Color] [nvarchar](15) NULL, [SafetyStockLevel] [smallint] NOT NULL, [ReorderPoint] [smallint] NOT NULL, [StandardCost] [money] NOT NULL, [ListPrice] [money] NOT NULL, [Size] [nvarchar](5) NULL, [SizeUnitMeasureCode] [nchar](3) NULL, [WeightUnitMeasureCode] [nchar](3) NULL, [Waga] [dziesiętny](8, 2) NULL, [DaysToManufacture] [int] NOT NULL, [ProductLine] [nchar](2) NULL, [Klasa] [nchar](2) NULL, [Styl] [nchar](2) NULL, [ProductSubcategoryID] [int] NULL, [ProductModelID] [int] NULL , [SellStartDate] [datetime] NOT NULL, [SellEndDate] [datetime] NULL, [DiscontinuedDate] [datetime] NULL, [rowguid] [unikalny identyfikator] ROWGUIDCOL NOT NULL, [ModifiedDate] [datetime] NOT NULL, Product_Valid_From datetime2 ZAWSZE GENEROWANE ROW START NOT NULL , Product_Valid_TO datetime2 GENEROWANY ZAWSZE JAKO ROW END NOT NULL , OKRES DLA S YSTEM_TIME (Product_Valid_From,Product_Valid_TO) )Z (SYSTEM_VERSIONING =ON (HISTORY_TABLE =dbo.Product_History));GO

Zaimportowałem dane z tabeli produktów bazy danych „AdventureWorks2014” do tabeli produktów „DemoDatabase”, wykonując następujący skrypt:

wstaw w DemoDatabase.dbo.tblProdukt(Nazwa,Numer produktu,Kolor,BezpieczeństwoPoziom zapasów,ReorderPoint,Standardowy koszt,ListCena,Rozmiar,RozmiarJednostkaKod pomiaru,Waga,Dni produkcji,Produkt,Klasa,Styl,ProduktRozpoczęcieID,SprzedażDedModel,Date ,rowguid,Data modyfikacji)select top 50Nazwa,Numer produktu,Kolor,Poziom bezpieczeństwa,Punkt zmiany kolejności,Koszt standardowy,Cena na liście,Rozmiar,RozmiarJednostkaKod miary,WagaJednostkaKod miary,Waga,Dni produkcji,Linia produktów,Klasa,Styl,ID podkategorii produktu,Data daty produktu,Dane,Sprzedaż AdventureWorks2014.Produkcja.Produkt

Usunąłem rekordy nazwy produktu, które zaczynają się od „Thin-Jam Hex Nut” z tblProduct. Zmieniłem również cenę produktów, których nazwy zaczynają się od Flat Washer w „tblProduct ’, wykonując następujące zapytanie:

usuń z DemoDatabase.dbo.Produkt, gdzie nazwa taka jak '%Thin-Jam Hex Nut%'czekaj na opóźnienie '00:01:00'zaktualizuj DemoDatabase.dbo.tblZestaw produktów ListPrice=500.00 gdzie nazwa taka jak '%Flat Washer%' 

Mamy świadomość, kiedy dane zostały usunięte. Stąd w celu zidentyfikowania, jakie dane zostały usunięte, posłużymy się podpunktem Zawarte-IN. Jak wspomniałem powyżej, otrzymam listę rekordów, które mają wersje wierszy, które stały się aktywne i zakończyły się w określonym zakresie dat. Następnie wykonaj poniższe zapytanie:

declare @StartDateTime datetimedeclare @EndDateTime datetimeset @StartDateTime=convert (datetime2, getdate()-1)set @EndDateTime=convert (datetime2, getdate())select ProductID, Name, ProductNumber, Product_Valid_From, Product_Valid_To z produktu dla SYSTEM_TIME zawarte IN ( @StartDateTime , @EndDateTime)

Wykonując powyższe zapytanie, pobrano 22 wiersze.

Zawarty-IN klauzula wypełni wiersze, które zostały zaktualizowane i usunięte w określonym czasie.

Wypełnij usunięte rekordy:

Aby wypełnić usunięte rekordy, musimy pominąć rekordy, które zostały zaktualizowane w czasie określonym w klauzuli Contained-IN. W poniższym skrypcie „Gdzie ” klauzula pominie produkty, które są obecne w tblProduct stół. Wykonamy następujące zapytanie:

declare @StartDateTime datetimedeclare @EndDateTime datetimeset @StartDateTime=convert(datetime2,getdate()-1)set @EndDateTime=convert(datetime2,getdate())select ProductID, Name, ProductNumber, Product_Valid_From, Product_Valid_To z tblProduct Contained For SYSTEM_TIME IN ( @StartDateTime , @EndDateTime) Gdzie nie ma nazwy (wybierz nazwę z tblProduct)

Powyższe zapytanie pominęło rekordy, które zostały zaktualizowane; stąd zwrócił 13 wierszy. Zobacz poniższy zrzut ekranu:

Korzystając z powyższej metody, będziemy mogli uzyskać listę produktów, które zostały usunięte z tblProduct tabela.

Wypełnij zaktualizowane rekordy

Aby wypełnić zaktualizowane rekordy, musimy pominąć rekordy, które zostały usunięte w czasie określonym w Zawarte-IN klauzula. W poniższym skrypcie „Gdzie ” klauzula będzie obejmować produkty, które są obecne w tblProduct stół. Wykonamy następujące zapytanie:

 define @StartDateTime datetimedeclare @EndDateTime datetimeset @StartDateTime=convert(datetime2,getdate()-1)set @EndDateTime=convert(datetime2,getdate())select ProductID, Name, ProductNumber, Product_Valid_From, Product_Valid_To z tblProduct dla SYSTEM_TIME zawarte IN ( @StartDateTime , @EndDateTime) Gdzie Nazwa w (Wybierz nazwę z tblProduct)

Powyższe zapytanie pominęło rekordy, które zostały zaktualizowane, stąd zwróciło 9 wierszy. Zobacz poniższy zrzut ekranu:

Korzystając z powyższej metody, będziemy w stanie zidentyfikować rekordy, które zostały zaktualizowane o nieprawidłowe wartości oraz rekordy, które zostały usunięte z tabeli czasowej.

Podsumowanie

W tym artykule omówiłem:

  1. Wprowadzenie wysokiego poziomu tabel czasowych.
  2. Wyjaśniono, w jaki sposób kolumny okresu będą aktualizowane przez wykonywanie zapytań DML.
  3. Demo do pobrania listy produktów, które zostały usunięte i zaktualizowane z niewłaściwą ceną, z tabeli tymczasowej. Ten raport może być wykorzystany do celów audytu.

  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Jak zainstalować Kubernetes za pomocą Kubeadm

  2. Wszystko, co musisz wiedzieć o operatorze LIKE w SQL

  3. Były dyrektor Capgemini, Sunitha Ray, dołącza do ScaleGrid DBaaS w celu rozszerzenia sprzedaży korporacyjnej

  4. Jaki jest najszybszy sposób obliczenia mediany?

  5. Synchronizacja struktury bazy danych między aplikacjami