需要帮助将两组3个表连接成1个主表

时间:2015-04-21 19:04:17

标签: sql oracle11g

很难弄清楚如何编写一些代码来加入一堆表。

基本上,我有两个组的3个表,我可以INNER JOIN。那些产生的两组具有我想要的所有信息,除了我似乎无法将它们组合成单个输出。

看起来像这样。

enter image description here

我也包括了表名。请注意,“rq”在两者中,并且基本上是我正在尝试将所有内容链接回来的主表。还有另一个名为rl_rq的表,我可以使用它而不是使用rq两次,但它似乎并不重要,因为rq包含我需要的ID。

基本上,一组表存储了申请单,申请单板和内部完成的测试结果。另一组表(用“rl”表示)是申请单,申请单板和参考实验室处理的测试结果。它们带有几乎相同的数据。

我尝试了一系列不同的方法,但似乎无法得到我想要的东西。我想我可能需要做一些类型的子查询,我只能通过改变JOINS的类型来实现这一点,但我不确定。我尝试可视化和测试不同的连接方法总是导致数据被丢弃,因为一旦我加入说rp到rq,rq不再包含我需要将rl_rp链接到rq的acc_id。我没想做完全加入...

这是一些修剪过的代码(你不需要看到我做同样的事情15次)。

对于内部请购单,我可以执行以下操作;

 SELECT
 rq.acc_id AS "Accession #"
,MAX (CASE WHEN rs.test_id = 102  THEN rs.result_numeric     END) AS "Glucose"
,LISTAGG (CASE WHEN rs.test_id = 831   THEN rs.result_alpha END, ';')
                          WITHIN GROUP (ORDER BY rs.result_alpha) AS "Crystal ID"
FROM      requisitions  rq

INNER JOIN  req_panels    rp  ON  rp.acc_id  = rq.acc_id
INNER JOIN  results       rs  ON  rs.rp_id   = rp.rp_id
WHERE    rq.RECEIVED_DATE > TO_DATE('9/1/2013', 'MM/DD/YYYY')
AND      rp.PANEL_ID IN (7000,...,7400)
AND      rs.TEST_ID  IN (7101,...,7400)

GROUP BY  rq.acc_id
ORDER BY  rq.acc_id

正如您所看到的,由于我必须进行一些演示,分组和聚合,所以它会更加复杂。

对于参考实验室数据,我可以运行以下内容;

SELECT
rq.acc_id AS "Accession #"
,MAX (CASE WHEN rl.profile_id = '738770' THEN rlr.RESULT_NUMERIC || dbms_lob.substr(rlr.RESULT_ALPHA,4000,1) END) AS "Chromium,Cobalt/Nickel, WB"
FROM      requisitions  rq

INNER JOIN  rl_req_panels rl  ON  rl.acc_id  = rq.acc_id
INNER JOIN  rl_results    rlr ON  rlr.rp_id  = rl.rp_id

WHERE     rq.RECEIVED_DATE > TO_DATE('9/1/2013', 'MM/DD/YYYY')              
          AND rl.profile_id IN ('738770','738774','738778','738780')

GROUP BY  rq.acc_id
ORDER BY  rq.acc_id

3 个答案:

答案 0 :(得分:1)

将select语句想象为一个表。它有一些列(SELECT列表中的列)并包含数据(select语句返回的行),就像表一样。考虑到这一点,您可以将整个第二个选择语句加入rq,如下所示:

SELECT
 ISNULL(rq.acc_id, t."Accession #") AS "Accession #"
,MAX (CASE WHEN rs.test_id = 102  THEN rs.result_numeric     END) AS "Glucose"
,LISTAGG (CASE WHEN rs.test_id = 831   THEN rs.result_alpha END, ';')
                          WITHIN GROUP (ORDER BY rs.result_alpha) AS "Crystal ID"
,t."Chromium,Cobalt/Nickel, WB"
FROM      requisitions  rq

