-- 根据流水号查询病人信息
-- 
-- 流水号格式：YYYYMMDD-XXX（例如：20260109-001）
--   - 前面8位是日期（YYYYMMDD）
--   - 后面3位是序号（XXX），对应数据库的 display_order
-- 
-- 说明：
--   display_order 是按"科室+医生+当天"自增的，所以同一天不同科室/不同医生可能有相同的序号
--   如果只知道序号（如 001），建议配合科室、医生、日期范围一起查询

-- ========================================
-- 方案1：知道完整流水号（如：20260109-001）
-- ========================================
-- 参数说明：
--   :serial_no = '20260109-001'  -- 完整流水号
-- 
-- 解析逻辑：
--   日期：20260109 -> 2026-01-09
--   序号：001 -> 1

WITH parsed AS (
    SELECT 
        -- 提取日期部分（前8位）并转换为日期格式
        TO_DATE(SUBSTRING(:serial_no FROM 1 FOR 8), 'YYYYMMDD') AS target_date,
        -- 提取序号部分（最后3位）并转换为整数
        CAST(SUBSTRING(:serial_no FROM 10) AS INTEGER) AS target_order
)
SELECT 
    e.id AS 就诊ID,
    e.bus_no AS 就诊编码,
    DATE(e.start_time) AS 挂号日期,
    e.start_time AS 挂号时间,
    e.organization_id AS 科室ID,
    e.registrar_id AS 医生ID,
    e.display_order AS 流水号序号,
    -- 计算完整流水号（用于验证）
    TO_CHAR(e.start_time, 'YYYYMMDD') || '-' || LPAD(e.display_order::text, 3, '0') AS 完整流水号,
    p.id AS 患者ID,
    p.name AS 患者姓名,
    p.bus_no AS 患者业务号,
    p.gender AS 性别,
    p.birth_date AS 出生日期,
    p.phone AS 电话,
    e.status_enum AS 状态
FROM adm_encounter e
INNER JOIN adm_patient p ON e.patient_id = p.id AND p.delete_flag = '0'
CROSS JOIN parsed
WHERE e.delete_flag = '0'
  AND DATE(e.start_time) = parsed.target_date
  AND e.display_order = parsed.target_order
ORDER BY e.start_time DESC
LIMIT 10;

-- ========================================
-- 方案2：只知道序号（如：001），配合其他条件查询
-- ========================================
-- 参数说明：
--   :order_no = '001'              -- 序号（不带日期）
--   :start_date = '2026-01-01'     -- 开始日期（可选，缩小范围）
--   :end_date = '2026-01-31'       -- 结束日期（可选，缩小范围）
--   :organization_id = 123         -- 科室ID（可选，精确匹配）
--   :registrar_id = 456            -- 医生ID（可选，精确匹配）
--   :patient_name = '张三'         -- 患者姓名（可选，模糊匹配）

SELECT 
    e.id AS 就诊ID,
    e.bus_no AS 就诊编码,
    DATE(e.start_time) AS 挂号日期,
    e.start_time AS 挂号时间,
    TO_CHAR(e.start_time, 'YYYYMMDD') || '-' || LPAD(e.display_order::text, 3, '0') AS 完整流水号,
    e.organization_id AS 科室ID,
    e.registrar_id AS 医生ID,
    e.display_order AS 流水号序号,
    p.id AS 患者ID,
    p.name AS 患者姓名,
    p.bus_no AS 患者业务号,
    p.phone AS 电话,
    e.status_enum AS 状态
FROM adm_encounter e
INNER JOIN adm_patient p ON e.patient_id = p.id AND p.delete_flag = '0'
WHERE e.delete_flag = '0'
  AND e.display_order = CAST(:order_no AS INTEGER)  -- 序号匹配
  -- 以下条件可选，去掉注释并根据需要填入值
  -- AND DATE(e.start_time) >= CAST(:start_date AS DATE)  -- 日期范围：开始
  -- AND DATE(e.start_time) <= CAST(:end_date AS DATE)    -- 日期范围：结束
  -- AND e.organization_id = CAST(:organization_id AS BIGINT)  -- 科室匹配
  -- AND e.registrar_id = CAST(:registrar_id AS BIGINT)        -- 医生匹配
  -- AND p.name LIKE '%' || :patient_name || '%'               -- 患者姓名模糊匹配
ORDER BY e.start_time DESC
LIMIT 50;

-- ========================================
-- 方案3：按患者姓名 + 大概日期范围查询（最常用）
-- ========================================
-- 参数说明：
--   :patient_name = '张三'         -- 患者姓名（模糊匹配）
--   :start_date = '2026-01-01'     -- 开始日期
--   :end_date = '2026-01-31'       -- 结束日期

