SQL 带 COALESCE 的条件 SELECT(分组或 table 连接可能存在问题)

SQL Conditional SELECT with COALESCE (possible issue with grouping or table joins)

提前为问题的长度道歉:

我正在处理一个查询,以显示将从不同表中提取的数据,具体取决于请求数据的设施。

我们维护着来自各个产品线的许多统计数据,每个设施都希望能够查看生产线级别的数据;然而,一些机构还按部门对产品进行分组,然后甚至按 "value stream"(只是层次结构中的另一层)对部门进行分组。

我想做的是在可用的最高组中显示数据(具有价值流的设施获取该设施的流列表,只有产品线的设施查看产品列表,等等) ).

我已经使用 COALESCE 函数来帮助解决这个问题,因为我有兴趣测试 NULL 值以确定设施使用的组织组。

不幸的是,必要的数据位于 6 个不同的表中,需要进行几次连接。我为每个连接添加了额外的参数以尝试确保连接正确。

对于不使用流或部门的设施(下例中的 1),查询功能正常;生成产品列表及其各自的分数。

查询未提供其他级别的所需结果。对于使用价值流 (2) 组织的设施,期望的结果是该设施的流及其各自分数的列表。相反,会再次生成产品线列表。

这是我的查询:

select * from
(select a.*, rownum rnum from (

SELECT /*STREAM_ID, DEPT_ID ,LINE,*/ 
  COALESCE(VS.ID, DT.ID, SLR.LINE) "ID", 
  COALESCE(VS.NAME, DT.NAME, SLR.NAME) "NAME", 
  case when SAFETY_VALUE = 0 then 'GREEN' when SAFETY_VALUE > 0 then 'RED' else 'WHITE' end AS COLOR 
FROM XX_SQDC_LINES_REF SLR  
LEFT JOIN SQDC_DEPARTMENT_DETAILS DTD on SLR.SITE=DTD.FACILITY_ID AND SLR.LINE=DTD.LINE_ID
LEFT JOIN SQDC_VALUE_STREAM_DETAILS VSD ON DTD.FACILITY_ID= VSD.FACILITY_ID AND DTD.LINE_ID=VSD.LINE_ID
LEFT JOIN SQDC_SAFETY_MAX KPI ON VSD.FACILITY_ID=KPI.FACILITY_ID AND VSD.LINE_ID=KPI.LINE_ID
LEFT JOIN SQDC_DEPARTMENTS DT ON KPI.FACILITY_ID= DT.FACILITY_ID and dtd.dept_id=dt.id
LEFT JOIN SQDC_VALUE_STREAMS VS ON DT.FACILITY_ID= VS.FACILITY_ID AND DT.VS_ID=VS.ID
WHERE (SITE = 2)
ORDER by NAME

)a)

表(示例值;还有一些我遗漏的列,因为它们与此查询无关):

XX_SQDC_LINES_REF

    Line Name    Site
    1    Table   1
    2    Lamp    1
    3    Screen  2
    4    Forcep  2
    5    Brush   2
    6    Camera2 2
    7    Screen2 2
    8    Forcep2 2
    9    Brush2  2
    10   Camera2 2

SQDC_DEPARTMENT_DETAILS

    Dept_ID Line_ID Facility_ID
    1       3       2
    1       4       2
    2       5       2 
    2       6       2
    3       7       2 
    3       8       2
    4       9       2 
    4       10      2

SQDC_VALUE_STREAM_DETAILS

    Stream_ID Line_ID Facility_ID
    1         3       2
    1         4       2
    1         5       2 
    1         6       2
    2         7       2 
    2         8       2
    2         9       2 
    2         10      2

SQDC_SAFETY_MAX

    Facility_ID Line_ID Actual_Date Safety_Value
    1           1       31-Jan-16   0
    1           2       31-Jan-16   0
    2           3       31-Jan-16   0
    2           4       24-Jan-16   10
    2           5       24-Jan-16   0
    2           7       24-Jan-16   0
    2           9       24-Jan-16   0

