先核來源與已訂規則
本例來源 code 定 NOT NULL、UNIQUE。CREATE TABLE target AS SELECT 會拷值,卻不帶這些限制。須先明建受限制目標,載行後再試真正重複寫入。
| 紀錄 | 輸入 JSON |
|---|---|
| 原例輸入 | {"source":["A"],"incoming":"A"} |
比較兩條實際路徑
錯目標存兩行 A;更正第二 A 違 UNIQUE2067,首 A 仍留。試寫前行數相同,並查不出已丟保護。
| 路徑 | 輸出 JSON |
|---|---|
| 錯誤路徑 | {"error":null,"records":[{"code":"A"},{"code":"A"}]} |
| 更正路徑 | {"error":{"code":2067},"records":[{"code":"A"}]} |
import {DatabaseSync} from 'node:sqlite';
import {TextDecoder} from 'node:util';
import {inflateSync} from 'node:zlib';
import {posix} from 'node:path';
import {createHash} from 'node:crypto';
const rows=(db,sql)=>db.prepare(sql).all().map(r=>({...r}));
const failed=(action)=>{try{action();return null;}catch(e){return {code:e.errcode??e.code??e.name};}};
import assert from 'node:assert/strict';
const run=function run(i,corrected=true){
const db=new DatabaseSync(':memory:');try{db.exec('CREATE TABLE source(code TEXT NOT NULL UNIQUE);');
for(const code of i.source)db.prepare('INSERT INTO source VALUES(?)').run(code);
if(corrected)db.exec('CREATE TABLE target(code TEXT NOT NULL UNIQUE); INSERT INTO target SELECT code FROM source;');
else db.exec('CREATE TABLE target AS SELECT * FROM source;');
const error=failed(()=>db.prepare('INSERT INTO target VALUES(?)').run(i.incoming));
return {error,records:rows(db,'SELECT code FROM target ORDER BY code')};
}finally{db.close();}
};
const cases=[{"label":"misleading base","input":{"source":["A"],"incoming":"A"},"expected":{"error":null,"records":[{"code":"A"},{"code":"A"}]},"corrected":false},{"label":"corrected base","input":{"source":["A"],"incoming":"A"},"expected":{"error":{"code":2067},"records":[{"code":"A"}]},"corrected":true},{"label":"new unique source value","input":{"source":["A"],"incoming":"B"},"expected":{"error":null,"records":[{"code":"A"},{"code":"B"}]},"corrected":true},{"label":"empty source table","input":{"source":[],"incoming":"A"},"expected":{"error":null,"records":[{"code":"A"}]},"corrected":true}];
for(const test of cases){
const actual=run(test.input,test.corrected);
assert.deepEqual(actual,test.expected,test.label);
console.log(test.label,actual);
}
下次載入前核邊界
新 B 可與 A 並存;來源起初空,目標仍須有唯一限制。
| 情況 | 輸入 JSON | 預期輸出 JSON |
|---|---|---|
| 另一個新代碼 | {"source":["A"],"incoming":"B"} | {"error":null,"records":[{"code":"A"},{"code":"B"}]} |
| 空來源仍保目標限制 | {"source":[],"incoming":"A"} | {"error":null,"records":[{"code":"A"}]} |
已有行都拷齊,是否自動保住 UNIQUE?
查看參考答案
不會,CTAS 沒有帶上限制。須重建並驗第二 A 真正被拒。