【问题标题】:Compare rows in the same table using Oracle SQL based on unique combinations of columns使用基于列的唯一组合的 Oracle SQL 比较同一表中的行
【发布时间】:2013-10-02 21:55:18
【问题描述】:

我在 Stackoverflow 上看到了一些与比较行有关的问题,但与这个问题完全不同。我有一个表,其列类似于:

 - Month       (Date (01-Jan-2013)
 - Country     (Varchar2)
 - SubCustomer (Varchar2)
 - FTE         (Number) Represents a value that is manually entered by employees each month

我们可能有一些这样的数据..

 - 01-Jan-2013 USA Customer1 10
 - 01-Feb-2013 USA Customer1 15
 - 01-Mar-2013 USA Customer1 30
 - 01-Jan-2013 BRA Customer2 100
 - 01-Feb-2013 BRA Customer2 300
 - 01-Mar-2013 BRA Customer2 50

我的目标是比较输入的 FTE,如果输入的 FTE 是上个月的 +/- 2 倍,则在单独的列中提供警报,例如“高警报”或“低警报”或“确定”每个月 + 国家 + 子客户。我一直在使用不同的 Case 语句,但似乎无法逐月进行比较。

使用上面的数据,客户 1 将在 2 月至 3 月产生“高警报”警报,而客户 2 将在 1 月至 2 月产生高警报,从 2 月至 3 月产生低警报。

【问题讨论】:

  • 您是否尝试在触发器中实现这一目标?还是只想通过 select 语句检索 Month、Country、Customer、AlertType?

标签: sql oracle


【解决方案1】:

听起来你应该使用 LAG / LEAD。

SELECT Month, Country, SubCustomer, FTE
, LAG(FTE, 1, 0) OVER (PARTITION BY Country, SubCustomer ORDER BY Month) as PrevFTE
FROM MyTable

您可以在这里找到一些很好的例子: http://www.oracle-base.com/articles/misc/lag-lead-analytic-functions.php

【讨论】:

    【解决方案2】:

    试试这个:包括 NULL 或零的可能性

    WITH TABLEDATA
        AS (SELECT
                 TO_DATE ( '01-Jan-2013',
                         'DD-MON-YYYY' )
                     AS MONT,
                 'USA' AS COUNTRY,
                 'Customer1' AS SUBCUST,
                 0 AS FTE
            FROM
                 DUAL
            UNION ALL
            SELECT
                 TO_DATE ( '01-Feb-2013',
                         'DD-MON-YYYY' )
                     AS MONT,
                 'USA' AS COUNTRY,
                 'Customer1' AS SUBCUST,
                 15 AS FTE
            FROM
                 DUAL
            UNION ALL
            SELECT
                 TO_DATE ( '01-Mar-2013',
                         'DD-MON-YYYY' )
                     AS MONT,
                 'USA' AS COUNTRY,
                 'Customer1' AS SUBCUST,
                 30 AS FTE
            FROM
                 DUAL
            UNION ALL
            SELECT
                 TO_DATE ( '01-Jan-2013',
                         'DD-MON-YYYY' )
                     AS MONT,
                 'BRA' AS COUNTRY,
                 'Customer2' AS SUBCUST,
                 100 AS FTE
            FROM
                 DUAL
            UNION ALL
            SELECT
                 TO_DATE ( '01-Feb-2013',
                         'DD-MON-YYYY' )
                     AS MONT,
                 'BRA' AS COUNTRY,
                 'Customer2' AS SUBCUST,
                 300 AS FTE
            FROM
                 DUAL
            UNION ALL
            SELECT
                 TO_DATE ( '01-Mar-2013',
                         'DD-MON-YYYY' )
                     AS MONT,
                 'BRA' AS COUNTRY,
                 'Customer2' AS SUBCUST,
                 50 AS FTE
            FROM
                 DUAL)
    SELECT
          MONT,
          COUNTRY,
          SUBCUST,
          FTE,
          ROUND ( ( FTE
                 - PREVIOUS_FTE )
                / NULLIF ( PREVIOUS_FTE,
                         0 ),
                2 )
          * 100
              CHANGE_IN_PERCENT,
          CASE
              WHEN ROUND ( ( FTE
                         - PREVIOUS_FTE )
                        / NULLIF ( PREVIOUS_FTE,
                                 0 ),
                        2 )
                  * 100 >= 200
              THEN
                  'High Alert'
              WHEN ROUND ( ( FTE
                         - PREVIOUS_FTE )
                        / NULLIF ( PREVIOUS_FTE,
                                 0 ),
                        2 )
                  * 100 <= 200
              THEN
                  'Low Alert'
              ELSE
                  'OK'
          END
              AS ALERTS
    FROM
          (SELECT
                MONT,
                COUNTRY,
                SUBCUST,
                FTE,
                LAG ( FTE,
                     1 )
                OVER (PARTITION BY COUNTRY, SUBCUST ORDER BY MONT)
                    PREVIOUS_FTE
           FROM
                TABLEDATA);
    

    结果:

    MONT        COUNTRY SUBCUST FTE CHANGE_IN_PERCENT ALERTS
    1/1/2013    BRA Customer2   100                   OK
    2/1/2013    BRA Customer2   300 200               High Alert
    3/1/2013    BRA Customer2   50  -83               Low Alert
    1/1/2013    USA Customer1   0                     OK
    2/1/2013    USA Customer1   15                    OK
    3/1/2013    USA Customer1   30  100               Low Alert
    

    【讨论】:

    • 所以..第二个解决方案的问题是我们有 100 多个客户..我需要动态进行比较,而不是按国家、客户和月份列出它们。我想我可以使第一个解决方案工作;)非常感谢您的帮助!
    • 我刚刚使用 with 子句重新创建了表。您可以只使用表名而不是 WITH 子句。
    • 好的,我现在明白了..感谢您的解释。我收到此错误是因为某些数据每个月都为零。我怀疑它与这部分代码有关。我试图在案例中处理它,但我仍然给出错误。关于如何解决这个问题的任何想法?谢谢 ROUND ( ( FTE - PREVIOUS_FTE ) / PREVIOUS_FTE, 2 ) * 100 CHANGE_IN_PERCENT, ORA-01476: 除数等于零 01476. 00000 - “除数等于零” *原因:*操作:
    • 您从未在数据集中提到 NULL 的可能性。请发布您的数据。我们可以提供帮助
    • 发布了新的 SQL。如果问题仍然存在,请尝试相同并恢复
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-12
    相关资源
    最近更新 更多