简体   繁体   English

SQL连接两个表,但是如果第二个表中存在第一个表,则覆盖第一个表

[英]SQL Joining two tables but overwriting the first if it exists in the second

I can't get this query to work the way I want it to. 我无法使此查询按我希望的方式工作。 I have two tables with almost identical data but want one to override the other if it exists. 我有两个具有几乎相同数据的表,但希望其中一个可以覆盖另一个(如果存在)。 An example would be easier than trying to explain: 一个例子比尝试解释要容易:

There is an unadjusted balance table: 有未调整的余额表:

未调整余额

and a separate table for adjustments for each balance 还有一个单独的表格,用于调整每个余额 在此处输入图片说明

the desired output takes unadjusted balances and applies any existing adjustments on top of it (if is_current=1)... essentially replacing the row but still keeping the original unadjusted current_balance. 所需的输出将获得未调整的余额,并在其之上应用任何现有的调整(如果is_current = 1)...本质上将替换该行,但仍保留原始的未调整的current_balance。

the desired output would be something like this: 所需的输出将是这样的:

在此处输入图片说明

here is my current query that is not working how I want... it is flipping values and missing current_balance. 这是我当前的查询无法正常工作...它正在翻转值并缺少current_balance。 i've been trying this for hours and can't get anywhere: 我已经尝试了几个小时,却无法到达任何地方:

SELECT
*
FROM
  (
    SELECT
      balance_adjustments.name,
      balance_adjustments.user_id,
      balance_adjustments.amount_owed,
      balance_adjustments.when_to_pay,
      balance_adjustments.current_balance
    FROM
      balance_adjustments
    WHERE
      balance_adjustments.when_to_pay = '2018-11-05'
      AND balance_adjustments.is_current = true
    UNION ALL
    SELECT
      unadjusted_balance.name,
      unadjusted_balance.user_id,
      unadjusted_balance.amount_owed,
      unadjusted_balance.when_to_pay,
      unadjusted_balance.current_balance
    FROM
      unadjusted_balance
      LEFT OUTER JOIN balance_adjustments ON balance_adjustments.user_id = unadjusted_balance.user_id
      AND balance_adjustments.name = unadjusted_balance.name
      AND balance_adjustments.when_to_pay = unadjusted_balance.when_to_pay
      AND balance_adjustments.is_current = true
    WHERE
      unadjusted_balance.when_to_pay = '2018-11-05'
      AND balance_adjustments.name IS NULL
  ) AS table1

some additional commands to help anyone set this scenario up to test: 一些其他命令可帮助任何人设置此方案进行测试:

CREATE TABLE balance_adjustments
(
name varchar(30),
    user_id varchar(30),
    amount_owed float,
    when_to_pay datetime,
    current_balance float,
    is_current boolean
);


CREATE TABLE unadjusted_balance
(
name varchar(30),
    user_id varchar(30),
    amount_owed float,
when_to_pay datetime,
current_balance float
);


insert into balance_adjustments values ('ricardo', '82340001', 100.00, '2018-11-05', null, 1)
insert into balance_adjustments values ('ricardo', '82340001', 33.00, '2018-11-05', null, 0)

insert into unadjusted_balance values ('joseph', '82340000', 2400.00, '2018-11-05', 4049.00)
insert into unadjusted_balance values ('ricardo', '82340001', 899.00, '2018-11-05', 500.00)

thanks for any help 谢谢你的帮助

If you want to overwrite the unadjusted balance with balance adjustments then do do the following: 如果要使用余额调整覆盖未调整的余额,请执行以下操作:

  • Select all unadjusted balances. 选择所有未调整的余额。
  • Left Join to adjustments so you can get any adjustments, making sure to filter out those who have is_current = 1. 左加入调整项,以便获得任何调整项,确保滤除is_current = 1的那些项。
  • Use the sum of amount_owed in adjustments to get the overwrite amount. 使用调整中的amount_owed的总和来获取覆盖量。
  • In order to default to the original if there is no adjustments, use coalesce outside of the sum, and have the original amount as the second parameter. 为了在没有调整的情况下默认为原始值,请在总和之外使用合并,并将原始量用作第二个参数。

Coalesce will return the first value if it is not null, or the value of the next parameter otherwise. 如果不为空,则Coalesce将返回第一个值,否则返回下一个参数的值。 The result of the sum aggregate will be null if no rows are returned from the left join. 如果左联接未返回任何行,则总和的结果将为null。

Query 询问

SELECT ub.name
    , ub.user_id
    , COALESCE(SUM(ba.amount_owed), ub.amount_owed) AS amount_owed 
    , ub.when_to_pay
    , ub.current_balance
FROM @unadjusted_balance AS ub
LEFT JOIN @balance_adjustments AS ba ON ba.user_id = ub.user_id AND ba.is_current = 1
GROUP BY ub.name, ub.user_id, ub.amount_owed, ub.when_to_pay, ub.current_balance;

I wasn't quite sure if you could have more than one adjustment where is_current is equal to 1. If there is at most going to be one row, then omit the aggregate and group by and just pass ba.amount_owed as the first parameter in the coalesce. 我不确定您是否可以在is_current等于1的情况下进行多个调整,如果最多只能有一行,则忽略聚合和分组,只需将ba.amount_owed作为第一个参数传递即可合并。

If you just want to replace the amount_owed by the value from the balance_adjustments table where is_current is 1 (and I am assuming there is only one of these values), then a simple LEFT JOIN and COALESCE will suffice. 如果您只想用balance_adjustments表中is_current为1的值替换amount_owed (我假设这些值只有一个),那么简单的LEFT JOINCOALESCE就足够了。 The COALESCE ensures any NULL values from unmatched rows in the balance_adjustments table get replaced by the original value from the unadjusted_balances table. COALESCE确保balance_adjustments表中不匹配的行中的任何NULL值都被unadjusted_balances表中的原始值替换。 It's not clear from your question whether you want to replace the when_to_pay field as well, I have assumed you have in this query. 从您的问题尚不清楚,您是否也想替换when_to_pay字段,我假设您在此查询中也有。 If you don't, just replace COALESCE(ba.when_to_pay, ub.when_to_pay) AS when_to_pay with ub.when_to_pay . 如果不这样做,只需更换COALESCE(ba.when_to_pay, ub.when_to_pay) AS when_to_payub.when_to_pay

SELECT ub.name, ub.user_id, 
    COALESCE(ba.amount_owed, ub.amount_owed) AS amount_owed,
    COALESCE(ba.when_to_pay, ub.when_to_pay) AS when_to_pay,
    ub.current_balance
FROM unadjusted_balance ub
LEFT JOIN balance_adjustments ba ON ba.user_id = ub.user_id AND ba.is_current
ORDER BY ub.name

Output: 输出:

name        user_id     amount_owed     when_to_pay             current_balance
joseph      82340000    2400            2018-11-05 00:00:00     4049
ricardo     82340001    100             2018-11-05 00:00:00     500

Demo on dbfiddle dbfiddle上的演示

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM