소개
MEND & MOSS는 공급업체의 변경 사항을 적용할 준비가 되었습니다. 입고 작업 공간에는 앞 실습의 임시 적재 납품 데이터와 기본 검사 스크립트가 이미 준비되어 있습니다. 독립적인 환경이므로 이전 VM의 파일은 필요하지 않습니다.
사용 가능해 보이는 일부 행은 같은 판에 대해 서로 다른 내용을 제시합니다. 늦게 도착한 행도 있습니다. 검사를 확장해 이러한 모순을 거부한 다음, 매장의 자체 선반 메모를 보존하면서 더 큰 리비전만 반영하는 갱신 스크립트를 저장합니다. 첫 번째 가이드 실습의 기본 SQL을 알고 있다고 가정합니다. 충돌 검사, UPSERT, 트랜잭션은 여기서 설명합니다.
전체 과정에서 Terminal을 사용하세요. inspect.sql을 변경하고, apply.sql을 만들며, raw_delivery를 다시 적재할 수 있습니다. 원래 재고의 식별 정보와 선반 메모, 공급업체, 두 CSV 파일은 보존하세요. 공급업체 소유의 상품명/가격/리비전 값은 아래 규칙에 따라 최신 값으로 갱신할 수 있습니다.
서로 모순되는 판 거부하기
이 단계에서는 동일한 행의 반복과 같은 판의 충돌을 구분합니다. Terminal에서 시작하세요:
cd /home/labex/project/supplier-desk
이 단원의 실제 납품 데이터와 제공된 검사 스크립트를 읽어 보세요:
cat deliveries/current.csv
cat inspect.sql
열 개의 납품 행이 이미 임시 적재되어 있습니다. 3번과 7번 행은 같은 수리용 테이프의 식별 정보, 상품명, 가격, 리비전을 반복합니다. 같은 사실이 반복된다고 새 상품이 되지는 않습니다. 8번과 9번 행은 모두 N / PIN-2, 리비전 2를 설명하지만 가격이 서로 다릅니다. 어느 쪽도 승인된 값이 아닙니다. 10번 행은 N / WASH-2, 리비전 1에 대해 재고에 있는 리비전 1과 다른 가격을 제시합니다. 하나의 판 번호가 서로 다른 두 내용을 뜻할 수는 없습니다.
첫 실습의 규칙은 그대로 적용됩니다. 거부 사유 두 가지가 추가됩니다. 그 밖의 조건은 유효한 행들이 같은 공급업체/SKU/리비전에 대해 다른 상품명이나 정수 가격을 제시하면 delivery conflict이고, 해당 판이 현재 재고와 다르면 stock conflict입니다. 둘 다 해당하면 납품 내 충돌이 우선합니다. 동일한 반복은 허용합니다. 낮은 판은 검사에서 승인할 수 있지만 최신 재고를 덮어써서는 안 됩니다.
변경하기 전에 원래 재고를 확인하세요:
sqlite3 -header -column stock.db 'SELECT * FROM stock ORDER BY supplier,sku;'
뷰가 생성되도록 기본 검사를 실행하세요:
sqlite3 -bail stock.db < inspect.sql
편집하기 전에 제공된 스크립트의 복구용 사본을 만드세요. cp는 원본을 변경하지 않고 첫 번째 경로를 두 번째 경로로 복사합니다:
cp inspect.sql inspect-start.sql
다음 SQL은 별칭 t, other, s, e로 각각 납품 행, 다른 납품 행, 재고 행, 오류 행을 가리킵니다. EXISTS (SELECT 1 ...)는 일치하는 행이 하나라도 있는지 묻습니다. 행의 내용은 반환하지 않으므로 1은 자리표시자일 뿐입니다. AND는 모든 키 필드가 일치하도록 요구합니다. <>는 서로 다름을 뜻합니다. NOT EXISTS는 오류가 없는 행을 유지합니다. UNION ALL은 개별 행의 식별 정보를 잃지 않고 기본 오류와 충돌을 합칩니다.
확장 내용을 inspect.sql에 추가하세요. >>는 덮어쓰기 대신 뒤에 덧붙이므로, 그 앞의 기본 정의를 유지하세요. 이 블록을 한 번 붙여 넣으세요. 각 확장이 마지막 두 뷰만 다시 만들기 때문에 여기서는 반복해도 해가 없지만, 불필요한 중복 텍스트는 피하세요:
cat >> inspect.sql <<'SQL'
DROP VIEW IF EXISTS delivery_ready;
DROP VIEW IF EXISTS delivery_errors;
CREATE VIEW delivery_errors AS
SELECT delivery_line,reason FROM delivery_check WHERE reason IS NOT NULL
UNION ALL
SELECT t.delivery_line,
CASE WHEN EXISTS (
SELECT 1 FROM typed_delivery AS other
WHERE other.supplier=t.supplier AND other.sku=t.sku
AND other.revision=t.revision
AND (other.title<>t.title OR other.price_cents<>t.price_cents)
) THEN 'delivery conflict' ELSE 'stock conflict' END
FROM typed_delivery AS t
WHERE EXISTS (
SELECT 1 FROM typed_delivery AS other
WHERE other.supplier=t.supplier AND other.sku=t.sku
AND other.revision=t.revision
AND (other.title<>t.title OR other.price_cents<>t.price_cents)
) OR EXISTS (
SELECT 1 FROM stock AS s
WHERE s.supplier=t.supplier AND s.sku=t.sku AND s.revision=t.revision
AND (s.title<>t.title OR s.price_cents<>t.price_cents)
);
CREATE VIEW delivery_ready AS
SELECT supplier,sku,title,price_cents,revision FROM typed_delivery AS t
WHERE NOT EXISTS (
SELECT 1 FROM delivery_errors AS e WHERE e.delivery_line=t.delivery_line
);
SQL
저장한 스크립트 전체를 다시 실행하세요:
sqlite3 -bail stock.db < inspect.sql
sqlite3 -header -column stock.db 'SELECT * FROM delivery_errors ORDER BY delivery_line;'
오류가 여섯 개 나와야 합니다. 4번 행은 invalid price, 5번은 unknown supplier, 6번은 missing SKU, 8번과 9번은 delivery conflict, 10번은 stock conflict입니다. 두 원본 행 모두 허용되므로 승인된 검토 결과에 수리용 테이프가 두 번 나타납니다. 동일한 두 행 때문에 가격이 두 배가 되거나 재고 항목이 두 개 생겨서는 안 됩니다.
sqlite3 -header -column stock.db 'SELECT * FROM delivery_ready ORDER BY supplier,sku;'
승인된 납품 행은 네 개이며, 서로 다른 세 상품을 나타냅니다. 재고는 아직 변경되지 않았습니다. 기본 오류 세 개만 보이면 추가한 블록이 있는지 확인하고 스크립트 전체를 다시 실행하세요. 추가 블록에 구문 오류가 있으면 cp inspect-start.sql inspect.sql로 제공된 기본 스크립트를 복원한 다음, 추가 블록 전체를 다시 붙여 넣고 실행하세요. 이 복구 과정은 재고와 두 CSV 파일을 변경하지 않습니다.
최신 값을 적용하고 납품을 안전하게 반복 처리하기
이 단계에서는 자체 선반 메모를 변경하지 않고 승인된 행을 적용한 다음, 같은 납품을 반복하거나 이전 납품을 받아도 작업 결과가 되돌아가지 않음을 확인합니다. 같은 Terminal 디렉터리에서 시작하세요.
stock 테이블에는 (supplier,sku)에 대한 기본 키가 있습니다. 이 두 필드가 한 행을 식별합니다. UPSERT는 없는 식별 조합을 삽입하거나 기존 키와의 충돌을 처리합니다. excluded는 제안된 입력 행을 가리킵니다. 갱신하려면 그 리비전이 현재 재고의 리비전보다 커야 합니다. 제공된 shelf_note 열은 매장 소유입니다. 입력 값과 갱신 대입 양쪽에서 제외하세요. 새 재고 항목에는 준비된 빈 메모 기본값이 적용됩니다.
BEGIN은 트랜잭션을 시작하고 COMMIT은 이를 하나의 단위로 저장합니다. 오류가 발생하면 이 -bail 명령이 중단되고, 연결이 닫히면서 끝나지 않은 트랜잭션이 롤백됩니다. 이 예제는 준비된 작은 데이터베이스를 갱신하며, 동시 동기화나 백업 시스템은 아닙니다.
SELECT는 실제 승인 뷰를 읽습니다. WHERE true는 해당 행을 모두 유지하면서 SQLite가 뒤의 ON CONFLICT를 조인 조건으로 혼동하지 않게 합니다. 전체 스크립트를 저장하세요:
cat > apply.sql <<'SQL'
BEGIN;
INSERT INTO stock(supplier,sku,title,price_cents,revision)
SELECT supplier,sku,title,price_cents,revision
FROM delivery_ready WHERE true
ON CONFLICT(supplier,sku) DO UPDATE SET
title=excluded.title,
price_cents=excluded.price_cents,
revision=excluded.revision
WHERE excluded.revision>stock.revision;
COMMIT;
SQL
적용에 사용할 연결에서 외래 키를 활성화하세요. -cmd는 따옴표 안의 연결 설정을 먼저 실행하며, 이를 전역으로 저장하지 않습니다. 이어서 < apply.sql이 SQL을 제공합니다:
sqlite3 -bail -cmd 'PRAGMA foreign_keys=ON;' stock.db < apply.sql
sqlite3 -header -column stock.db 'SELECT * FROM stock ORDER BY supplier,sku;'
재고 행 네 개가 나와야 합니다:
supplier sku title price_cents revision shelf_note
-------- ------ ----------- ----------- -------- ----------
N BOLT-1 Steel bolt 135 3 Bin A
N TAPE-4 Repair tape 450 1
N WASH-2 Washer 40 1 Bin C
W BOLT-1 Brass bolt 190 2 Drawer 4
와셔는 모순되는 판이 거부되어 40으로 유지됩니다. 핀, 잘못된 캡, 알 수 없는 공급업체 또는 빈 SKU의 재고 항목은 추가되지 않았습니다. 두 볼트의 원래 메모도 유지됩니다. 수리용 테이프는 납품 데이터에 두 번 나타났어도 재고에는 한 행만 있습니다.
같은 스크립트를 반복 실행하세요:
sqlite3 -bail -cmd 'PRAGMA foreign_keys=ON;' stock.db < apply.sql
sqlite3 -header -column stock.db 'SELECT * FROM stock ORDER BY supplier,sku;'
결과는 그대로입니다. 리비전 조건 덕분에 같은 가져오기 결과를 반복 적용해도 안전합니다. 가격을 더하거나 자체 메모를 바꾸지 않습니다.
이제 이전 납품을 사용하기 전에 읽어 보세요:
cat deliveries/older.csv
이것들은 볼트의 이전 판입니다. 대화형 셸에서 임시 적재 테이블만 다시 적재하세요:
sqlite3 stock.db
DELETE FROM raw_delivery;
.import --csv --skip 1 deliveries/older.csv raw_delivery
.quit
뷰는 테이블의 현재 행을 자동으로 읽습니다. 변경하지 않은 갱신 스크립트를 실행한 다음 재고를 검사하세요:
sqlite3 -bail -cmd 'PRAGMA foreign_keys=ON;' stock.db < apply.sql
sqlite3 -header -column stock.db 'SELECT * FROM stock ORDER BY supplier,sku;'
네 행 모두 같은 값을 유지합니다. 검사는 유효한 이전 숫자 값을 허용하지만, 이를 적용해도 재고가 이전 상태로 돌아가지는 않습니다. 이는 잘못되거나 모순되는 납품과는 다른 경우입니다.
오늘 납품을 다시 검토할 수 있도록 작업 공간을 준비해 두세요. 임시 적재 데이터를 비워도 재고는 비워지지 않습니다:
sqlite3 stock.db
DELETE FROM raw_delivery;
.import --csv --skip 1 deliveries/current.csv raw_delivery
.quit
sqlite3 -header -column stock.db 'SELECT * FROM delivery_errors ORDER BY delivery_line;'
거부된 여섯 행과 사유가 계속 보입니다. 두 스크립트를 보관하세요. inspect.sql은 다른 호환 납품 데이터를 검토하는 방법을, apply.sql은 안전한 행을 재고에 반영하는 방법을 기술합니다. 잘못된 경로는 절대 경로 cd로 복구할 수 있고, 잘못 입력한 스크립트는 전체 블록으로 덮어쓸 수 있습니다. 철자 오류를 고치려고 stock.db를 다시 만들거나 레코드를 삭제하지 마세요.
요약
실제 SQLite 행을 사용해 공급업체 식별 정보, 납품 데이터, 매장의 재고를 연결했습니다. 실제로 승인되거나 거부된 레코드를 해석하고, 원본 자료를 보존하며, 다음 납품에도 재사용할 수 있는 SQL을 저장했습니다.



