【问题标题】:SQL report - Matching percent value with a numberSQL 报告 - 将百分比值与数字匹配
【发布时间】:2018-09-09 13:37:39
【问题描述】:

我的报告有一个小问题,我想知道是否可以这样做? 我正在使用 Oracle12c 和工具 OBIEE,我试图创建一个 自定义列,其数值(1 和 2)与我的“百分比”列中的结果相匹配,如下所述。 p>

这是我在表格中的结果:

我会给你一个应该如何工作的例子:

Emilian 是少数客户的所有者,列出了客户的年收入,旁边的列是 Emilian 客户总收入的百分比值。现在,在我的自定义列中,我需要为贡献超过(或准确)80% 的客户显示“1”,其余的显示“2”。所以在 Emilian Case 中,他的前两个客户将是“1”,因为 78% + 14% 已经超过 80%,其余的将是“2”。对于只有一个客户的其他 Owner,由于他们的贡献为 100%,因此逻辑上将所有这些所有者都匹配为“1”

希望我说清楚了,非常感谢您在编码方面的帮助:)

亚历克斯

【问题讨论】:

  • 请不要发布 SQL 的图像。任何人都很难模仿它来帮助你。尝试重新创建您的架构和测试数据。一个简单的基于文本的描述会有所帮助,但如果可以,请使用 dbfiddle.uksqlfiddle.com 之类的内容。
  • 对不起,我认为这有助于理解这个概念:) 所有的列都是从一个表中选择的,并且有一个百分比值列的计算,例如 (sales/sum(sales) )*100。如上所述,我正在寻求帮助,为它制作自定义列:)
  • 你能解释一下'所以在 Emilian Case 中,他的前两个客户将是“1”,因为 78% + 14% 已经超过 80%,其余的将是“2”。?为什么这些得到 1 而不是 2?从技术上讲,第一和第三客户也都在 80% 以上。如果您有 5 个客户,每个客户贡献 20% 怎么办?您的具体要求是什么?
  • 是的,好的:客户的排名(使用 RANK())从最高贡献者到最低贡献者。在 Emilian 的案例中,他的前两个客户已经超过了他总贡献的 80%,因此他们将与值“1”配对。 80% 线是这里的关键。如果有 5 位客户,例如排名为:30%、25%、20%、10% 和 5%,则只有最后一位为“2”,因为第 4 位突破了 80%(30+25 +20+10 = 85 所以高于 80)。希望它说清楚:)
  • 是的,但是如果它们都被捆绑了呢?

标签: sql oracle oracle12c obiee


【解决方案1】:

可能有一种更有效的方法来做到这一点。我通过一系列子选择建立了你需要得到的东西。这仍然不能处理相等的百分比,但是您说这不是预期的问题。我还是会注意的。

SQL Fiddle

Oracle 11g R2 架构设置

CREATE TABLE t1 ( ownerId int, customerId int, revenue int ) ;

INSERT INTO t1 ( ownerid, customerid, revenue )
SELECT 1, 1, 99 FROM dual UNION ALL
SELECT 1, 2, 200 FROM dual UNION ALL
SELECT 1, 3, 300 FROM dual UNION ALL
SELECT 1, 4, 400 FROM dual UNION ALL
SELECT 2, 5, 100 FROM dual UNION ALL
SELECT 2, 6, 100 FROM dual UNION ALL
SELECT 2, 7, 200 FROM dual UNION ALL
SELECT 2, 8, 600 FROM dual UNION ALL
SELECT 3, 9, 100 FROM dual UNION ALL
SELECT 3, 10, 900 FROM dual UNION ALL
SELECT 4, 11, 1000 FROM dual UNION ALL
SELECT 5, 12, 1000 FROM dual UNION ALL
SELECT 6, 13, 200 FROM dual UNION ALL
SELECT 6, 14, 200 FROM dual UNION ALL
SELECT 6, 15, 200 FROM dual UNION ALL
SELECT 6, 16, 200 FROM dual UNION ALL
SELECT 6, 17, 200 FROM dual UNION ALL
SELECT 42, 736784, 1480000 FROM dual UNION ALL
SELECT 42, 736580, 280160 FROM dual UNION ALL
SELECT 42, 1040137, 112486 FROM dual UNION ALL
SELECT 42, 738685, 22903 FROM dual UNION ALL
SELECT 42, 736781, 56 FROM dual 
;

