OCM_수술주상병(bzDataInterface.vb:13148 + GetOprInfDT_OKDMain :13364 — 기존 수술 조회와의 실질 차이가 상병 집계의 주상병 한정(OPRVAR1='0') 한 줄이라 SurgeryStore 에 mainDiagnosisOnly 를 얹었다. 치환이 빗나가면 필터 없는 값이 조용히 나가므로 가드로 던진다), OCM_수술집도의_진료과/_그룹진료과(:3157/:3194 — 집도의(DTRUIDCOD)를 오늘 기준 마스터로 푸는 원문 특이점(OprStt 무필터·SYSDATE 유효기간) 그대로, 최신 수술 첫 행 고정), OCM_수술명칭(:3520 Case Else — OPRCOD 를 수술일 순으로, 각 행 뒤 공백 1칸 + CRLF 결합. GNBEDRO· HIMCHAN_BP 의 OPNAME 포함 분기 미이식). 사유 완결 2종: OCM_수술진단명(:3066 — PURME 전용, 그 외 병원은 Case 미매칭으로 항상 빈 값), OCM_수술처치(:3474 — SUSS·YJRCH 전용). ㉘ 정정: 수술 검증이 늘 SKIP 이던 원인은 소유자 탐색을 O_OprInf 로 한 것 — 실제 조회(GetOprInfDT)의 축은 S_OprInf(수술 신청)다. 표를 바로잡자 이 시험 DB 에서 수술 행 1건·OPNAME 실값이 검증됐다 (SurgeryStore 의 낡은 주석도 함께 정정). - dotnet test 342/342 · --edit-smoke 실패 0 (이름 검사 242종) - --db-patient ①~㊱ 전건 통과 — ㉘ 이 처음으로 실값 PASS - --db-render P062 md5 8d683835f5d81e7bb41c79071d6bf954 불변 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
212 lines
9.7 KiB
C#
212 lines
9.7 KiB
C#
using Oracle.ManagedDataAccess.Client;
|
|
|
|
namespace SheetMe.Data.Stores;
|
|
|
|
/// <summary>
|
|
/// 수술 정보 조회 — 레거시 <c>GetOprInfDT</c>(bzDataInterface.vb:13203-13363)의 이식.
|
|
///
|
|
/// 상병과 달리 <b>병원 분기가 없다</b>(Select Case 0회). 바인드는 내원번호 하나뿐이고
|
|
/// 접수일자 조건은 원문에서 이미 주석 처리되어 있다(:sAcpDte — 죽은 코드).
|
|
///
|
|
/// SQL 은 원문에서 기계 추출했다(133줄 그대로). S_OprInf(수술 신청)를 축으로 수술명·부위·상병·
|
|
/// 집도의·마취의를 LISTAGG 로 접는 큰 조회이고, 소비 태그 8종이 전부
|
|
/// <b>첫 행에서 컬럼 하나</b>를 집는다 — 그래서 행 목록만 돌려주고 선택은 해석기가 한다.
|
|
///
|
|
/// 원문의 Catch 는 ErrorMessageBox 를 띄운다 — 여기서는 던진다(해석기가 사유로 바꾼다).
|
|
/// 조회 함수가 대화상자를 띄우는 부작용은 옮기지 않는다.
|
|
/// </summary>
|
|
public sealed class SurgeryStore
|
|
{
|
|
#region Member Fields
|
|
private readonly string connectionString;
|
|
|
|
/// <summary>원문 그대로의 조회 — 바인드는 :iComNum 하나다</summary>
|
|
private const string Query = @"
|
|
With
|
|
OprInfRec
|
|
AS
|
|
(
|
|
SELECT Opr.*
|
|
FROM (
|
|
|
|
SELECT /* 수술 정보 */
|
|
OprKey
|
|
, OprDte
|
|
, OprChtNum
|
|
, OprComNum, OprOrgCom, OprGbnCod, OprStt
|
|
, OprRomCod
|
|
, OprUseTms, OprStrTms, OprDayNum
|
|
, OprActStt
|
|
, OprNam
|
|
, OprDtrCod, OprDepCod, OprSplCmt
|
|
, CASE OprRegion WHEN '1' THEN '오른쪽'
|
|
WHEN '2' THEN '왼쪽'
|
|
WHEN '3' THEN '양쪽'
|
|
ELSE '없음'
|
|
END AS OprRegionName
|
|
, OprPatEtc
|
|
, OPR.OprUpdDtf
|
|
|
|
/* 인적 정보 */
|
|
, PatNam
|
|
, PatSexTyp
|
|
, ComPatTyp
|
|
, SUBSTR(ComAcpDtm, 1, 8) AS ComAcpDte
|
|
|
|
/* 관련 정보 */
|
|
, PRGSTSDTL.DtlCodNam AS OprActFlg
|
|
, UIDOPRDTR.UidNam AS OprDtrNam /* 집도의 명 */
|
|
, UIDCODDTR.UidNam AS CodDtrNam /* 주치의 명 */
|
|
|
|
, ROW_NUMBER() OVER (PARTITION BY OprKey ORDER BY CodStrDtm DESC ) AS RN
|
|
|
|
FROM S_OprInf OPR
|
|
LEFT JOIN P_PatInf
|
|
ON PatChtNum = OprChtNum
|
|
|
|
/* 수술정보의 내원정보 */
|
|
LEFT JOIN P_ComInf
|
|
ON OprComNum = ComNum
|
|
LEFT JOIN P_CodInf
|
|
ON CodComNum = ComNum
|
|
AND CASE WHEN ComPatTyp = 'I' THEN OprDte ||'2359'
|
|
ELSE CodStrDtm
|
|
END BETWEEN CodStrDtm AND CodEndDtm
|
|
|
|
LEFT JOIN M_DtlMst PRGSTSDTL
|
|
ON PRGSTSDTL.DtlTblCod = 'OPRPRGSTS'
|
|
AND PRGSTSDTL.DtlCod = OprActStt
|
|
/* 집도의 */
|
|
LEFT JOIN M_UidMst UIDOPRDTR
|
|
ON UIDOPRDTR.UidCod = OprDtrCod
|
|
AND OprDte BETWEEN UIDOPRDTR.UidStrDte AND UIDOPRDTR.UidEndDte
|
|
/* 주치의 */
|
|
LEFT JOIN M_UidMst UIDCODDTR
|
|
ON UIDCODDTR.UidCod = CodDtrCod
|
|
AND OprDte BETWEEN UIDCODDTR.UidStrDte AND UIDCODDTR.UidEndDte
|
|
|
|
WHERE 1 = 1
|
|
AND OprStt = 'E'
|
|
-- AND OprDte = :sAcpDte
|
|
AND OprComNum = :iComNum
|
|
-- AND OprDepCod IN ('0100','0101','0200','0201','0300','1601','1900','2100','2301','7001','0400','0500','0501','0550','0600','0601','0900','0901','1000','1100','1300','2601','0800','1400','1500','1600','5500')
|
|
|
|
) OPR
|
|
|
|
WHERE RN = 1
|
|
)
|
|
,
|
|
OprTypRec
|
|
AS
|
|
(
|
|
SELECT OprTypKey, DX, OPNAME
|
|
, SUBSTR(ANECOD, 1, LENGTH(ANECOD)-1) AS ANECOD
|
|
, SUBSTR(ANECODNAM, 1, LENGTH(ANECODNAM)-1) AS ANECODNAM
|
|
, SUBSTR(ANEUIDCOD, 1, LENGTH(ANEUIDCOD)-1) AS ANEUIDCOD
|
|
, SUBSTR(OKDNAM, 1, LENGTH(OKDNAM)) AS OKDNAM
|
|
, SUBSTR(OPRCODNAM, 1, LENGTH(OPRCODNAM)) AS OPRCODNAM
|
|
FROM (
|
|
SELECT OprKey AS OprTypKey
|
|
, MAX(DX.OprCodNam) AS DX
|
|
, MAX(OPNAME.OprCodNam) AS OPNAME
|
|
, regexp_replace(LISTAGG(ANECOD.OprCod || ',') WITHIN GROUP ( ORDER BY ANECOD.OprTypKey ), '([^,]+)(,\1)+', '\1') AS ANECOD
|
|
, regexp_replace(LISTAGG(ANECOD.OprCodNam || ',') WITHIN GROUP ( ORDER BY ANECOD.OprTypKey ), '([^,]+)(,\1)+', '\1') AS ANECODNAM
|
|
, regexp_replace(LISTAGG(ANEUID.OprCodNam || ',') WITHIN GROUP ( ORDER BY ANEUID.OprTypKey ), '([^,]+)(,\1)+', '\1') AS ANEUIDCOD
|
|
, MIN(OKDNAM.OprCodNam) AS OKDNAM
|
|
, MIN(OPRCODNAM.OprCodNam) AS OPRCODNAM
|
|
|
|
FROM OprInfRec
|
|
LEFT JOIN S_OprTyp DX
|
|
ON OprKey = DX.OprKeyNum
|
|
AND DX.OprTyp = 'DX'
|
|
LEFT JOIN S_OprTyp OPNAME
|
|
ON OprKey = OPNAME.OprKeyNum
|
|
AND OPNAME.OprTyp = 'OPNAME'
|
|
LEFT JOIN S_OprTyp ANECOD
|
|
ON OprKey = ANECOD.OprKeyNum
|
|
AND ANECOD.OprTyp = 'ANECOD'
|
|
LEFT JOIN S_OprTyp ANEUID
|
|
ON OprKey = ANEUID.OprKeyNum
|
|
AND ANEUID.OprTyp = 'ANEUIDCOD'
|
|
LEFT JOIN S_OprTyp OKDNAM
|
|
ON OprKey = OKDNAM.OprKeyNum
|
|
AND OKDNAM.OprTyp = 'OKD'
|
|
LEFT JOIN S_OprTyp OPRCODNAM
|
|
ON OprKey = OPRCODNAM.OprKeyNum
|
|
AND OPRCODNAM.OprTyp = 'OPRCOD'
|
|
AND ROWNUM = 1
|
|
|
|
WHERE 1 = 1
|
|
GROUP BY OprKey
|
|
)
|
|
|
|
)
|
|
,
|
|
OprLstRec
|
|
AS
|
|
(
|
|
SELECT *
|
|
FROM OprInfRec
|
|
LEFT JOIN OprTypRec
|
|
ON OprKey = OprTypKey
|
|
)
|
|
|
|
--SELECT * FROM OprInfRec
|
|
--SELECT * FROM OprTypRec
|
|
SELECT * FROM OprLstRec
|
|
ORDER BY OprComNum, OprDte DESC, OprDayNum ASC
|
|
";
|
|
#endregion
|
|
|
|
#region Constructors
|
|
public SurgeryStore(string connectionString) => this.connectionString = connectionString;
|
|
#endregion
|
|
|
|
#region Methods
|
|
/// <summary>이 내원의 수술 행들 — 없으면 빈 목록</summary>
|
|
public List<Dictionary<string, string>> Surgeries(decimal comNum)
|
|
=> Surgeries(comNum, mainDiagnosisOnly: false);
|
|
|
|
/// <summary>
|
|
/// <paramref name="mainDiagnosisOnly"/> 가 true 면 상병 집계를 주상병(OPRVAR1='0')로
|
|
/// 한정한다 — 레거시 <c>GetOprInfDT_OKDMain</c>(bzDataInterface.vb:13364)과
|
|
/// <c>GetOprInfDT</c> 의 유일한 실질 차이가 이 조인 조건 한 줄이다
|
|
/// (OKDMain 판의 수술부위·비고 컬럼 부재와 정렬 약화는 옮기지 않는다 —
|
|
/// 그 판으로 부위 태그를 부르면 레거시도 컬럼 예외였다).
|
|
/// </summary>
|
|
public List<Dictionary<string, string>> Surgeries(decimal comNum, bool mainDiagnosisOnly)
|
|
{
|
|
using var connection = new OracleConnection(connectionString);
|
|
connection.Open();
|
|
using var command = connection.CreateCommand();
|
|
command.BindByName = true;
|
|
var sql = mainDiagnosisOnly
|
|
? Query.Replace("AND OKDNAM.OprTyp = 'OKD'",
|
|
"AND OKDNAM.OprTyp = 'OKD' AND OKDNAM.OPRVAR1 = '0'")
|
|
: Query;
|
|
if (mainDiagnosisOnly && !sql.Contains("OPRVAR1", StringComparison.Ordinal))
|
|
{
|
|
// 치환이 빗나가면 주상병 필터 없는 값이 조용히 나간다 — 빈 값보다 나쁘다
|
|
throw new InvalidOperationException("주상병 필터 치환이 원문과 맞지 않습니다");
|
|
}
|
|
command.CommandText = sql;
|
|
command.Parameters.Add(new OracleParameter("iComNum", comNum));
|
|
|
|
var rows = new List<Dictionary<string, string>>();
|
|
using var reader = command.ExecuteReader();
|
|
while (reader.Read())
|
|
{
|
|
var row = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
|
for (var i = 0; i < reader.FieldCount; i++)
|
|
{
|
|
row[reader.GetName(i)] = reader.IsDBNull(i)
|
|
? string.Empty
|
|
: reader.GetValue(i).ToString()!.Trim();
|
|
}
|
|
rows.Add(row);
|
|
}
|
|
return rows;
|
|
}
|
|
#endregion
|
|
}
|