SQDC_DEPARTMENTS

    ID Name   Facility_ID VS_ID
    1  Dept 1 2           1
    2  Dept 2 2           1
    3  Dept 3 2           2
    4  Dept 4 2           2

SQDC_VALUE_STREAMS

    ID Name   Facility_ID
    1  VS 1   2
    2  VS 2   2

提前感谢任何能帮助我指明正确方向的人。

编辑以添加预期结果:

站点 1(无流):

    ID Name  Color RNUM
    1  Table GREEN 1
    2  Lamp  GREEN 2

站点 2(带流):

    ID Name Color RNUM
    1  VS 1 GREEN 1
    2  VS 2 WHITE 2

我知道我缺少一些额外的函数或运算符来使它按照我喜欢的方式工作,所以让我们看看我是否可以重新表述期望:

我想显示设施使用的最高级别(流、部门或产品)的 ID、名称和安全值颜色代码,并在最近一天提供了信息。

根据 VS 和部门表,站点 1 没有任何流或部门,因此应该填充产品列表。使用提供的数据,站点 1 将单独显示两种产品并显示绿色值,因为两种产品数据均来自 2016 年 1 月 31 日且值为 0。如果站点 1 下有其他产品包含该日期之前的数据,则颜色将无论实际安全值如何,都为白色。

站点 2 最好显示仅包含两个价值流的列表(因为这是最高级别)。

站点 2 的最晚日期是 2016 年 1 月 31 日。在 VS 1 下的产品线中,只有 Line_ID=3 有这个日期(其他线有更早的日期)。因此,平均安全值将为 0(Line_ID=4 的 10 由于日期较早,不会成为平均值的一部分),然后颜色为绿色。

VS 2 下所有产品线的安全值均在 2016 年 1 月 31 日之前,因此未计算平均值,因此结果为白色。

希望这有助于解决问题。

来自@Hogan 的每个请求的单个案例查询:

价值流级别查询(如网站 2):

    select *
          from
        (select a.*, rownum rnum
           from
           (SELECT stream_id, NAME,  case when SUM(SAFETY_VALUE) = 0 then 'GREEN'  when SUM(SAFETY_VALUE) > 0 then 'RED' else 'WHITE' end AS COLOR 
    FROM SQDC_VALUE_STREAMS VLS  LEFT JOIN SQDC_VALUE_STREAM_DETAILS VS ON VLS.ID = VS.STREAM_ID LEFT JOIN SQDC_SAFETY_MAX KPI ON VS.LINE_ID=KPI.LINE_ID 

    WHERE (vs.facility_id = 2
    )
    group by name, STREAM_id
    ORDER by NAME) a
    )

部门级查询(示例中没有这样的站点,但它会以相同的方式工作):

    select *
          from
        (select a.*, rownum rnum
           from
           (SELECT dept_id, NAME,  case when SUM(SAFETY_VALUE) = 0 then 'GREEN'  when SUM(SAFETY_VALUE) > 0 then 'RED' else 'WHITE' end AS COLOR 
    FROM SQDC_DEPARTMENTS DPTS  LEFT JOIN SQDC_DEPARTMENT_DETAILS DT ON DPTS.ID = DT.Dept_ID LEFT JOIN SQDC_SAFETY_MAX KPI ON DT.LINE_ID=KPI.LINE_ID

    WHERE (DT.facility_id = 7986128121911792
    )
    group by name, DEPT_id
    ORDER by NAME) a
    )

产品级别查询(如站点 1):

    select *
          from
        (select a.*, rownum rnum
           from
           (SELECT line, NAME,  case when SAFETY_VALUE = 0 then 'GREEN'  when      SAFETY_VALUE > 0 then 'RED' else 'WHITE' end AS COLOR 
    FROM XX_SQDC_LINES_REF SLR  LEFT JOIN SQDC_SAFETY_MAX KPI ON     SLR.LINE=KPI.LINE_ID 

    WHERE (SITE = 1
    )
    ORDER by NAME) a
    )

