From 942780ae9711c40a511b1eadf2fb170ee777c26d Mon Sep 17 00:00:00 2001 From: Msystech Date: Wed, 19 Aug 2026 11:45:00 +0900 Subject: [PATCH] =?UTF-8?q?C=20=EB=A5=BC=20=EB=A8=BC=EC=A0=80=20=EC=84=B8?= =?UTF-8?q?=20=EB=B4=A4=EB=8B=A4=20=E2=80=94=2025,488=EA=B1=B4=EC=9D=B4=20?= =?UTF-8?q?=EA=B1=B8=EB=A6=B0=EB=8B=A4.=20"=EB=A0=88=EA=B1=B0=EC=8B=9C=20?= =?UTF-8?q?=EA=B7=B8=EB=8C=80=EB=A1=9C"=EB=8A=94=20=EC=84=A0=ED=83=9D?= =?UTF-8?q?=EC=A7=80=EA=B0=80=20=EC=95=84=EB=8B=88=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CodMtiSeq=0 행이 2개 이상인 내원: 25,488건, 최대 41행. 0건이면 없는 문제였겠지만 아니었다. 41행짜리 내원에서 ORDER BY 없는 Rows(0) 은 사실상 무작위다. 레거시는 지금도 그 25,488건의 담당의를 확정적으로 찍지 못하고 있다 — 재현할 대상 자체가 없으므로 "그대로 옮긴다"가 성립하지 않는다. 정황이 하나 더 있다. 레거시는 GetCodInfDT 에 적용일시를 넘기면서도 그것으로 P_CodInf 를 거르지 않는다(넘긴 날짜는 마스터 유효기간 조인에만 쓴다). P_CodInf 에 CodStrDtm/CodEndDtm 이 있는데 WHERE 에 없다 — "그 시점의 진료과"를 뽑으려던 의도가 반쯤만 구현된 것으로 보인다. 측정 코드는 진단에 남겼다. 세기 전에는 A 와 B 중 어느 쪽인지 알 수 없었다. Co-Authored-By: Claude Opus 5 --- docs/TAG-PORTABLE-48.md | 31 +++++++++++++++++++++ src/SheetMe.Designer/Diagnostics/DbSmoke.cs | 15 ++++++++++ 2 files changed, 46 insertions(+) diff --git a/docs/TAG-PORTABLE-48.md b/docs/TAG-PORTABLE-48.md index 71a131e..afe0755 100644 --- a/docs/TAG-PORTABLE-48.md +++ b/docs/TAG-PORTABLE-48.md @@ -156,3 +156,34 @@ WHERE CodComNum = :n AND CodMtiSeq = '0' 또한 이 조회는 `PatientContextStore` 가 이미 읽는 `CodInf` 와 선택 규칙이 다르다 (그쪽은 적용일시 BETWEEN + 최신순 1행). 같은 표를 두 규칙으로 읽게 되므로 문맥의 `CodInf` 를 재사용하면 안 된다. + +### 조사 결과 — ① 은 실재하는 문제다 + +운영 DB(SRCH_TEST)에서 센 결과: + +| 항목 | 값 | +| --- | --- | +| `CodMtiSeq=0` 행이 2개 이상인 내원 | **25,488건** | +| 한 내원의 최대 행수 | **41행** | + +0건이면 없는 문제였겠지만 아니다. 그리고 41행짜리 내원에서 +정렬 없는 `Rows(0)` 은 사실상 무작위다. +즉 레거시는 지금 이 순간에도 그 25,488건에 대해 담당의를 확정적으로 찍고 있지 않다. + +**"레거시 그대로"는 선택지가 아니다** — 재현할 대상 자체가 없다. + +#### 정황 하나 더 + +레거시는 `GetCodInfDT` 에 적용일시를 넘기면서도 그것으로 거르지 않는다. +넘긴 날짜는 `M_UidMst`·`M_DepMst` 의 유효기간 조인에만 쓰인다. +`P_CodInf` 자체에는 `CodStrDtm`/`CodEndDtm` 이 있는데 `WHERE` 에 없다 — +"그 시점의 진료과"를 뽑으려던 의도가 코드에 반쯤만 구현된 것으로 보인다. + +`PatientContextStore` 가 문맥의 `CodInf` 를 읽을 때는 그 조건을 이미 쓴다 +(`:t BETWEEN CodStrDtm AND CodEndDtm`, 최신순 1행). + +#### 권고 + +적용일시로 거르고 최신순 1행을 집는다 — 문맥 조회와 같은 규칙. +결정적이 되고, 레거시가 의도한 것으로 보이는 동작과도 맞는다. +이는 의도적으로 레거시와 다르게 가는 첫 사례이므로 코드 주석과 여기에 근거를 남긴다. diff --git a/src/SheetMe.Designer/Diagnostics/DbSmoke.cs b/src/SheetMe.Designer/Diagnostics/DbSmoke.cs index 18b42d9..4675296 100644 --- a/src/SheetMe.Designer/Diagnostics/DbSmoke.cs +++ b/src/SheetMe.Designer/Diagnostics/DbSmoke.cs @@ -2153,6 +2153,21 @@ public static class DbSmoke $"{normalized.Length}자 — 복호화 실패나 컬럼 부재를 의심할 것"); Check("㉑ 그 번호에서 성별이 나온다", sex is "M" or "F", $"'{sex}'"); } + + // ── OCM_담당의사 배치의 선행 조사 ── + // 레거시 GetCodInfDT 는 ORDER BY 없이 CodMtiSeq='0' 만 걸고 + // 호출부가 Rows(0) 을 집는다. 한 내원에 그런 행이 둘 이상이면 + // 오라클이 어느 행을 먼저 주느냐에 따라 담당의가 달라진다. + // 실제로 그런 내원이 있는지 세어 본다 — 0이면 없는 문제고, + // 있으면 정렬 규칙을 정해야 한다. 세기 전에는 어느 쪽인지 알 수 없다. + foreach (var line in ExplainPeriod(conn, 0, + "SELECT COUNT(*) 다중내원, MAX(행수) 최대행수 FROM (" + + " SELECT CodComNum, COUNT(*) 행수 FROM P_CodInf" + + " WHERE CodMtiSeq = 0 GROUP BY CodComNum HAVING COUNT(*) > 1)" + + " WHERE :k = 0")) + { + lines.Add($" [조사] CodMtiSeq=0 이 2행 이상인 내원: {line}"); + } } } }