查询 1

SELECT s3.ownerID, s3.customerID, s3.revenue, s3.OwnerRevenue
  , CAST(s3.customerRevPct AS decimal(5,2)) AS customerRevPct
  , CASE WHEN s3.PctRT < 80 OR s3.custCount = 1 THEN 1 ELSE 2 END AS customCol
  /* Do the running pcts add up to 80+? 1 customer = 100% == 1. What if all are pcts are equal? */
FROM (
  SELECT s2.*
    , 100-SUM(nvl(s2.customerRevPct,0)) OVER (PARTITION BY s2.ownerID ORDER BY s2.customerRevPct, s2.customerID RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS pctRT
    , COUNT(*) OVER (PARTITION BY s2.ownerID ORDER BY (s2.ownerID) ) AS custCount /* Is there only 1 customer? */
  FROM (
    SELECT s1.*
      , ( ( ( s1.revenue * 1.0 ) / s1.ownerRevenue ) * 100 ) AS customerRevPct 
    FROM (
      SELECT t1.ownerID, t1.customerID, t1.revenue
        ,  SUM(t1.revenue) OVER ( PARTITION BY t1.ownerID ) AS ownerRevenue
      FROM t1
    ) s1
  ) s2
) s3
WHERE ownerID = 42 /* REMOVE THIS LINE - TESTING ONLY */
ORDER BY s3.ownerID, s3.customerRevPct DESC

Results

| OWNERID | CUSTOMERID | REVENUE | OWNERREVENUE | CUSTOMERREVPCT | CUSTOMCOL |
|---------|------------|---------|--------------|----------------|-----------|
|      42 |     736784 | 1480000 |      1895605 |          78.08 |         1 |
|      42 |     736580 |  280160 |      1895605 |          14.78 |         1 |
|      42 |    1040137 |  112486 |      1895605 |           5.93 |         2 |
|      42 |     738685 |   22903 |      1895605 |           1.21 |         2 |
|      42 |     736781 |      56 |      1895605 |              0 |         2 |

编辑:我更改了 Fiddle 来说明您的数据示例。

【讨论】:

    【解决方案2】:
    create table custrev(owner varchar2(100), cust_id number, revenue number);
    
    insert into custrev values('Emilian',1,1480000);
    insert into custrev values('Emilian',2,280160);
    insert into custrev values('Emilian',3,112486);
    insert into custrev values('Emilian',4,22903);
    insert into custrev values('Emilian',5,56);
    insert into custrev values('Andy',6,1378);
    insert into custrev values('Sandy',7,560000);
    
    commit;
    

    以下是满足您要求的 SQL。

    select owner, cust_id, revenue, pct,
           case when pct = 100 then 1
                when flg is null or flg < 80 then 1
                else 2 end flag_col
      from (select owner, cust_id, revenue, pct,--cumulative_sum,
                   lag(cumulative_sum) over(partition by owner 
                                            order by revenue desc) flg 
              from (select owner, cust_id, revenue, pct, 
                           sum(pct) over(partition by owner 
                                         order by revenue desc 
                                         rows between unbounded preceding 
                                                  and current row) cumulative_sum
                      from (select owner, cust_id, revenue,
                                   round(ratio_to_report(revenue) over(partition by owner)*100,2) pct 
                              from custrev)
                   )
           )
    order by owner, revenue desc;
    

    输出:

    OWNER   CUST_ID REVENUE PCT     FLAG_COL
    Andy    6       1378    100     1
    Emilian 1       1480000 78.08   1
    Emilian 2       280160  14.78   1
    Emilian 3       112486  5.93    2
    Emilian 4       22903   1.21    2
    Emilian 5       56      0       2
    Sandy   7       560000  100     1
    

    【讨论】:

    • 这个不考虑只有 1 个客户的所有者。那 1 个客户将始终是 100%,并且应该有 1 个。
    • 将“pct = 100 然后 2 的情况”更改为“pct = 100 然后 1 的情况”。
    【解决方案3】:

    亚历克斯,

    OBIEE 基于模型。不在 SQL 上。

    很抱歉这么说,但 SQL 代码将帮助您完全归零...

    【讨论】:

      猜你喜欢
      • 2021-02-05
      • 2021-05-07
      • 1970-01-01
      • 2019-07-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多