【问题标题】:Finding out when summed values reached a certain checkpoint in SQL找出总和值何时到达 SQL 中的某个检查点
【发布时间】:2015-11-26 13:58:45
【问题描述】:

首先:我在之前提出的问题中找到了我的问题的一些可能答案,但我遇到了让它们正常工作的问题。我知道这个问题已经被问过了,但答案总是工作代码,几乎没有解释所使用的方法。

所以:我必须找出客户何时达到 VIP 状态,即他的订单价值超过 50 000。我有 2 个表:一个带有 orderid、customerid 和 orderdate,第二个带有 orderid 、数量和单价。 我写的查询结果应该是3列宽,一列是customerid,一列是真/假,名为“是VIP?”,第三是获得VIP状态的日期(即订单日期与前面的相加得到超过 50 000 的结果)- 如果客户没有达到 VIP 状态,最后一个应该是空白

select o.customerid, sum(od.quantity*od.unitprice),
case
when sum(od.quantity*od.unitprice)>50000 then 'VIP'
else 'Normal'
end as 'if vip'
from
orders o join [Order Details] od on od.orderid=o.orderid
group by o.customerid

就我得到的代码而言,它返回了客户的状态,现在我需要获取发生这种情况的日期。 .

【问题讨论】:

  • 我不是在寻求解决问题的方法,而是寻求解决方法,寻求解决方法的想法。没有问题,因为还没有解决方案。我正在研究 Northwind 数据库,我问的问题是关于我在教科书中找到的一个练习,我不知道如何创建除了视图之外的任何东西(我想这不会很有帮助),也不知道如何插入任何东西.谢谢你的回答。
  • 嗯,是的。我刚刚注意到我选择了错误的标签,抱歉。
  • 你使用的是哪个数据库?
  • 我正在使用 Northwind 和 SQL Server 2014。

标签: sql sql-server sum


【解决方案1】:

您可以使用窗口函数轻松计算运行总计:

select o.customerid, 
       o.orderdate, 
       sum(od.quantity*od.unitprice) over (partition by o.customerid order by orderdate) as running_sum, 
from orders o 
   join Order_Details od on od.orderid = o.orderid
order by customer_id, orderdate;

现在你需要找到一种方法来检测第一行,其中运行总计超过阈值:

一旦达到阈值,以下查询开始以降序方式对行进行编号。这反过来意味着编号为 1 的行是第一个越过阈值的行:

with totals as (
  select o.customerid, 
         o.orderdate, 
         sum(od.quantity*od.unitprice) over (partition by o.customerid order by orderdate) as running_sum, 
         case
           when 
              sum(od.quantity*od.unitprice) over (partition by o.customerid order by orderdate) > 50000 then row_number() over (partition by o.customerid order by orderdate desc)
           else 0
         end as rn
  from orders o 
     join Order_Details od on od.orderid = o.orderid
)
select *
from totals
where rn = 1
order by customerid;

SQLFiddle 示例:http://sqlfiddle.com/#!6/a7f18/3

【讨论】:

  • 这只是返回具有最新日期的行:-)
【解决方案2】:

您可以使用解析函数SUM OVER 获得累积总和。然后添加一个聚合来找到最小日期:

with cte as
 ( select o.customerid, 
      o.orderdate, 
      case when sum(od.quantity*od.unitprice) -- running total
                over (partition by o.customerid
                      order by orderdate
                      rows unbounded preceding) > 50000 
           then 'Y' 
           else 'N' 
      end as VIP
  from orders o 
  join Order_Details od on od.orderid = o.orderid
 )
select customerid,
   MAX(VIP) AS "isVIP?",  -- either 'N' or 'Y'
   MIN(CASE WHEN VIP = 'Y' THEN orderdate END) AS VIP_date -- only when VIP status reached
from cte
group by customerid
order by customers;

fiddle

【讨论】:

    【解决方案3】:

    不会用逻辑来复杂化答案以显示“vip”和“vip date”。这将为您提供每个客户订单的运行总计。

    select o.orderid, o.customerid, o.orderdate, sum(od.quantity*od.unitprice) 'Total', ( select sum(od.quantity * od.unitprice) total from orders o2 join [Order Details] od2 on od2.orderid=o2.orderid where o2.orderID <= o.orderID and o2.customerid = o.customerid) 'RunningTotal' from orders o join [Order Details] od on od.orderid=o.orderid group by o.orderid, o.customerid, o.orderdate order by o.customerid

    【讨论】:

    • 使用sum(od.quantity*od.unitprice) over (partition by o.customerid order by o.orderdate),您可以更轻松地计算总和
    【解决方案4】:

    要回答有关如何处理的问题,您可以考虑使用 SQL 触发器,该触发器在每次更新所涉及的表时运行,并在达到阈值时设置状态。这将设置事件发生的日期和时间.

    另一种方法是使用存储过程,您可以在其中使用循环顶部迭代记录并到达日期。

    可以根据数据量进行选择,前者适用于海量数据。

    【讨论】:

      猜你喜欢
      • 2020-12-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-30
      • 1970-01-01
      • 1970-01-01
      • 2020-04-16
      • 2018-07-21
      相关资源
      最近更新 更多