INNER JOIN  req_panels    rp  ON  rp.acc_id  = rq.acc_id
INNER JOIN  results       rs  ON  rs.rp_id   = rp.rp_id
FULL JOIN (SELECT
            rq2.acc_id AS "Accession #"
           ,MAX (CASE WHEN rl.profile_id = '738770' THEN rlr.RESULT_NUMERIC || dbms_lob.substr(rlr.RESULT_ALPHA,4000,1) END) AS "Chromium,Cobalt/Nickel, WB"
            FROM      requisitions  rq2

            INNER JOIN  rl_req_panels rl  ON  rl.acc_id  = rq2.acc_id
            INNER JOIN  rl_results    rlr ON  rlr.rp_id  = rl.rp_id

            WHERE     rq2.RECEIVED_DATE > TO_DATE('9/1/2013', 'MM/DD/YYYY')              
            AND rl.profile_id IN ('738770','738774','738778','738780')
            GROUP BY  rq2.acc_id) t ON t."Accession #" = rq.acc_id

WHERE    rq.RECEIVED_DATE > TO_DATE('9/1/2013', 'MM/DD/YYYY')
AND      rp.PANEL_ID IN (7000,...,7400)
AND      rs.TEST_ID  IN (7101,...,7400)

GROUP BY  rq.acc_id
ORDER BY  rq.acc_id, t."Accession #"

我使用FULL JOIN加入SELECT语句,因为INNER JOIN只返回rqacc_id匹配的rq2行1}},因此您可能无法在rp / rs / rl / rlr中看到一些记录。

答案 1 :(得分:1)

我不确定为什么你不能使用OUTER JOIN。您可以按如下方式将其分解:

WITH rq_filtered AS (
  SELECT
    rq.acc_id
  , ......
  FROM rq
  WHERE ........
), in_house AS (
  SELECT 
    rq_filtered.acc_id
  , ........
  FROM rq_filtered
  JOIN rp ON ...
  JOIN r ON ....
), ref_lab AS (
  SELECT
    rq_filtered.acc_id
  , ......
  FROM rq_filtered
  JOIN rl_rp ON ...
  JOIN rl_r ON ...
)
SELECT 
  -- cols from rqf (rq)
  -- cols from in house (optional)
  -- cols from ref lab (optional)
FROM rq_filtered rqf
LEFT JOIN in_house ih ON rqf.acc_id = ih.acc_id
LEFT JOIN ref_lab rl ON rqf.acc_id = rl.acc_id

这会使您的工作集rq成为您的共性,您可以将其过滤掉。然后,您可以根据第一个过滤器生成2个数据集。最后在外部查询中,您将外部数据集连接到内部,并将ref实验室全部关闭到acc_id,最后假定单行基数(通过在您的因子子查询中聚合)。


当我误解你的情景时的原始答案

您应该查看UNION集合运算符,它允许您将两个结果集“连接”在一起。 SQL (wiki)Oracle specific

限制是您的结果集应返回相同数量的列和相应的数据类型。从你的图表:

SELECT
  col_a
, col_b
, col_c
FROM r
JOIN rp ON ....
JOIN rq ON ....
UNION
SELECT
  col_d
, col_e
, col_f
FROM rq
JOIN rl_rp ON ....
JOIN rl_r ON ....

只要col_acol_d是相同的数据类型等,这就可以工作。

这也会删除重复的行。为了提高性能但没有重复检查,请使用UNION ALL

还有其他“设置操作”,例如MINUS,可让您从另一个结果集中减去一个结果集,从而可以在两个查询之间进行智能比较,例如:

SELECT
  'In a but not b' set_desc
, a.*
FROM a
MINUS
SELECT
  'In a but not b' set_desc
, b.*
FROM b 
UNION
SELECT
  'In b but not a' set_desc
, b.*
FROM b
MINUS
SELECT
  'In b but not a' set_desc
, a.*
FROM a

将显示表a和b之间不同的行,并指出它们在/中的位置。

答案 2 :(得分:0)

所以我回头看了一下我写给JOIN rq rprl_rp的另一个查询后,能够让这个工作并返回必要的数据。

它只使用多个LEFT JOIN和特定ONWHERE子句。我怀疑这是处理这种情况的正确或最有效的方法,但它已经奏效了。也许有人可以查看这段代码并以更有效的方式重写它。这是代码的jist(删除一些select语句以将其缩短一点)。

SELECT
 rq.acc_id                               AS "Accession ID"
,MAX(rp.RUN_DATE)                        AS "Run Date"
,MAX(doc.L_NAME || ' ' || doc.f_name)    AS "Physician Name"
,MAX(org.ORG_NAME)                       AS "Organization"
,MAX(org.STATE)                          AS "State"

