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
}