- sql/01_sync_queue.sql: idempotent DDL for dbo.SyncQueue (PK + unique
dedup index + pending lookup index), safe to re-run.
- sql/02_sync_apply.sql: dbo.usp_SyncApply (@MaxRetries INT=5). Per
distinct (TargetSchema,TargetTable) it builds column projections from
sys.columns (excludes ID key/computed/identity/rowversion) and runs a
dynamic-SQL MERGE (last-write-wins via ROW_NUMBER over SourceLogID DESC)
for Insert/Update plus a DELETE for the last op = Delete.
SET IDENTITY_INSERT ON preserves Access PKs.
- tests/conftest.py: sql_conn fixture reads conn_str from gitignored
config.yaml via load_config; skipped without RUN_INTEGRATION=1.
- tests/test_apply_proc.py: integration test covering IDENTITY-preserving
INSERT, last-write-wins UPDATE, BIT conversion, and DELETE; cleans up.
Deviation from the brief's procedure (root-cause fix, design preserved):
every JSON path key is quoted ('$."col"') so non-ASCII column names
(e.g. Chinese 名字/数量) parse correctly. Without quoting, JSON_VALUE
raises "JSON path format is not correct" on Chinese columns, which is the
real target schema for this Access->SQL Server sync.
Co-Authored-By: Claude <noreply@anthropic.com>
43 lines
1.7 KiB
Transact-SQL
43 lines
1.7 KiB
Transact-SQL
-- SyncQueue: staging table for the Access -> SQL Server one-way sync.
|
|
-- Idempotent: safe to re-run (table created only if absent; indexes only if absent).
|
|
|
|
IF OBJECT_ID('dbo.SyncQueue', 'U') IS NULL
|
|
BEGIN
|
|
CREATE TABLE dbo.SyncQueue (
|
|
QueueID bigint IDENTITY(1,1) NOT NULL,
|
|
SourceFile nvarchar(255) NOT NULL,
|
|
SourceTable nvarchar(255) NOT NULL,
|
|
SourceLogID bigint NOT NULL,
|
|
TargetSchema nvarchar(128) NOT NULL,
|
|
TargetTable nvarchar(255) NOT NULL,
|
|
RecordID nvarchar(50) NOT NULL,
|
|
OperateType varchar(10) NOT NULL,
|
|
RowData nvarchar(max) NULL,
|
|
Status varchar(10) NOT NULL CONSTRAINT DF_SyncQueue_Status DEFAULT 'pending',
|
|
RetryCount int NOT NULL CONSTRAINT DF_SyncQueue_Retry DEFAULT 0,
|
|
ErrorMsg nvarchar(max) NULL,
|
|
CapturedAt datetime2 NOT NULL CONSTRAINT DF_SyncQueue_Captured DEFAULT sysdatetime(),
|
|
AppliedAt datetime2 NULL,
|
|
CONSTRAINT PK_SyncQueue PRIMARY KEY CLUSTERED (QueueID)
|
|
);
|
|
END
|
|
GO
|
|
|
|
IF NOT EXISTS (SELECT 1 FROM sys.indexes
|
|
WHERE name = 'UX_SyncQueue_Dedup'
|
|
AND object_id = OBJECT_ID('dbo.SyncQueue'))
|
|
BEGIN
|
|
CREATE UNIQUE INDEX UX_SyncQueue_Dedup
|
|
ON dbo.SyncQueue(SourceFile, SourceTable, SourceLogID);
|
|
END
|
|
GO
|
|
|
|
IF NOT EXISTS (SELECT 1 FROM sys.indexes
|
|
WHERE name = 'IX_SyncQueue_Pending'
|
|
AND object_id = OBJECT_ID('dbo.SyncQueue'))
|
|
BEGIN
|
|
CREATE INDEX IX_SyncQueue_Pending
|
|
ON dbo.SyncQueue(Status, TargetSchema, TargetTable);
|
|
END
|
|
GO
|