很难弄清楚如何编写一些代码来加入一堆表。
基本上,我有两个组的3个表,我可以INNER JOIN。那些产生的两组具有我想要的所有信息,除了我似乎无法将它们组合成单个输出。
看起来像这样。
我也包括了表名。请注意,“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
答案 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
只返回rq
中acc_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_a
和col_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
rp
和rl_rp
的另一个查询后,能够让这个工作并返回必要的数据。
它只使用多个LEFT JOIN
和特定ON
和WHERE
子句。我怀疑这是处理这种情况的正确或最有效的方法,但它已经奏效了。也许有人可以查看这段代码并以更有效的方式重写它。这是代码的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