【问题标题】:Can INNER JOIN replace a column's value with another value from the same table - for all rowsINNER JOIN 可以用同一个表中的另一个值替换列的值 - 对于所有行
【发布时间】:2017-06-25 07:08:04
【问题描述】:

我需要编写一个查询,用同一表中另一行的值替换其中一个列的值。我尝试使用简单的内部连接,但没有看到我需要的结果。

以下是表 BANK_LOANS 的示例:

MONTH_ID   LOAN_NUMBER    BANK_NAME       AMOUNT
========   ===========    ==========      ========
76         00-100         Bank One        100.00
75         00-100         The Bank One    150.00
74         00-100         Bank 1          150.00
76         00-200         Another Bank    300.00 
75         00-200         Another Bank    500.00

数据是从不验证银行名称的外部来源加载的,因此给定贷款编号的银行名称的拼写可能会有所不同。客户希望数据库中的任何 BANK_NAME 最大 MONTH_ID 用于该 LOAN_NUMBER 的所有结果,并且他们希望结果按 BANK_NAME 排序。例如,贷款 00-100 的所有行都需要一个 BANK_NAME 为“Bank One”。

我尝试使用内部联接来执行此操作,但没有得到正确的结果

SELECT name.BANK_NAME, 
       bl.LOAN_NUMBER,
       bl.AMOUNT
FROM BANK_LOANS    
INNER JOIN BANK_LOANS home
    ON name.LOAN_NUMBER = bl.LOAN_NUMBER
    AND name.MONTH_ID = 67  --the max id provided to the query
ORDER BY name.BANK_NAME, bl.LOAN_NUMBER, bl.MONTH_ID DESC

我认为我可以使用子查询,但它有点难看。我想知道是否有更好的方法(最佳实践)通过连接或其他 oracle 函数来完成此任务。

这似乎可行,但感觉不对:

SELECT name.BANK_NAME, 
       bl.LOAN_NUMBER,
       bl.AMOUNT
FROM BANK_LOANS, 
     (SELECT bl2.BANK_NAME, bl2.LOAN_NUMBER
      FROM BANK_LOANS
      WHERE bl2.MONTH_ID = 76  --max month id provided to query
     ) name
WHERE name.LOAN_NUMBER = bl.LOAN_NUMBER
ORDER BY name.BANK_NAME, bl.LOAN_NUMBER, bl.MONTH_ID DESC

【问题讨论】:

  • 任何包含逗号“感觉不对”的FROM 子句。
  • @GordonLinoff - 有少数例外;例如,具有快速刷新功能的物化视图不支持标准连接语法,它们需要旧的 Oracle 语法以及 WHERE 子句中的连接条件。只有甲骨文知道为什么。

标签: sql oracle join subquery


【解决方案1】:

使用解析函数:

select bl.loannumber, bl.amount,
       max(bank_name) keep (dense_rank first order by month_id desc) over (partition by loannumber) as bank_name
from bank_loans bl;

【讨论】:

  • 这是一个聚合函数(没有分区子句),所以解析器会抛出语法错误,因为没有 GROUP BY 子句。
【解决方案2】:
with
     test_data ( month_id, loan_number, bank_name, amount ) as (
       select 76, '00-100', 'Bank One'    , 100.00 from dual union all
       select 75, '00-100', 'The Bank One', 150.00 from dual union all
       select 74, '00-100', 'Bank 1'      , 150.00 from dual union all
       select 76, '00-200', 'Another Bank', 300.00 from dual union all
       select 75, '00-200', 'Another Bank', 500.00 from dual
     )
-- end of test data (not part of the solution).
-- SQL query begins BELOW THIS LINE; use with your table.
select month_id, loan_number, 
       first_value(bank_name) 
              over (partition by loan_number order by month_id desc) as bank_name,
       amount
from   test_data
;

MONTH_ID LOAN_N BANK_NAME    AMOUNT
-------- ------ ------------ ------
      74 00-100 Bank One        150
      75 00-100 Bank One        150
      76 00-100 Bank One        100
      75 00-200 Another Bank    500
      76 00-200 Another Bank    300

5 rows selected.

【讨论】:

  • 感谢@mathguy 的帖子!我将研究 first_value() 函数和 partition 子句,并尝试将其用于我们的查询。
  • @Roy - 您需要“研究”的是分析函数(有时不正确地称为窗口函数)的一般概念。 partition 子句是其中的主要概念之一,first_value() 是分析函数之一。好处是它们都以非常相似的方式工作,因此只要花费合理的时间学习它们,您就会一次获得很多工具。祝你好运!
【解决方案3】:
SELECT month_id,
   loan_number,
   MIN(bank_name) over(PARTITION BY loan_number ORDER BY month_id DESC),
   amount
FROM bank_loans;

【讨论】:

  • 错误的分析函数(并且,使用 ORDER BY 子句,无论如何它将是移动窗口上的 MIN)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-16
  • 2016-07-22
  • 2013-03-20
  • 1970-01-01
  • 2019-04-10
相关资源
最近更新 更多