using Oracle.ManagedDataAccess.Client; namespace SheetMe.Data.Stores; /// /// 수술 정보 조회 — 레거시 GetOprInfDT(bzDataInterface.vb:13203-13363)의 이식. /// /// 상병과 달리 병원 분기가 없다(Select Case 0회). 바인드는 내원번호 하나뿐이고 /// 접수일자 조건은 원문에서 이미 주석 처리되어 있다(:sAcpDte — 죽은 코드). /// /// SQL 은 원문에서 기계 추출했다(133줄 그대로). S_OprInf(수술 신청)를 축으로 수술명·부위·상병· /// 집도의·마취의를 LISTAGG 로 접는 큰 조회이고, 소비 태그 8종이 전부 /// 첫 행에서 컬럼 하나를 집는다 — 그래서 행 목록만 돌려주고 선택은 해석기가 한다. /// /// 원문의 Catch 는 ErrorMessageBox 를 띄운다 — 여기서는 던진다(해석기가 사유로 바꾼다). /// 조회 함수가 대화상자를 띄우는 부작용은 옮기지 않는다. /// public sealed class SurgeryStore { #region Member Fields private readonly string connectionString; /// 원문 그대로의 조회 — 바인드는 :iComNum 하나다 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 /// 이 내원의 수술 행들 — 없으면 빈 목록 public List> Surgeries(decimal comNum) => Surgeries(comNum, mainDiagnosisOnly: false); /// /// 가 true 면 상병 집계를 주상병(OPRVAR1='0')로 /// 한정한다 — 레거시 GetOprInfDT_OKDMain(bzDataInterface.vb:13364)과 /// GetOprInfDT 의 유일한 실질 차이가 이 조인 조건 한 줄이다 /// (OKDMain 판의 수술부위·비고 컬럼 부재와 정렬 약화는 옮기지 않는다 — /// 그 판으로 부위 태그를 부르면 레거시도 컬럼 예외였다). /// public List> 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>(); using var reader = command.ExecuteReader(); while (reader.Read()) { var row = new Dictionary(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 }