【问题标题】:How do I combine SELECT statements to allow me to calculate percentages, successes and failures in SQL Server?如何结合 SELECT 语句来计算 SQL Server 中的百分比、成功和失败?
【发布时间】:2011-09-08 04:58:15
【问题描述】:

想象一张桌子:

CUST_PROMO (customer_id,PROMOTION) 用作客户收到的每个促销之间的映射。

select promotion, count(customer_id) as promo_size
from CUST_PROMO
group by promotion

这让我们得到每次促销活动的客户总数。

现在,我们有了 CUSTOMER (customer_id, PROMO_RESPONDED,PROMO_PURCHASED),它列出了客户以及哪些促销活动让客户做出了回应,以及哪些促销活动让他们购买了。

select PROMO_RESPONDED, count(customer_id) as promo_responded 
from CUSTOMER
group by PROMO_RESPONDED

select PROMO_PURCHASED,count(customer_id) as promo_responded 
from CUSTOMER 
group by PROMO_PURCHASED

这一切都是不言自明的;现在我得到了每个促销活动成功的人数。

但是;我想结束的是[以 CSV 形式]

PROMOTION,PROMO_SIZE,PROMO_RESPONDED,PROMO_PURCHASED,PROMO_RESPSUCCESSRATE,blah

1,100,12,5,12%,...
2,200,23,14,11.5%,...

我不知道该怎么做。我可以联合上面的三个查询;但这实际上并没有得到我想要的结果。我考虑过创建一个内存表,插入每个促销值,然后执行一个更新语句并对其进行连接以设置每个值——但这很麻烦;并且需要为每个表/选择语句创建一个新的 UPDATE 语句。我还可以为每个结果集制作一个临时表,然后将它们连接在一起;但真的;谁愿意这样做?

我想不出任何有意义的方法来加入这些数据;因为我正在处理聚合。

所以,充其量,我需要一个函数,就像 UNION 一样,将组合结果集,但实际上会组合键上的类似列并添加这些列,而不是添加行的联合。描述使它听起来像一个 JOIN;但我看不到那个工作。

感谢您的帮助!