目标是将这三个查询合并为一个,并确保只显示设施的最高组织级别(流、部门、产品)。

鉴于您的 3 个查询,不难将它们与您描述的规则合并。

我知道,这不像 COALESCE 和许多花哨的连接那样性感,但我认为这可能是最好的方法,因为它非常清晰,因此易于维护。

WITH stream_query AS
(
  SELECT 1 AS PRIORITY, stream_id, null as dept_id, null as line, NAME, COLOR, rownum rnum
  FROM (
    SELECT stream_id, NAME,  case when SUM(SAFETY_VALUE) = 0 then 'GREEN'  when SUM(SAFETY_VALUE) > 0 then 'RED' else 'WHITE' end AS COLOR
    FROM SQDC_VALUE_STREAMS VLS
    LEFT JOIN SQDC_VALUE_STREAM_DETAILS VS ON VLS.ID = VS.STREAM_ID
    LEFT JOIN SQDC_SAFETY_MAX KPI ON VS.LINE_ID=KPI.LINE_ID 
    WHERE vs.facility_id = 2
    group by name, STREAM_id
    ORDER by NAME
  ) a
), dept_query AS
(
  SELECT 2 AS PRIORITY, null as stream_id, dept_id, null as line, NAME, COLOR, rownum rnum 
  FROM (
    SELECT dept_id, NAME,  case when SUM(SAFETY_VALUE) = 0 then 'GREEN'  when SUM(SAFETY_VALUE) > 0 then 'RED' else 'WHITE' end AS COLOR 
    FROM SQDC_DEPARTMENTS DPTS  
    LEFT JOIN SQDC_DEPARTMENT_DETAILS DT ON DPTS.ID = DT.Dept_ID 
    LEFT JOIN SQDC_SAFETY_MAX KPI ON DT.LINE_ID=KPI.LINE_ID
    WHERE DT.facility_id = 7986128121911792
    group by name, DEPT_id
    ORDER by NAME
  ) a
), prod_query AS
(
  SELECT 3 AS PRIORITY, null as stream_id, null as dept_id, line, NAME, COLOR, rownum rnum
  FROM (
    SELECT line, NAME,  case when SAFETY_VALUE = 0 then 'GREEN'  when      SAFETY_VALUE > 0 then 'RED' else 'WHITE' end AS COLOR 
    FROM XX_SQDC_LINES_REF SLR 
    LEFT JOIN SQDC_SAFETY_MAX KPI ON     SLR.LINE=KPI.LINE_ID 
    WHERE SITE = 1
    ORDER by NAME
  ) a
), merged AS
(
  SELECT a.*, MIN(PRIORITY) OVER () AS HIGHEST 
  FROM (
    SELECT * FROM stream_query
      UNION ALL
    SELECT * FROM dept_query
      UNION ALL
    SELECT * FROM prod_query
  ) a  
)
SELECT *
FROM merged
WHERE PRIORITY = HIGHEST

您的想法已找到,但您没有正确设置联接。您需要从 XX_SQDC_LINES_REF 或 SQDC_DEPARTMENT_DETAILS 离开加入——您没有这样做,您是加入到之前的加入

SELECT /*STREAM_ID, DEPT_ID ,LINE,*/ 
  COALESCE(VS.ID, DT.ID, SLR.LINE) "ID", 
  COALESCE(VS.NAME, DT.NAME, SLR.NAME) "NAME", 
  case when SAFETY_VALUE = 0 then 'GREEN' when SAFETY_VALUE > 0 then 'RED' else 'WHITE' end AS COLOR,
  rownum rnum
