Khôi phục dữ liệu sau khi xóa trong SQL Server

--Tạo một DBName mới
USE master
GO
IF DB_ID('TestDB') IS NOT NULL
DROP DATABASE TestDB
GO
CREATE DATABASE TestDB
GO


--Tạo 1 bảng mới trong DB vừa tạo
USE TestDB
GO
CREATE TABLE dbo.Table1(ID INT IDENTITY, Ten VARCHAR(30) )
GO
INSERT INTO dbo.Table1(Ten)
SELECT 'Nguyen Van A' UNION ALL
SELECT 'Nguyen Van B' UNION ALL
SELECT 'Nguyen Van C'
GO


--Thực hiện full backup: lúc 2:52 ph
BACKUP DATABASE TestDB TO DISK = 'D:\Temp\TestDB.bak' WITH INIT
GO


--Thêm dữ liệu mới sau khi full backup: 3h15
INSERT INTO dbo.Table1(Ten)
SELECT 'Nguyen Van D'
UNION ALL
SELECT 'Nguyen Van E'
GO


--Thời điểm nào đó nhỡ tay xóa nhầm dữ liệu: 3h18
DELETE FROM dbo.Table1
GO


--Đóng kết nói DB (không cho ai connect ngoài mình ra, để đảm bảo k có cập nhật gì tới db)
ALTER DATABASE TestDB SET SINGLE_USER WITH ROLLBACK IMMEDIATE
GO
--Sau đó ghi lại thời điểm xảy ra sự cố: 2011-06-15 15:12:28.950
SELECT GETDATE()
GO


--Việc tiếp theo là backup log:
BACKUP LOG TestDB TO DISK = 'D:\Temp\TestDB.trn' WITH INIT
GO


--Sau đó khôi phục lại database theo thứ tự bản full backup trước rồi đến bản log backup:
USE master
GO
RESTORE DATABASE TestDB FROM DISK = 'D:\Temp\TestDB.bak' WITH NORECOVERY –dòng này nhớ chạy nhớ chờ 1 lúc cho xong mới chạy dòng tiếp theo:
GO
RESTORE DATABASE TestDB FROM DISK = 'D:\Temp\TestDB.trn' WITH STOPAT='2011-06-15 15:16:00'
GO


--Giờ thì select xem đã lấy được dữ liệu chưa nhé?
SELECT * FROM Table1


--Bước cuối cùng là chuyển lại database sang chế độ bình thường
ALTER DATABASE TestDB SET MULTI_USER


Cách dùng hàm Copmute By trong SQL

Hàm COMPUTE [BY] dùng để tính toán dựa trên các hàm tập hợp và thêm kết quả vào dòng cuối cùng của bảng (hoặc dòng cuối cùng của mỗi nhóm dữ liệu).

Và chú ý là:
- Khi sử dụng COMPUTE có BY thì phải có phần ORDER BY
- Các cột sử dụng trong BY phải có mặt trong phần ORDER BY

Ví dụ 1

Hiển thị danh sách sản phẩm, và tính tổng số sản phẩm tìm được

[code]SELECT * FROM Suppliers COMPUTE count(*)

Ví dụ 2

Hiển thị danh sách sản phẩm và tính tổng số sản phẩm của từng nhà cung cấp
Code:
SELECT * FROM Suppliers ORDER BY SupplierID COMPUTE count(*) BY SupplierID

Hàm RANK / DENSE_RANK / NTILE

Hàm RANK


SELECT RANK() OVER (ORDER BY airport_code) AS [Rank by airport_code],airport_code
FROM lohref_regions


  • Tất cả những airport nào có giá trị giống nhau sẽ đánh cu`ng 1 số,
  • Ví dụ có 2 airport=’’ thì:
[Rank by airport_code] [airport_code]
1 ‘’
1 ‘’
2 ‘hello’


Hàm DENSE_RANK

Hàm DENSE_RANK cũng giống như hàm RANK, tuy vậy, hàm này không cung cấp khoảng cách giữa các số xếp loại. Thay vào đó, hàm này sẽ xếp loại liên tục cho từng giá trị ORDER BY cụ thể. Với hàm DENSE_RANK, kể cả khi có hai dòng có cùng giá trị xếp loại thì dòng tiếp theo vẫn chỉ tăng thêm một giá trị so với dòng trên. Hàm DENSE_RANK có cú pháp như hàm RANK.

Đây là hàm DENSE_RANK được tôi sử dụng để xếp loại cho toàn bộ các bản ghi trong bảng Person theo trường Age
SELECT DENSE_RANK() OVER (ORDER BY Age) AS [Dense Rank by Age],
FirstName,
Age
FROM Person
Đoạn mã trên sẽ xuất ra như sau:
Dense Rank by Age FirstName Age
-------------------- ---------- -----------
1 Larry 5
2 Doris 6
2 George 6
3 Mary 11
3 Sherry 11
4 Sam 17
5 Ted 23
5 Marty 23
6 Sue 29
7 Frank 38
8 John 40
Như bạn thấy các số trong cột “Dense Rank By Age” vẫn đảm bảo tính liên tục, không hề bị ngắt quãng kể cả khi có hai dòng cùng giá trị ORDER BY và giá trị xếp loại như Ted và Marty.


Hàm NTILE

Hàm cuối cùng là hàm NTILE. Đây là hàm được sử dụng để phá vỡ tập hợp bản ghi trong một số cụ thể của các nhóm. Hàm NTILE cũng sử dụng cú pháp như các hàm ranking khác.

Trong ví dụ đầu của hàm này, tôi sẽ nhóm các bản ghi trong bảng Person thành 3 nhóm khác nhau. Tôi muốn các nhóm này dựa trên cột Age. Để làm được điều này, tôi sẽ chạy T-SQL sau:
SELECT FirstName,
Age,
NTILE(3) OVER (ORDER BY Age) AS [Age Groups]
FROM Person
Đây là tập hợp kết quả của tôi từ câu lệnh T-SQL trên:
FirstName Age Age Groups
---------- ----------- --------------------
Larry 5 1
Doris 6 1
George 6 1
Mary 11 1
Sherry 11 2
Sam 17 2
Ted 23 2
Marty 23 2
Sue 29 3
Frank 38 3
John 40 3
Trong tập hợp kết quả đã có ở trên với 3 nhóm Age khác nhau. Nhóm đầu tiên bắt đầu từ 5 đến 11 tuổi, nhóm thứ 2 bắt đầu từ 11 đến 23 và nhóm cuối cùng là từ 29 đến 40. Hàm NTILE chỉ có tác dụng chia đều số lượng các bản ghi và đưa vào từng nhóm số. Sử dụng hàm NTILE cho từng bản ghi trong một nhóm sẽ đưa gia các xếp loại giống nhau.

Hàm NTILE là một hàm rất có ích nếu bạn chỉ muốn trả lại một nhóm cụ thể trong các bản ghi. Dưới đây là một ví dụ khi tôi muốn trả lại chỉ nhóm người có độ tuổi chung bình (Nhóm Age 2) từ ví dụ trên.
SELECT FirstName,
Age,
Age AS [Age Group]
FROM ( SELECT FirstName,
Age,
NTILE(3) OVER (ORDER BY Age) AS AgeGroup
FROM Person) A
WHERE AgeGroup = 2
Kết quả của câu lệnh trên:
FirstName Age Age Group
---------- ----------- -----------
Sherry 11 11
Sam 17 17
Ted 23 23
Marty 23 23

XÓA 1 BẢN GHI TRONG KHI 2 BẢN GHI GIỐNG HỆT NHAU VỀ CỘT, KHÔNG THỂ PH N BIỆT BẰNG ID bằng ROW_NUMBER()

WITH [CTE DUPLICATE] AS
(
SELECT
RN = ROW_NUMBER() OVER (PARTITION BY airport_code ORDER BY airport_code DESC)
FROM lohref_regions
where ([Country name] like '%Viet Nam%' or [Country_name] like '%Viet Nam%')
and city_name like '%hanoi%'
)
DELETE FROM [CTE DUPLICATE] WHERE RN = 1


  • có thể thay delete bằng select,…
  • PARTITION BY, ORDER BY bất kỳ cột nào

Hàm ROW_NUMBER không chỉ cho phép bạn sắp xếp toàn bộ tập hợp dòng mà còn có thể sử dụng mệnh đề PARTITION để lọc ra nhóm dòng cần đánh số. Các dòng sẽ được đánh số tuần tự trong từng giá trị PARTITION độc nhất. Các dãy số được đánh sẽ luôn bắt đầu từ 1 cho từng giá trị PARTITION mới trong tập hợp bản ghi của bạn