【问题讨论】:

    标签: sql sql-server tsql join


    【解决方案1】:

    这行得通吗?我不确定除法和乘法运算符,但我相信我的逻辑很好。关键是在 select 语句中使用相关的 select 子语句。

    SELECT c.promotion, 
           COUNT(c.customer_id) as promo_size, 
           (SELECT COUNT(customer_id)
              FROM CUSTOMER
             WHERE PROMO_RESPONDED = c.promotion) PROMO_RESPONDED,
           (SELECT COUNT(customer_id)
              FROM CUSTOMER
             WHERE PROMO_PURCHASED = c.promotion) PROMO_PURCHASED,
           (SELECT COUNT(customer_id) *100/count(c.customer_id)
             FROM CUSTOMER
            WHERE PROMO_RESPONDED = c.promotion)                                                      
    FROM CUST_PROMO c
    GROUP BY c.promotion
    

    使用解码的更简洁的解决方案。仍然不确定数学是否有效

    select PROMOTION, count(CUSTOMER_ID) as promo_size, 
           SUM(DECODE(PROMO_RESPONDED, PROMOTION, 1, 0)) PROMO_RESPONDED,
           SUM(DECODE(PROMO_PURCHASED, PROMOTION, 1, 0)) PROMO PURCHASED,
           SUM(DECODE(PROMO_RESPONDED, PROMOTION, 1, 0))*100/count(CUSTOMER_ID) PROMO_RESPONDED
    from CUST_PROMO join CUSTOMER using CUSTOMER_ID
    group by PROMOTION 
    

    【讨论】:

    • 这可能有效,但如果可以使用连接,则应始终避免嵌套选择。
    • 实际上这可能行不通,因为 promo_size 将在 group by 之后计算,这在您的子选择运行之前不会发生..
    • 这里已经很晚了,所以我不知道你是说它是错误的,因为结果是不正确的还是一些“编译”错误。但我很好奇我做错了什么
    • @marina 您不能在 sql server 中使用嵌套选择或别名中的值(您可以在 MS 访问中这样做)
    • @marina --- 还是很恶心;而不是一个干净的解决方案;但它确实有效。我不得不清理一些东西(在初始选择和分组中使用 c.)等等;但我没有意识到 group by 会以这种方式工作。
    【解决方案2】:
    WITH tmp AS
    (
        SELECT  PROMOTION, 0 as promo_responded, 0 as promo_purchased, COUNT(customer_id) as total
        FROM    CUST_PROMO
        GROUP BY PROMOTION
        SELECT  PROMOTION, COUNT(customer_id) as promo_responded, 0 as promo_purchased, 0 as total
        FROM    CUSTOMER
        GROUP BY PROMO_RESPONDED
        UNION   
        SELECT  PROMOTION, COUNT(customer_id) as promo_purchased, 0 as promo_responded, 0 as total
        FROM    CUSTOMER
        GROUP BY PROMO_PURCHASED
    )
    SELECT  PROMOTION, SUM(promo_responded) as TotalResponded, SUM(promo_purchased) as TotalPurchased, SUM(Total) as TotalSize,
            SUM(promo_responded)/SUM(Total) as ResponseRate, SUM(promo_purchased)/SUM(Total) as PurchaseRate
    FROM    tmp
    

    【讨论】:

      【解决方案3】:

      是的,我认为JOINing 三个聚合查询是要走的路。 LEFT JOINs 的存在是为了以防某些促销活动没有回应或没有购买。

      我还将COUNT(customer_id) 更改为COUNT(*)。结果是一样的,除非customer_id 字段在两个表中可以有NULL 值,而这很可能不是这种情况。但是,如果客户可能出现在具有相同促销代码的表格的两行中,那么您应该将其更改为 COUNT(DISTINCT customer_id)

      SELECT prom.promotion
           , prom.promo_size
           , responded.promo_responded
           , purchased.promo_purchased
           , responded.promo_responded / prom.promo_size
             AS promo_response_success_rate
      FROM
          ( SELECT promotion
               , COUNT(*) AS promo_size
            FROM CUST_PROMO
            GROUP BY promotion
          ) AS prom
        LEFT JOIN 
          ( SELECT PROMO_RESPONDED AS promotion
                 , COUNT(*) AS promo_responded
            FROM CUSTOMER
            GROUP BY PROMO_RESPONDED
          ) AS responded
          ON responded.promotion = prom.promotion
        LEFT JOIN
          ( SELECT PROMO_PURCHASED AS promotion
                 , COUNT(*) AS promo_purchased
            FROM CUSTOMER
            GROUP BY PROMO_PURCHASED
          ) AS purchased
          ON purchased.promotion = prom.promotion
      

      【讨论】:

        【解决方案4】:
        SELECT
          cp.promotion,
          PROMO_SIZE = COUNT(*),
          PROMO_RESPONDED = COUNT(c1.customer_id),
          PROMO_PURCHASED = COUNT(c2.customer_id),
          PROMO_RESPSUCCESSRATE = COUNT(c1.customer_id) * 100.0 / COUNT(*)
        FROM CUST_PROMO cp
          LEFT JOIN CUSTOMER c1
            ON cp.customer_id = c1.customer_id AND cp.promotion = c1.PROMO_RESPONDED
          LEFT JOIN CUSTOMER c2
            ON cp.customer_id = c2.customer_id AND cp.promotion = c2.PROMO_PURCHASED
        GROUP BY cp.promotion
        

        【讨论】:

        • 这就是我最终这样做的方式;尽管所有解决方案都有其优点。
        猜你喜欢
        • 2020-10-17
        • 2010-10-20
        • 1970-01-01
        • 2013-10-22
        • 2015-04-05
        • 2021-03-16
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多