【问题标题】:Inserting the previous date's info if the current is empty Oracle如果当前为空,则插入上一个日期的信息 Oracle
【发布时间】:2017-12-24 15:03:08
【问题描述】:

我有一张包含以下信息的表格

Table1 是一个子查询,为了简化我将只使用结果表:

| Account_No | Dept_ID | Currency| Amount | Date_2(dd/mm/yyyy)|
+------------+---------+---------+--------+-------------------+
| 1          | 1       | USD     | 50     | 03/01/2017        |
| 1          | 2       | EUR     | 25     | 01/01/2017        |
| 1          | 3       | USD     | 51     | 01/01/2017        |
| 1          | 1       | GBP     | 45     | 01/01/2017        |
| 1          | 2       | USD     | 65     | 02/01/2017        |

金额是某部门指定货币的账户在该日期当天结束时的金额。更重要的是,CurrencyDept_ID(相同的 Account_no 但不同的货币和/或部门 ID)可能会导致同一帐户的变化,我的意思是 PK 是组合Account_no、Dept_ID 和货币。

我正在尝试将该表附加到具有某个指定范围的每天的日期表:

日期表:

|   Date_1   |
+------------+
| 01/01/2017 |
| 02/01/2017 |
| 03/01/2017 |
| 04/01/2017 |
| 05/01/2017 |
...

预期结果是:

|   Date_1   | Account_No | Dept_ID | Currency| Amount | Date_2(dd/mm/yyyy)|
+------------+------------+---------+---------+--------+-------------------+
| 01/01/2017 | 1          | 1       | USD     | 0      |                   |
| 01/01/2017 | 1          | 2       | USD     | 0      |                   |
| 01/01/2017 | 1          | 2       | EUR     | 25     | 01/01/2017        |
| 01/01/2017 | 1          | 3       | USD     | 51     | 01/01/2017        |
| 01/01/2017 | 1          | 1       | GBP     | 45     | 01/01/2017        |
| 02/01/2017 | 1          | 2       | USD     | 65     | 02/01/2017        |
| 02/01/2017 | 1          | 2       | EUR     | 25     |                   |
| 02/01/2017 | 1          | 3       | USD     | 51     |                   |
| 02/01/2017 | 1          | 1       | GBP     | 45     |                   |
| 02/01/2017 | 1          | 1       | USD     | 0      |                   |
| 03/01/2017 | 1          | 1       | USD     | 50     | 03/01/2017        |
| 03/01/2017 | 1          | 1       | GBP     | 45     |                   |
| 03/01/2017 | 1          | 3       | USD     | 51     |                   |
| 03/01/2017 | 1          | 2       | EUR     | 25     |                   |
| 03/01/2017 | 1          | 2       | USD     | 65     |                   |

因此,对于 Dates 表中的每个日期,我都会从 Table1 获得信息,如果缺少信息,则应选择前几天的信息。我已经完成了左加入的查询,但不知道如何将前一天的数据填充到缺失的字段中

SELECT * FROM DATES A LEFT JOIN TABLE1 B ON A.DATE_1 = B.DATE_2;

我明白了

|   Date_1   | Account_No | Dept_ID | Currency| Amount | Date_2(dd/mm/yyyy)|
+------------+------------+---------+---------+--------+-------------------+
| 01/01/2017 | 1          | 2       | EUR     | 25     | 01/01/2017        |
| 01/01/2017 | 1          | 3       | USD     | 51     | 01/01/2017        |
| 01/01/2017 | 1          | 1       | GBP     | 45     | 01/01/2017        |
| 02/01/2017 | 1          | 2       | USD     | 65     | 02/01/2017        |
| 03/01/2017 | 1          | 1       | USD     | 50     | 03/01/2017        |
| 04/01/2017 |            |         |         |        |                   |
...

感谢您提供有关如何进行的建议