FROM XX_SQDC_LINES_REF SLR  
LEFT JOIN SQDC_DEPARTMENT_DETAILS DTD   on SLR.SITE=DTD.FACILITY_ID AND SLR.LINE=DTD.LINE_ID
LEFT JOIN SQDC_VALUE_STREAM_DETAILS VSD ON SLR.SITE=VSD.FACILITY_ID AND SLR.LINE=VSD.LINE_ID
LEFT JOIN SQDC_SAFETY_MAX KPI           ON SLR.SITE=KPI.FACILITY_ID AND SLR.LINE=KPI.LINE_ID
LEFT JOIN SQDC_DEPARTMENTS DT           ON SLR.SITE=DT.FACILITY_ID and  DTD.dept_id=DT.id
LEFT JOIN SQDC_VALUE_STREAMS VS         ON SLR.SITE=VS.FACILITY_ID AND  DTD.VS_ID=VS.ID
WHERE (SITE = 2)
ORDER by NAME

我还删除了所有子查询内容,因为那不是必需的,只会让它变得更复杂 (IMO)

在@Hogan 的帮助下,这里是完成的查询:

SELECT COALESCE(STREAM_ID, DEPT_ID, TO_CHAR(LINE)) ID, NAME,COLOR
FROM(
WITH  stream_query AS
(
  SELECT 1 AS PRIORITY, stream_id, null as dept_id, null as line, NAME, COLOR, rownum rnum
  FROM (
    SELECT stream_id, NAME,  case when SUM(SAFETY_VALUE) = 0 then 'GREEN' when SUM(SAFETY_VALUE) > 0 then 'RED' else 'WHITE' end AS COLOR
    FROM SQDC_VALUE_STREAMS VLS
    LEFT JOIN SQDC_VALUE_STREAM_DETAILS VS ON VLS.ID = VS.STREAM_ID
    LEFT JOIN (select line_id, safety_value, actual_date from SQDC_SAFETY_MAX where actual_date in (select max(actual_date) from SQDC_SAFETY_MAX)) KPI ON VS.LINE_ID=KPI.LINE_ID 
    WHERE vs.facility_id = [replace1]
    group by name, STREAM_id
    ORDER by NAME
  ) a
), dept_query AS
(
  SELECT 2 AS PRIORITY, null as stream_id, dept_id, null as line, NAME, COLOR, rownum rnum 
  FROM (
    SELECT dept_id, NAME,  case when SUM(SAFETY_VALUE) = 0 then 'GREEN'  when SUM(SAFETY_VALUE) > 0 then 'RED' else 'WHITE' end AS COLOR 
    FROM SQDC_DEPARTMENTS DPTS  
    LEFT JOIN SQDC_DEPARTMENT_DETAILS DT ON DPTS.ID = DT.Dept_ID 
    LEFT JOIN (select line_id, safety_value, actual_date from SQDC_SAFETY_MAX where actual_date in (select max(actual_date) from SQDC_SAFETY_MAX)) KPI ON DT.LINE_ID=KPI.LINE_ID
    WHERE DT.facility_id = [replace1]
    group by name, DEPT_id
    ORDER by NAME
  ) a
), prod_query AS
(
  SELECT 3 AS PRIORITY, null as stream_id, null as dept_id, line, NAME, COLOR, rownum rnum
  FROM (
    SELECT line, NAME,  case when SAFETY_VALUE = 0 then 'GREEN'  when      SAFETY_VALUE > 0 then 'RED' else 'WHITE' end AS COLOR 
    FROM XX_SQDC_LINES_REF SLR 
    LEFT JOIN SQDC_SAFETY_MAX KPI ON     SLR.LINE=KPI.LINE_ID 
    WHERE SITE =[replace1]
    ORDER by NAME
  ) a
),merged AS
(
  SELECT a.*, MIN(PRIORITY) OVER () AS HIGHEST 
  FROM (
    SELECT * FROM stream_query
      UNION ALL
    SELECT * FROM dept_query
      UNION ALL
    SELECT * FROM prod_query
  ) a  
)
SELECT *
FROM merged
WHERE PRIORITY = HIGHEST
)
where rownum <=12
AND rnum >=1

我在 select 中添加了更多内容以获取最新的可用日期并限制行数和列数,但这对测试用例和我的实际数据都有效。再次感谢@Hogan。