sql left join on / where

本文探讨了OMS项目中的复杂SQL查询案例,重点分析了如何从多个表中获取特定手术实施所需的数据,并解释了左连接操作导致部分不符合条件记录被包含在内的原因。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

如例子: 对OMS这个项目的例子:

実施資材単品テーブルより、指定条件のデータを取得する。取得項目はUI仕様書参照。
手術実施ID=指定手術実施ID
実施資材単品テーブル.単品コード=単品マスタ.単品コード and 単品マスタ.償還材料フラグ='1'
 

select
    OPE_CD,
    to_char(CURRENT_DATE,'yyyy/MM/dd') AS CURRENT_DATE,
    PATIENT_ID,
    EXAMINATION_COURSE_NAME,
    to_char(OPE_DAY,'yyyy/MM/dd') as OPE_DAY,
    PHYSIQUE_CD1,
    PHYSIQUE_CD2,
    PATIENT_NAME,
    to_char(PATIENT_BIRTH,'yyyy/MM/dd') as PATIENT_BIRTH,
    to_char(AGE,'9999') as AGE,
    PATIENT_SEX,
    ILLNESS_NAME_1,
    ILLNESS_NAME_2,
    ILLNESS_NAME_3,
    to_char(OPE_START_TIME,'HH24:MI:SS') as OPE_START_TIME,
    to_char(OPE_END_TIME,'HH24:MI:SS') as OPE_END_TIME,
    to_char(REQUIRETIME,'HH24:MI:SS') as REQUIRETIME,
    to_char(ANESTHESIA_START_TIME,'HH24:MI:SS') as ANESTHESIA_START_TIME,
    to_char(ANESTHESIA_END_TIME,'HH24:MI:SS') as ANESTHESIA_END_TIME ,
    to_char(ANESTHESIATIME,'HH24:MI:SS') as ANESTHESIATIME,
    ARTTYPE_NAME_1,
    ARTTYPE_NAME_2,
    ARTTYPE_NAME_3,
    ANESTHESIA_NAME_1,
    ANESTHESIA_NAME_2,
    ANESTHESIA_NAME_3,
    emst.MATERIAL_DIVISION_FLAG ,
    sm.JAN_CD AS SKU_CD,
    
    CASE WHEN sm.ABBREVIATED IS NULL OR TRIM(sm.ABBREVIATED) = ''
         THEN sm.ARTICLENAME
         ELSE sm.ABBREVIATED
    END AS ARTICLENAME,
               
    sm.STANDARD,
    sm.MAKER,
    sum (emst.use_amount) as SUMUSEAMOUNT,
    um.UNIT_NAME,
               
    case
       when (emst.MATERIAL_DIVISION_FLAG <> '5' and emst.MATERIAL_DIVISION_FLAG <> '6')
       then
           '0'
                   when (emst.MATERIAL_DIVISION_FLAG = '6' and sm.sku_division_flag = '2')
       then
           '9999'
                   else sm.sku_division_flag
                end  as sku_division_flag,

               emst.sku_cd as _sku_cd,
                emst.set_cd as SETCD,
                sm.repaymentmaterials_flag

   from

       ( select
      oet.ope_cd AS OPE_CD,
      CURRENT_DATE AS CURRENT_DATE,
      oet.patient_id AS PATIENT_ID,
      (  select
        ecm.examination_course_name
       from
       examination_course_mst ecm
       where
       ecm.examination_course_cd = oet.PERFORM_DOC_EXAMINATION_COURSE_CD
      ) AS EXAMINATION_COURSE_NAME,
      oet.ope_day AS OPE_DAY,
      (    select
           USER_NAME
           FROM
           user_mst
           where
           oet.PERFORM_DOC_ID_1 = USER_CD  )AS PHYSIQUE_CD1,
      oet.physique_cd_2  AS PHYSIQUE_CD2,
      oet.patient_name  AS PATIENT_NAME,
      oet.patient_birth AS PATIENT_BIRTH,
      (select (CURRENT_DATE - to_date(oet.patient_birth,'yyyy'))/365) AS AGE,
      oet.patient_sex as PATIENT_SEX,
      oet.ILLNESS_NAME_1,
      oet.ILLNESS_NAME_2,
      oet.ILLNESS_NAME_3,
      oet.OPE_START_TIME,
      oet.OPE_END_TIME,
      
      case

when (oet.ope_start_nextday_check is null or oet.ope_start_nextday_check ='0')    and       oet.ope_end_nextday_check = '1'
 then
        oet.ope_end_time-oet.ope_start_time + interval '24 hours'
 else

        oet.ope_end_time-oet.ope_start_time

     end AS REQUIRETIME,

     oet.ANESTHESIA_START_TIME,
     oet.ANESTHESIA_END_TIME,
     case

           when (oet.anesthesia_start_nextday_check is null or oet.anesthesia_start_nextday_check = '0') and oet.anesthesia_end_nextday_check = '1'

           then   
                 oet.anesthesia_end_time - oet.anesthesia_start_time + interval '24 hours'
           else
                  oet.anesthesia_end_time - oet.anesthesia_start_time
     end AS ANESTHESIATIME,


      oet.ARTTYPE_NAME_1,
      oet.ARTTYPE_NAME_2,
      oet.ARTTYPE_NAME_3,
      oet.ANESTHESIA_NAME_1,
      oet.ANESTHESIA_NAME_2,
      oet.ANESTHESIA_NAME_3,
      oet.ope_effect_id AS ope_effect_id
     from
      ope_effect_table oet
     where
     oet.ope_cd='0000000063'                    and
        oet.ope_effect_id = '00000000053'
    ) as aa

   left join
              (
              select * from effect_material_sku_table where use_amount <> 0

               and
               (del_flag = '0' or del_flag is null)
               and

                sku_cd != ''

                and

               sku_cd is not null
             

               ) emst

           on aa.ope_effect_id = emst.ope_effect_id

           left join


         (select * from sku_mst
          where sku_cd is not null and

          repaymentmaterials_flag ='1' and

          sku_cd != ''

                and

               sku_cd is not null


          )sm


         on emst.sku_cd =sm.sku_cd

         left join unit_mst um  on sm.unit_cd = um.unit_cd

        group by
                 aa.ope_cd,
                 aa.ope_day,
                 aa.patient_id,
                 aa.examination_course_name,
                 aa.physique_cd1,
                 aa.physique_cd2,
                 aa.patient_name,
                 aa.patient_birth,
                 aa.patient_sex,
                 aa.illness_name_1,
                 aa.illness_name_2,
                 aa.illness_name_3,
                 aa.ope_start_time,
                 aa.ope_end_time,
                 aa.anesthesia_start_time,
                 aa.anesthesia_end_time,
                 aa.arttype_name_1,
                 aa.arttype_name_2,
                 aa.arttype_name_3,
                 aa.anesthesia_name_1,
                 aa.anesthesia_name_2,
                 aa.anesthesia_name_3,
                 ARTICLENAME,
                 sm.standard,
                 sm.maker,
                 um.unit_name,
                 emst.material_division_flag,
                 sm.JAN_CD,
                 sm.ABBREVIATED,
                aa.age,
                aa.requiretime,
                aa.anesthesiatime,
                sku_division_flag
                ,_sku_cd
                ,SETCD
                ,sm.repaymentmaterials_flag
      
      
      order by _sku_cd,SETCD


 

 这里有三个内部子查询 aa ,emst ,和 sm ,还有一个表是单位表 unit_mst  ,因为 aa 这个查询总会有结果(他指的是患者的信息),所以要求无论 emst 或sm 抑或 unit_mst  即使没有结果,至少要查出 aa  这个表的患者的记录,我原想会查询出符合where条件的结果,但却不是这个样子,经过查找,发现有 repaymentmaterials_flag != ‘1’ 的记录也被查处来,这是为什么呢? 原来 repaymentmaterials_flag = ‘1’ 是在 sm这个子查询中的条件,又因为aa与 emst  进行的左查询没有限制 repaymentmaterials_flag != ‘1’  (也不可能限制,因为aa与 emst  均没有这个字段),所以就会有查出这样的单品:如它的sku_cd = '003' ,在 单品表中差得sku_cd = '003'