【问题讨论】:

    标签: sql oracle join oracle10g


    【解决方案1】:

    您可以使用 lag()ignore nulls 选项来执行此操作。我想这就是你想要的:

    select d.date_1, a.account_no,
           coalesce(dept_id,
                    lag(dept_id ignore nulls) over (partition by t1.account_no order by d.date_1)
                   ) as dept_id,
           coalesce(currency,
                    lag(currency ignore nulls) over (partition by t1.account_no order by d.date_1)
                   ) as currency,
           coalesce(amount,
                    lag(amount ignore nulls) over (partition by t1.account_no order by d.date_1)
                   ) as amount
    from dates d CROSS JOIN
         (select distinct account_no from table1) a left join
         table1 t1
         on d.DATE_1 = t1.DATE_2 and a.account_no = t1.account_no;
    

    【讨论】:

    • 您好,感谢您的宝贵时间,我在使用ignore nulls 时遇到问题,上面写着Found: "ignore" expecting: ) 我试图找到丢失的括号,但没有找到,我做错了什么吗?
    • @Hatik 。 . . Oracle 绝对支持IGNORE NULLSdocs.oracle.com/cd/E11882_01/server.112/e41084/…
    • 是的,11支持,我没注意到10.2不支持,所以用last_value代替,应该指定我的版本
    【解决方案2】:

    您也可以使用partition outer join 加上一个 case 语句来执行此操作,该语句决定是放入当前金额还是如果没有当前金额,则输入以前的可用金额,如下所示:

    WITH table1 AS (SELECT 1 account_no, 1 dept_id, 'USD' currency, 50 amount, to_date('03/01/2017', 'dd/mm/yyyy') date_2 FROM dual UNION ALL
                    SELECT 1 account_no, 2 dept_id, 'EUR' currency, 25 amount, to_date('01/01/2017', 'dd/mm/yyyy') date_2 FROM dual UNION ALL
                    SELECT 1 account_no, 3 dept_id, 'USD' currency, 51 amount, to_date('01/01/2017', 'dd/mm/yyyy') date_2 FROM dual UNION ALL
                    SELECT 1 account_no, 1 dept_id, 'GBP' currency, 45 amount, to_date('01/01/2017', 'dd/mm/yyyy') date_2 FROM dual UNION ALL
                    SELECT 1 account_no, 2 dept_id, 'USD' currency, 65 amount, to_date('02/01/2017', 'dd/mm/yyyy') date_2 FROM dual),
          dates AS (SELECT to_date('01/01/2017', 'dd/mm/yyyy') date_1 FROM dual UNION ALL
                    SELECT to_date('02/01/2017', 'dd/mm/yyyy') date_1 FROM dual UNION ALL
                    SELECT to_date('03/01/2017', 'dd/mm/yyyy') date_1 FROM dual UNION ALL
                    SELECT to_date('04/01/2017', 'dd/mm/yyyy') date_1 FROM dual UNION ALL
                    SELECT to_date('05/01/2017', 'dd/mm/yyyy') date_1 FROM dual)
    SELECT d.date_1,
           t1.account_no,
           t1.dept_id,
           t1.currency,
           CASE WHEN t1.amount is NULL THEN
                     LAG(t1.amount, 1, 0) IGNORE NULLS OVER (PARTITION BY t1.account_no, t1.dept_id, t1.currency ORDER BY d.date_1)
                ELSE t1.amount
           END amount,
           t1.date_2
    FROM   dates d
           LEFT OUTER JOIN table1 t1 PARTITION BY (t1.account_no, t1.dept_id, t1.currency)
             ON d.date_1 = t1.date_2
    ORDER BY d.date_1,
             t1.account_no,
             t1.dept_id,
             t1.currency;
    
    DATE_1      ACCOUNT_NO    DEPT_ID CURRENCY     AMOUNT DATE_2
    ----------- ---------- ---------- -------- ---------- -----------
    01/01/2017           1          1 GBP              45 01/01/2017
    01/01/2017           1          1 USD               0 
    01/01/2017           1          2 EUR              25 01/01/2017
    01/01/2017           1          2 USD               0 
    01/01/2017           1          3 USD              51 01/01/2017
    02/01/2017           1          1 GBP              45 
    02/01/2017           1          1 USD               0 
    02/01/2017           1          2 EUR              25 
    02/01/2017           1          2 USD              65 02/01/2017
    02/01/2017           1          3 USD              51 
    03/01/2017           1          1 GBP              45 
    03/01/2017           1          1 USD              50 03/01/2017
    03/01/2017           1          2 EUR              25 
    03/01/2017           1          2 USD              65 
    03/01/2017           1          3 USD              51 
    04/01/2017           1          1 GBP              45 
    04/01/2017           1          1 USD              50 
    04/01/2017           1          2 EUR              25 
    04/01/2017           1          2 USD              65 
    04/01/2017           1          3 USD              51 
    05/01/2017           1          1 GBP              45 
    05/01/2017           1          1 USD              50 
    05/01/2017           1          2 EUR              25 
    05/01/2017           1          2 USD              65 
    05/01/2017           1          3 USD              51 
    

    注意如果您使用的是 11.2 之前的 Oracle 版本,则 lag 不会知道忽略空值。您可以改用以下方法来模拟相同的效果:

    nvl(last_value(t1.amount) IGNORE NULLS OVER (PARTITION BY t1.account_no, t1.dept_id, t1.currency ORDER BY d.date_1), 0)
    

    【讨论】:

    • 您好!谢谢你的帮助,我想你误解了我一点,如果你的代码中的nvl 不在 table1 中,它将返回 0,但是我想要做的是返回前一天的信息如果当前为空,例如在 05/01/2017 它将返回 amount = 50account_no =1dept_id = 1 因为没有进行任何操作它会与最后一天操作完成时相同
    • 好的,在这种情况下,你需要一个 lag 或 last_value 而不是 nvl。
    • 是的,我也这么认为,这就是我目前正在研究的,感谢@Gordon Linoff
    • 好的,我已经添加了一个应该可以按您预期工作的答案 - 抱歉错过了您的实际要求!
    • 确实,我也得出了同样的结论,Oracle 10g 中没有 IGNORE NULLS 用于延迟,不幸的是我的 db 是 10.2。
    【解决方案3】:
    WITH table1 AS
        (
            SELECT 1 account_no,
                1 dept_id,
                'USD' currency,
                50 amount,
                to_date('03/01/2017', 'dd/mm/yyyy') date_2
            FROM dual
            UNION ALL
            SELECT 1 account_no,
                2 dept_id,
                'EUR' currency,
                25 amount,
                to_date('01/01/2017', 'dd/mm/yyyy') date_2
            FROM dual
            UNION ALL
            SELECT 1 account_no,
                3 dept_id,
                'USD' currency,
                51 amount,
                to_date('01/01/2017', 'dd/mm/yyyy') date_2
            FROM dual
            UNION ALL
            SELECT 1 account_no,
                1 dept_id,
                'GBP' currency,
                45 amount,
                to_date('01/01/2017', 'dd/mm/yyyy') date_2
            FROM dual
            UNION ALL
            SELECT 1 account_no,
                2 dept_id,
                'USD' currency,
                65 amount,
                to_date('02/01/2017', 'dd/mm/yyyy') date_2
            FROM dual
        )
        ,
        dates AS
        (
            SELECT to_date('01/01/2017', 'dd/mm/yyyy') date_1 FROM dual
            UNION ALL
            SELECT to_date('02/01/2017', 'dd/mm/yyyy') date_1 FROM dual
            UNION ALL
            SELECT to_date('03/01/2017', 'dd/mm/yyyy') date_1 FROM dual
            UNION ALL
            SELECT to_date('04/01/2017', 'dd/mm/yyyy') date_1 FROM dual
            UNION ALL
            SELECT to_date('05/01/2017', 'dd/mm/yyyy') date_1 FROM dual
        )
    SELECT d.date_1,
        t1.account_no,
        t1.dept_id,
        t1.currency,
        t1.amount,
        CASE (t1.date_2)
            WHEN d.date_1
            THEN t1.date_2
            ELSE NULL
        END
    FROM table1 t1,
        dates d
    ORDER BY d.date_1,
        t1.account_no,
        t1.dept_id,
        t1.currency;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-10-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多