Cần thiết: Di chuyển dữ liệu từ các cột COMPANY, OGB04, OGA01, OGA03 của bảng tạm thời sqlservertemp_table trong SQL Server sang một phiên bản Oracle được kết nối với tên ds nhằm giảm việc truy vấn không cần thiết khi lấy dữ liệu từ SQL Server.
Dưới đây là một kịch bản triển khai đầy đủ bao gồm:
- Tất cả các đối tượng cơ sở dữ liệu (bảng tạm thời, bảng trung gian, bảng nhật ký)
- Các thủ tục lưu trữ (điểm nhập chính, xử lý nội bộ, gọi bất đồng bộ)
- Mechanism xóa bỏ (xóa tự động dữ liệu cũ)
- Ví dụ về công việc SQL Agent
- Hỗ trợ gọi API Web (.NET Core ví dụ đơn giản)
Kịch Bản Triển Khai Đầy Đủ
1. Tạo Bảng Trung Gian và Bảng Nhật Ký
-- Bảng trung gian: Lưu trữ dữ liệu từ #Params để xử lý sau này
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[BảngTrungGian_Temp]') AND type in (N'U'))
CREATE TABLE dbo.BảngTrungGian_Temp (
MaSession VARCHAR(50),
CongTy VARCHAR(50),
MaOGB04 VARCHAR(100),
MaOGA01 VARCHAR(100),
MaOGA03 VARCHAR(100)
);
GO
-- Bảng nhật ký: Ghi lại thông tin thực thi đồng bộ hóa
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[NhậtKýĐồngBộ]') AND type in (N'U'))
CREATE TABLE dbo.NhậtKýĐồngBộ (
MaNhậtKý INT IDENTITY PRIMARY KEY,
MaSession VARCHAR(50),
ThờiGianBắtĐầu DATETIME,
ThờiGianKếtThúc DATETIME,
TrạngThai VARCHAR(20), -- 'ĐãBắtĐầu', 'ĐãHoànTất', 'ThấtBại'
SốDòng INT,
ThôngDiễnLỗi NVARCHAR(MAX)
);
GO
2. Thủ Tục Lưu Trữ Xử Lý Nội Bộ `ĐồngBộHoaDữLiệuNộiBộ`
-- Thủ tục: ĐồngBộHoaDữLiệuNộiBộ
-- Chức năng: Chèn dữ liệu từ bảng trung gian vào bảng tạm thời Oracle (ánh xạ trường)
IF OBJECT_ID('dbo.ĐồngBộHoaDữLiệuNộiBộ') IS NOT NULL
DROP PROCEDURE dbo.ĐồngBộHoaDữLiệuNộiBộ;
GO
CREATE PROCEDURE dbo.ĐồngBộHoaDữLiệuNộiBộ
@MaSession VARCHAR(50),
@KíchThướcMônhChia INT = 500 -- Giới hạn số lượng bản ghi chèn mỗi lần, ngăn chặn khóa bảng
AS
BEGIN
SET NOCOUNT ON;
DECLARE @ThờiGianBắtĐầu DATETIME = GETDATE();
DECLARE @SốDòng INT;
DECLARE @TênBảngOracle NVARCHAR(128) = 'TMP_' + REPLACE(CAST(NEWID() AS VARCHAR(36)), '-', '_');
DECLARE @DanhSáchCột NVARCHAR(MAX);
DECLARE @CâuSQL NVARCHAR(MAX);
BEGIN TRY
-- Tạo bảng tạm thời cấp phiên (mô phỏng tải từ bảng trung gian)
IF OBJECT_ID('tempdb..#BảngTemp') IS NOT NULL
DROP TABLE #BảngTemp;
SELECT *
INTO #BảngTemp
FROM dbo.BảngTrungGian_Temp
WHERE MaSession = @MaSession;
IF NOT EXISTS (SELECT 1 FROM tempdb.sys.tables WHERE name LIKE '#BảngTemp%')
BEGIN
THROW 50001, 'Không tìm thấy dữ liệu tương ứng với MaSession.', 1;
RETURN;
END
-- Lấy danh sách cột
SELECT @DanhSáchCột = STRING_AGG(QUOTENAME(name), ', ')
FROM tempdb.sys.columns
WHERE object_id = OBJECT_ID('tempdb..#BảngTemp');
-- Tạo bảng Oracle
IF NOT EXISTS (
SELECT 1
FROM OPENQUERY(DS, 'SELECT table_name FROM all_tables WHERE table_name = ''' + UPPER(@TênBảngOracle) + '''' )
)
BEGIN
SET @CâuSQL = 'CREATE TABLE ' + @TênBảngOracle + ' (ma_session VARCHAR2(50), ' +
STUFF((SELECT ',' + name + ' VARCHAR2(4000)'
FROM tempdb.sys.columns
WHERE object_id = OBJECT_ID('tempdb..#BảngTemp')
ORDER BY column_id
FOR XML PATH('')), 1, 1, '') + ')';
EXEC (@CâuSQL) AT DS;
END
-- Xóa dữ liệu hiện tại của session
EXEC ('DELETE FROM ' + @TênBảngOracle + ' WHERE ma_session = ''' + @MaSession + '''') AT DS;
-- Chèn dữ liệu
WHILE EXISTS(SELECT 1 FROM #BảngTemp)
BEGIN
SET @CâuSQL = '
INSERT INTO OPENQUERY(DS, ''SELECT ma_session, ' + @DanhSáchCột + ' FROM ' + @TênBảngOracle + ''')
SELECT ''' + @MaSession + ''', ' + @DanhSáchCột + '
FROM (
SELECT TOP (' + CAST(@KíchThướcMônhChia AS NVARCHAR) + ') *
FROM #BảngTemp
) AS tam';
EXEC sp_executesql @CâuSQL;
DELETE TOP (@KíchThướcMônhChia) FROM #BảngTemp;
END
SET @SốDòng = (SELECT COUNT(*) FROM BảngTrungGian_Temp WHERE MaSession = @MaSession);
INSERT INTO dbo.NhậtKýĐồngBộ (MaSession, ThờiGianBắtĐầu, ThờiGianKếtThúc, TrạngThai, SốDòng)
VALUES (@MaSession, @ThờiGianBắtĐầu, GETDATE(), 'ĐãHoànTất', @SốDòng);
END TRY
BEGIN CATCH
INSERT INTO dbo.NhậtKýĐồngBộ (MaSession, ThờiGianBắtĐầu, ThờiGianKếtThúc, TrạngThai, SốDòng, ThôngDiễnLỗi)
VALUES (@MaSession, @ThờiGianBắtĐầu, GETDATE(), 'ThấtBại', NULL, ERROR_MESSAGE());
END CATCH
END
GO
3. Thủ Tục Lưu Trữ Điểm Nhập Chính `ĐồngBộHoaDữLiệuBấtĐồngBộ`
-- Thủ tục: ĐồngBộHoaDữLiệuBấtĐồngBộ
-- Chức năng: Khởi động tác vụ chèn bất đồng bộ
IF OBJECT_ID('dbo.ĐồngBộHoaDữLiệuBấtĐồngBộ') IS NOT NULL
DROP PROCEDURE dbo.ĐồngBộHoaDữLiệuBấtĐồngBộ;
GO
CREATE PROCEDURE dbo.ĐồngBộHoaDữLiệuBấtĐồngBộ
@MaSession VARCHAR(50) = NULL OUTPUT
AS
BEGIN
SET NOCOUNT ON;
IF OBJECT_ID('tempdb..#ThôngSố') IS NULL
BEGIN
THROW 50001, '#ThôngSố bảng tạm thời không tồn tại, vui lòng tạo trước khi gọi thủ tục này.', 1;
RETURN;
END
IF @MaSession IS NULL
SET @MaSession = REPLACE(CAST(NEWID() AS VARCHAR(36)), '-', '_');
-- Sao chép #ThôngSố vào bảng trung gian toàn cục
IF OBJECT_ID('tempdb..#ThôngSốToànCục') IS NOT NULL
DROP TABLE #ThôngSốToànCục;
SELECT @MaSession AS MaSession, * INTO #ThôngSốToànCục FROM #ThôngSố;
INSERT INTO dbo.BảngTrungGian_Temp
SELECT * FROM #ThôngSốToànCục;
-- Khởi động công việc SQL Agent (ví dụ cách thay thế tham số)
EXEC msdb.dbo.sp_start_job @job_name = 'ĐồngBộHoaDữLiệuCôngViec',
@step_name = 'Chạy ThủTụcNộiBộ',
@input_parameters = N'@MaSession=''' + @MaSession + '''';
SELECT @MaSession AS MaSession;
END
GO
4. Công Việc Dọn Dẹp Định Thời (SQL Server Agent Job hoặc Script Công Việc)
Tạo Thủ Tục Dọn Dẹp
-- Xóa dữ liệu session quá hạn (ví dụ như sau 1 giờ)
IF OBJECT_ID('dbo.DọnDẹpSessionCu') IS NOT NULL
DROP PROCEDURE dbo.DọnDẹpSessionCu;
GO
CREATE PROCEDURE dbo.DọnDẹpSessionCu
AS
BEGIN
SET NOCOUNT ON;
-- Xóa dữ liệu nhật ký sau 1 giờ
DELETE FROM dbo.NhậtKýĐồngBộ
WHERE ThờiGianBắtĐầu < DATEADD(HOUR, -1, GETDATE());
-- Xóa dữ liệu từ bảng trung gian quá hạn
DELETE btg
FROM dbo.BảngTrungGian_Temp btg
LEFT JOIN dbo.NhậtKýĐồngBộ nk ON btg.MaSession = nk.MaSession
WHERE nk.MaSession IS NULL
AND btg.MaSession IN (
SELECT MaSession
FROM dbo.NhậtKýĐồngBộ
WHERE ThờiGianBắtĐầu < DATEADD(HOUR, -1, GETDATE())
);
END
GO
Hỗ Trợ Gọi API Web (Ví dụ .NET Core)
Giả sử bạn sử dụng .NET Core để tương tác với SQL Server, dưới đây là một ví dụ đơn giản về controller:
[ApiController]
[Route("api/[controller]")]
public class ĐồngBộController : ControllerBase
{
private readonly string _chuỗiKếtNối;
public ĐồngBộController(IConfiguration cấuHình)
{
_chuỗiKếtNối = cấuHình.GetConnectionString("MặcĐịnh");
}
[HttpPost("bắtđầu")]
public async Task<IActionResult> BắtĐầuBấtĐồngBộ([FromBody] YêuCầuThôngSố yêuCầu)
{
var maSession = Guid.NewGuid().ToString();
using (var kếtNối = new SqlConnection(_chuỗiKếtNối))
{
await kếtNối.MởAsync();
// Tạo bảng #ThôngSố và chèn dữ liệu
using (var lệnh = new SqlCommand())
{
lệnh.KếtNối = kếtNối;
lệnh.CâuTruyVấn = $@"
CREATE TABLE #ThôngSố (CongTy VARCHAR(50), MaOGB04 VARCHAR(100), MaOGA01 VARCHAR(100), MaOGA03 VARCHAR(100));
INSERT INTO #ThôngSố (CongTy, MaOGB04, MaOGA01, MaOGA03)
VALUES {string.Join(",", yêuCầu.BảnGhi.Select(r => $"'{r.CôngTy}','{r.MaOGB04}','{r.MaOGA01}','{r.MaOGA03}'"))};
EXEC dbo.ĐồngBộHoaDữLiệuBấtĐồngBộ @MaSession OUTPUT;
";
lệnh.ThamSố.Add(new SqlParameter("@MaSession", SqlDbType.VarChar, 50) { Hướng = ParameterDirection.Output });
await lệnh.ThựcThiNonQueryAsync();
var maSessionĐầuRa = lệnh.ThamSố["@MaSession"].GiáTri?.ToString() ?? maSession;
return Ok(new { MaSession = maSessionĐầuRa });
}
}
}
[HttpGet("trạngthái/{maSession}")]
public async Task<IActionResult> LấyTrạngThái(string maSession)
{
using (var kếtNối = new SqlConnection(_chuỗiKếtNối))
{
var nhậtKý = await kếtNối.TruyVấnFirstOrDefaultAsync(
"SELECT * FROM dbo.NhậtKýĐồngBộ WHERE MaSession = @MaSession",
new { MaSession = maSession });
return Ok(nhậtKý);
}
}
}
public class YêuCầuThôngSố
{
public List BảnGhi { get; set; }
}
public class BảnGhiThôngSố
{
public string CôngTy { get; set; }
public string MaOGB04 { get; set; }
public string MaOGA01 { get; set; }
public string MaOGA03 { get; set; }
}
public class NhậtKýĐồngBộ
{
public int MaNhậtKý { get; set; }
public string MaSession { get; set; }
public DateTime ThờiGianBắtĐầu { get; set; }
public DateTime? ThờiGianKếtThúc { get; set; }
public string TrạngThai { get; set; }
public int? SốDòng { get; set; }
public string ThôngDiễnLỗi { get; set; }
}