SELECT 
    e.id AS 就诊ID,
    e.bus_no AS 就诊编码,
    DATE(e.start_time) AS 挂号日期,
    e.start_time AS 挂号时间,
    TO_CHAR(e.start_time, 'YYYYMMDD') || '-' || LPAD(e.display_order::text, 3, '0') AS 完整流水号,
    e.organization_id AS 科室ID,
    e.registrar_id AS 医生ID,
    e.display_order AS 流水号序号,
    p.id AS 患者ID,
    p.name AS 患者姓名,
    p.bus_no AS 患者业务号,
    p.phone AS 电话,
    e.status_enum AS 状态
FROM adm_encounter e
INNER JOIN adm_patient p ON e.patient_id = p.id AND p.delete_flag = '0'
WHERE e.delete_flag = '0'
  AND p.name LIKE '%' || :patient_name || '%'
  AND DATE(e.start_time) >= CAST(:start_date AS DATE)
  AND DATE(e.start_time) <= CAST(:end_date AS DATE)
ORDER BY e.start_time DESC;

-- ========================================
-- 方案4：按就诊卡号查询（最准确）
-- ========================================
-- 参数说明：
--   :card_no = '12345678'  -- 就诊卡号

SELECT 
    e.id AS 就诊ID,
    e.bus_no AS 就诊编码,
    DATE(e.start_time) AS 挂号日期,
    e.start_time AS 挂号时间,
    TO_CHAR(e.start_time, 'YYYYMMDD') || '-' || LPAD(e.display_order::text, 3, '0') AS 完整流水号,
    e.organization_id AS 科室ID,
    e.registrar_id AS 医生ID,
    e.display_order AS 流水号序号,
    p.id AS 患者ID,
    p.name AS 患者姓名,
    p.bus_no AS 患者业务号,
    COALESCE(
        (SELECT identifier_no 
         FROM adm_patient_identifier 
         WHERE patient_id = p.id 
           AND delete_flag = '0' 
           AND identifier_no IS NOT NULL 
           AND identifier_no != ''
         ORDER BY create_time ASC 
         LIMIT 1),
        p.bus_no,
        ''
    ) AS 就诊卡号,
    p.phone AS 电话,
    e.status_enum AS 状态
FROM adm_encounter e
INNER JOIN adm_patient p ON e.patient_id = p.id AND p.delete_flag = '0'
WHERE e.delete_flag = '0'
  AND (
      -- 优先匹配 identifier_no
      EXISTS (
          SELECT 1 
          FROM adm_patient_identifier api
          WHERE api.patient_id = p.id
            AND api.delete_flag = '0'
            AND api.identifier_no = :card_no
      )
      OR
      -- 备用：匹配 patient.bus_no
      p.bus_no = :card_no
  )
ORDER BY e.start_time DESC
LIMIT 20;

-- ========================================
-- 方案5：模糊查询流水号（部分匹配）
-- ========================================
-- 参数说明：
--   :serial_part = '20260109'      -- 只输入日期部分
--   或
--   :serial_part = '001'           -- 只输入序号部分
--   或
--   :serial_part = '20260109-00'   -- 输入部分（前缀匹配）

SELECT 
    e.id AS 就诊ID,
    e.bus_no AS 就诊编码,
    DATE(e.start_time) AS 挂号日期,
    e.start_time AS 挂号时间,
    TO_CHAR(e.start_time, 'YYYYMMDD') || '-' || LPAD(e.display_order::text, 3, '0') AS 完整流水号,
    e.organization_id AS 科室ID,
    e.registrar_id AS 医生ID,
    e.display_order AS 流水号序号,
    p.id AS 患者ID,
    p.name AS 患者姓名,
    p.bus_no AS 患者业务号,
    p.phone AS 电话,
    e.status_enum AS 状态
FROM adm_encounter e
INNER JOIN adm_patient p ON e.patient_id = p.id AND p.delete_flag = '0'
WHERE e.delete_flag = '0'
  AND (
      -- 匹配日期部分（如输入：20260109）
      TO_CHAR(e.start_time, 'YYYYMMDD') LIKE :serial_part || '%'
      OR
      -- 匹配序号部分（如输入：001）
      LPAD(e.display_order::text, 3, '0') LIKE '%' || :serial_part || '%'
      OR
      -- 匹配完整流水号前缀（如输入：20260109-00）
      (TO_CHAR(e.start_time, 'YYYYMMDD') || '-' || LPAD(e.display_order::text, 3, '0')) LIKE :serial_part || '%'
  )
ORDER BY e.start_time DESC
LIMIT 50;