/*Define TYPE of test*/
,MAX (CASE WHEN rp.panel_id IN (7000,70001)            THEN 'Type 1'
         WHEN rp.panel_id IN (7400)                    THEN 'Type 2'
         WHEN rl_rp.profile_id IN ('738774','738780')  THEN 'Type 3'
         WHEN rl_rp.profile_id IN ('738770','738778')  THEN 'Type 4'                                            END)  AS "Panel Ordered"

,MAX (CASE WHEN rp.panel_id IN (70551)                 THEN 'Culture'                                           END)  AS "Culture Ordered"

/*Try to get Joint, but only available through Cultured Data*/
,MAX (CASE WHEN rs.test_id  = 7110 THEN dbms_lob.substr(rs.result_alpha,4000,1)                                END)  AS "Joint"

/*Get Numeric Results for certain Test_ID's*/
,MAX (CASE WHEN rs.test_id = 7102                            THEN rs.result_numeric                            END)  AS "Hemaglobin"

/*Get Alpha Results for certain Test_ID's*/
,LISTAGG (CASE WHEN rs.test_id = 831   THEN rs.result_alpha   END, ';') WITHIN GROUP (ORDER BY rs.result_alpha)      AS "Crystal ID"

/*Culture Data*/
,LISTAGG (CASE WHEN rs.test_id = 10010 THEN rs.result_alpha   END, ';') WITHIN GROUP (ORDER BY rs.result_alpha)      AS "Organism"

/*Whole Blood Tests Results*/
,MAX(CASE WHEN rl_rs.TEST_NO = '738771' THEN rl_rs.RESULT_NUMERIC || dbms_lob.substr(rl_rs.RESULT_ALPHA,4000,1) END) AS "Chromium, WB"
,MAX(CASE WHEN rl_rs.TEST_NO = '738772' THEN rl_rs.RESULT_NUMERIC || dbms_lob.substr(rl_rs.RESULT_ALPHA,4000,1) END) AS "Cobalt, WB"
,MAX(CASE WHEN rl_rs.TEST_NO = '790447' THEN rl_rs.RESULT_NUMERIC || dbms_lob.substr(rl_rs.RESULT_ALPHA,4000,1) END) AS "Nickel, WB"

/*Serum/Plasma Test Results*/
,MAX(CASE WHEN rl_rs.TEST_NO = '738775' THEN rl_rs.RESULT_NUMERIC || dbms_lob.substr(rl_rs.RESULT_ALPHA,4000,1) END) AS "Chromium, S/P"
,MAX(CASE WHEN rl_rs.TEST_NO = '738776' THEN rl_rs.RESULT_NUMERIC || dbms_lob.substr(rl_rs.RESULT_ALPHA,4000,1) END) AS "Cobalt, S/P"
,MAX(CASE WHEN rl_rs.TEST_NO = '738779' THEN rl_rs.RESULT_NUMERIC || dbms_lob.substr(rl_rs.RESULT_ALPHA,4000,1) END) AS "Nickel, S/P"

FROM requisitions rq

LEFT  JOIN req_panels    rp    ON (rq.acc_id = rp.acc_id AND rp.PANEL_ID IN (7000,70551,7400,70001,8260,7120,831) AND rp.DEL_FLAG='F')
LEFT  JOIN results       rs    ON (rs.RP_ID = rp.RP_ID AND rs.DEL_FLAG='F')
LEFT  JOIN rl_req_panels rl_rp ON (rq.acc_id = rl_rp.acc_id AND rl_rp.PROFILE_ID IN ('738770','738774','738778','738780') AND rl_rp.DEL_FLAG='F')
LEFT  JOIN rl_results    rl_rs ON (rl_rs.RP_ID = rl_rp.RP_ID AND rl_rs.DEL_FLAG='F')
INNER JOIN doctors       doc   ON rq.doc_id1 = doc.doc_id
INNER JOIN organizations org   ON rq.org_id = org.org_id

WHERE
(rl_rp.PROFILE_ID IN ('738770','738774','738778','738780') AND rl_rp.DEL_FLAG='F'
OR rp.PANEL_ID IN (7000,70551,7400,70001,8260,7120,831)    AND rp.DEL_FLAG='F')
AND rq.DEL_FLAG='F'
AND rq.RECEIVED_DATE > TO_DATE('9/1/2013', 'MM/DD/YYYY')

GROUP BY rq.acc_id
ORDER BY rq.acc_id DESC