【问题标题】:PL-SQL - First record in a One-to-Many relation left joinPL-SQL - 一对多关系中的第一条记录左连接
【发布时间】:2017-12-30 06:12:54
【问题描述】:

我正在尝试在 Oracle 中使用 LEFT JOIN 连接两个表。我只需要包含“右”连接表中的第一条记录。

请看下面的例子:

表 A

code | emp_no

101  | 11111
102  | 22222
103  | 33333
104  | 44444
105  | 55555

表 B

code | city       | county

101  | City1      | Country1
101  | City2      | Country1
101  | City3      | Country1
102  | City4      | Country2
103  | City5      | Country3

预期输出:

code | emp_no | city      | county

101  | 11111  | City1     | Country1
102  | 22222  | City4     | Country2
103  | 33333  | City5     | Country3
104  | 44444  | NULL      | NULL
105  | 55555  | NULL      | NULL

我需要从表 B 中选择第一个匹配的记录并忽略所有其他行。

上面的查询假设有效:

SELECT *
FROM TABLE_A a
   LEFT JOIN TABLE_B b ON b.CODE = a.CODE
      AND b.CODE = 
      (
         SELECT CODE
         FROM TABLE_B
         WHERE ROWNUM = 1
      )

但是我得到了错误: ORA-01799: 列不能外连接到子查询

我该怎么做?

谢谢

【问题讨论】:

  • 你如何决定哪个是“第一”?
  • 注意:目前尚不清楚您要通过仅检索 ROWNUM = 1 来实现什么。反正我已经写好了答案。

标签: oracle join plsql left-join


【解决方案1】:

您可以使用 min() 聚合函数和 the keep (dense_rank first ...) syntax 从外连接表中获取“第一个”匹配数据:

select a.code, a.emp_no,
  min(b.city) keep (dense_rank first order by city, county) as city,
  min(b.county) keep (dense_rank first order by city, county) as county
from table_a a
left join table_b b on b.code = a.code
group by a.code, a.emp_no
order by a.code, a.emp_no;

      CODE     EMP_NO CITY  COUNTY  
---------- ---------- ----- --------
       101      11111 City1 Country1
       102      22222 City4 Country2
       103      33333 City5 Country3
       104      44444               
       105      55555               

您必须定义“第一”的含义 - 我在 keep 子句中使用了city, county 的顺序,但您可能还有另一列未显示,应该规定顺序。

(您可以按 null 排序以使其有些随意,但这通常不是一个好主意,尤其是稍后运行相同的查询可能会为相同的数据给出不同的结果。)

【讨论】:

  • 感谢亚历克斯,辛苦了!澄清一下,我使用的是 BIRT(集成了 PL-SQL),而我的实际情况比这更复杂。 1. 我的“第一”行是基于最近更改的 (LST_UPD_TSTMP) 2. 此问题将与当前包含用户信息的现有报告连接,例如“ID,名称...” 3. TABLE_B 基本上包含: STUD_ID (PK, FK); DEL_STUD_ID(获得用户权限的用户)(PK,FK); LST_UPD_TSTMP (NOT NULL) 4. 在此之后我需要再次加入以带来有关 DEL_STUD_ID 的信息我将尝试在我的报告中使用此查询并在此处更新好吗?
  • @IgorIvanov - 听起来您需要在两个keep 子句中使用order by lst_upd_tstmp desc。 (或者,如果您认为它读起来更好,请使用last 而不是first,这样您就不需要desc:即max(b.city) keep (dense_rank last order by last_upd_tstmp) 等)
【解决方案2】:

在 Oracle 12c 上,您可以使用 OUTER APPLYFETCH FIRST 子句:

SELECT *
FROM tableA  a
OUTER APPLY (
   SELECT * FROM tableB b
   WHERE a.code = b.code
   ORDER BY city, county
   FETCH FIRST ROW ONLY
)

      CODE     EMP_NO       CODE CITY  COUNTY  
---------- ---------- ---------- ----- --------
       101      11111        101 City1 Country1
       102      22222        102 City4 Country2
       103      33333        103 City5 Country3
       104      44444                          
       105      55555   

【讨论】:

  • 谢谢,这很简单!但它是11g。我们可以在 11g 上使用类似的东西吗?
【解决方案3】:

使用row_number()函数获取row_number()= 1的记录

SELECT select a.code,
       a.emp_no,
       b.city,
       b.county
FROM   table_a a
       left join (SELECT code,
                         city,
                         county,
                         row_number()
                           over (
                             PARTITION BY code
                             ORDER BY city, county ) rn
                  FROM   table_b) b
              ON b.code = a.code
                 WHERE rn = 1 OR rn IS NULL;  

注意:从问题中仍然不清楚这实际上意味着什么。

“右”连接表中的第一条记录

【讨论】:

  • 目前只为您提供来自a 的一个代码的b.code 值,而您已经拥有了;它没有给你任何行的城市/县?
  • 我的第一条记录是基于LST_UPD_TSTMP(真实情况)。我不明白我应该在 id 中使用什么:PARTITION BY id.
  • @IgorIvanov - 看起来你会使用PARTITION BY code。但目前不会显示 104 或 105 行;您可以将最后一行更改为 WHERE rn IS NULL OR rn = 1 来解决这个问题...
  • @Alex Poole 根据建议编辑。谢谢!
猜你喜欢
  • 2011-12-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-07
  • 2013-12-03
相关资源
最近更新 更多