但 repaymentmaterials_flag != ‘1’   ,因为是左查所以会列出。

<think>嗯,用户想了解SQL中的JOIN操作,特别是LEFT JOIN、INNER JOIN和RIGHT JOIN,还希望有详细的例子。首先,我得回忆一下这些JOIN的区别和用法。LEFT JOIN会返回左表的所有记录,右表没有匹配的部分用NULL填充。INNER JOIN只返回两个表有匹配的记录。RIGHT JOIN则相反,返回右表的所有记录,左表没有匹配的用NULL。用户可能对左右表的概念不太清楚,需要解释清楚。 接下来,我应该考虑如何用例子来说明。可能需要创建两个简单的表,比如员工表和部门表,这样比较直观。员工表有员工ID、姓名和部门ID,部门表有部门ID和部门名称。然后通过不同的JOIN操作展示结果的变化。 用户可能还不太明白ON子句的作用,需要强调ON后面跟的是连接条件,比如两个表中部门ID相等。同时,要指出WHEREON的区别,避免混淆。 另外,用户可能在实际应用中会遇到需要多个JOIN的情况,或者更复杂的连接条件,但这次的问题应该先聚焦在基础的三种JOIN上,确保例子简单明了,便于理解。是否需要提到FULL JOIN呢?可能暂时不用,保持回答集中在用户提到的三个类型。 在写例子的时候,确保每个JOIN的结果都清楚,比如LEFT JOIN会显示所有员工,包括没有部门的,而INNER JOIN只显示有部门的员工。RIGHT JOIN则显示所有部门,包括没有员工的。可能还需要用表格来展示结果,但因为是文字形式,需要用文字描述清楚。 最后,需要总结一下使用场景,帮助用户理解什么时候该用哪种JOIN。比如需要包含所有左表记录时用LEFT JOIN,需要严格匹配时用INNER JOIN,需要所有右表记录时用RIGHT JOIN。可能还要提醒用户,RIGHT JOIN在实际中使用较少,通常可以通过调整表的顺序用LEFT JOIN代替,这样可读性更好。</think>好的,我将通过具体示例逐步解释 SQL 中三种主要 JOIN 的用法及区别。以下是结构化说明: --- ### 一、数据准备 先创建两个示例表: ```sql -- 员工表 (employees) +--------+-------+------------+ | emp_id | name | dept_id | +--------+-------+------------+ | 1 | 张三 | 101 | | 2 | 李四 | 102 | | 3 | 王五 | NULL | +--------+-------+------------+ -- 部门表 (departments) +---------+-----------+ | dept_id | dept_name | +---------+-----------+ | 101 | 技术部 | | 102 | 市场部 | | 103 | 财务部 | +---------+-----------+ ``` --- ### 二、JOIN 类型详解 #### 1. INNER JOIN(内连接) **特性**:仅返回两个表中匹配的行 **公式**: $$ A \cap B $$ **示例**: ```sql SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id = d.dept_id; ``` **结果**: ``` +-------+-----------+ | name | dept_name | +-------+-----------+ | 张三 | 技术部 | | 李四 | 市场部 | +-------+-----------+ ``` #### 2. LEFT JOIN(左外连接) **特性**:返回左表所有行 + 右表匹配行(不匹配则填充 NULL) **公式**: $$ A $$ **示例**: ```sql SELECT e.name, d.dept_name FROM employees e LEFT JOIN departments d ON e.dept_id = d.dept_id; ``` **结果**: ``` +-------+-----------+ | name | dept_name | +-------+-----------+ | 张三 | 技术部 | | 李四 | 市场部 | | 王五 | NULL | +-------+-----------+ ``` #### 3. RIGHT JOIN(右外连接) **特性**:返回右表所有行 + 左表匹配行(不匹配则填充 NULL) **公式**: $$ B $$ **示例**: ```sql SELECT e.name, d.dept_name FROM employees e RIGHT JOIN departments d ON e.dept_id = d.dept_id; ``` **结果**: ``` +-------+-----------+ | name | dept_name | +-------+-----------+ | 张三 | 技术部 | | 李四 | 市场部 | | NULL | 财务部 | +-------+-----------+ ``` --- ### 三、图示对比 ``` 左表(employees) 右表(departments) ● 张三 ↔ 技术部 (INNER JOIN) ● 李四 ↔ 市场部 ○ 王五 → NULL (LEFT JOIN) NULL ← 财务部 (RIGHT JOIN) ``` --- ### 四、使用场景建议 1. **INNER JOIN**:需精确匹配时(如订单关联商品信息) 2. **LEFT JOIN**:保留主表完整数据时(如显示所有用户及其订单,包括未下单用户) 3. **RIGHT JOIN**:实际较少使用(通常改用 LEFT JOIN 调换表顺序) --- ### 五、进阶注意 - **多表 JOIN** 可叠加使用 - **ONWHERE** 的区别:ON 定义连接条件,WHERE 过滤最终结果 - 使用 `COALESCE()` 处理 NULL 值更安全 需要进一步具体场景的示例吗?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值