【问题标题】:Sql Server - Running Totals Based on ConditionsSql Server - 根据条件运行总计
【发布时间】:2014-09-25 01:13:20
【问题描述】:

我一直在努力想出正确的逻辑(SQL Server 2012)来实现我认为相当常规的事情,但我无法在任何地方找到任何这样的例子。基本上,我在一个表中有 3 列:产品、标志、值。一个产品可以在表中多次列出,但只有一次带有唯一标志(即 product1 可以有 flag1 或 flag2 具有不同/相同但永远不会有 2 条记录具有 product1 和 flag1 以及不同/相同的值) .

标志代表一个预定义的值 (1,2,3,4),该字段背后的目的是能够根据标志的值分配一个唯一的数学方程。最终结果将产生一个产品、唯一标志和基于数学方程输出的新累积总数。例如,假设 product1 被列出 4 次,其标志值为 flag1、flag2、flag3、flag4(见下文):

Product-----Flag-----Value
Product1----Flag1----1.00
Product1----Flag2----3.00
Product1----Flag3----5.00
Product1----Flag4----7.00

Product-----Flag-----Value
Product1----Flag1----1.00  (flag1 value)
Product1----Flag2----4.00  (flag1+flag2 value)
Product1----Flag3----6.00  (flag1+flag3 value)
Product1----Flag4----10.00 (flag2+flag4 value)

Flag1 仅定义为添加 flag1。 Flag2 定义为添加 flag1 和 flag2。标志 3 定义为添加标志 1 和标志 3。标志 4 定义为添加标志 2 和标志 4。新输出将是 product1 列出四次,其标志值为 flag1、flag2、flag3、flag4,但新值为 flag1、flag1_flag2、flag1+flag3、flag2+flag4。

我尝试通过 case 语句应用逻辑,但我不知道如何遍历每个条件的所有产品,我尝试使用运行总计解决方案,但我不确定如何合并将条件标记到其中,因此它仅在这些条件为真时执行运行总计。任何能帮助我走上正确道路的帮助和/或文章将不胜感激。

【问题讨论】:

  • 基于标志的“唯一数学方程”是一直固定的,还是存在一些差异?不同的产品会有不同的标志计算吗?
  • 但是 Product1 没有被列出 4 次
  • 所有产品的标志方程都是固定的,因此所有产品将共享相同的数学方程。更正了产品名称。谢谢!

标签: tsql sql-server-2012


【解决方案1】:

虽然我不确定我是否完全理解您的问题,但我认为这可能是您想要的。为此,它假设 flag1 在 flag 1 到 3 存在时始终存在,而 flag2 在 flag4 存在时存在。

;with cte as (
    select 
       product, 
       max(case when flag = 'Flag1' then Value end) as f1Value,
       max(case when flag = 'Flag2' then Value end) as f2Value,
       max(case when flag = 'Flag3' then Value end) as f3Value,
       max(case when flag = 'Flag4' then Value end) as f4Value
    from flags group by Product
)

select 
    flags.Product,
    flags.Flag,
    flags.Value as "Org. value",
    case flag 
       when 'Flag1' then f1Value 
       when 'Flag2' then f1Value + f2Value
       when 'Flag3' then f1Value + f3Value
       when 'Flag4' then f2Value + f4Value
       else flags.Value -- take the present value when flag is not Flag1-4
     end as "New value"    
from flags
inner join cte on flags.Product = cte.Product

看看这个Sample SQL Fiddle 看看它的实际效果。

【讨论】:

  • 抱歉,我的回信延迟了,但我刚放学回家。显然,由于日期范围重叠,我可能会拥有具有相同标志的重复产品,因此 max() 当前不包括这些值。基本上我有两个额外的列开始日期,停止日期。在某些日子里,我的产品可能会重叠,但我无法保证每种类型至少有 1 个标志。
  • @TStewartFan 好的,那么你想如何处理重复的行?如果您想对它们求和(根据与以前相同的公式)并且不关心日期,也许这就是您需要的? sqlfiddle.com/#!3/967cc/2
  • 我有一天的时间来研究这个方程式,而我所走的每一条路都让我离真正的答案越来越远。日期很重要,因为它们代表成本的开始时间。例如,在您的示例中,01/01 上的 product2/flag1 应该具有与之关联的累积成本 1.00。但是 01/02 上的 product2/flag1 应该有与之相关的 12.00 的累积成本。
  • @TStewartFan 我认为如果不花更多的时间我就无法解决这个问题,但我很确定它是可以解决的。祝你好运!
  • 实际上你的解决方案让我非常接近。希望一旦我从学校回到家,我将能够解决我剩下的失败的测试用例。谢谢!
【解决方案2】:

您可以将表连接到自身,并适当地选择条件:

SELECT p1.product,p1.Flag,p1.Value + COALESCE(p2.Value,0)
FROM
    Products p1
        left join
    Products p2
        on
           p1.Product = p2.Product and
           p2.Flag = CASE p1.Flag
                       --1 doesn't need a previous value
                       WHEN 2 THEN 1
                       WHEN 3 THEN 1
                       WHEN 4 THEN 2
                     END

【讨论】:

    【解决方案3】:

    我假设并尝试了 Range 值。

    CREATE TABLE #tmp (Product VARCHAR(10), flag VARCHAR(10),value numeric(13,2))
    GO
    INSERT INTO #tmp
        SELECT 'Product1' , 'Flag1',1
        UNION
    SELECT 'Product1' , 'Flag2',3
        UNION
    SELECT 'Product1' , 'Flag3',5
        UNION
    SELECT 'Product1' , 'Flag4',7
    GO
                ;WITH cte
                AS
        (
        SELECT row_number () OVER(
                ORDER BY flag)  'row',*
            FROM #tmp
        )
    SELECT  *,value 'RT'
        FROM    cte
        WHERE    row = 1
        UNION
    SELECT    * ,(
        SELECT  cte.value
            FROM cte
            WHERE row  = 1
        )                    + value 'RT'
        FROM cte
        WHERE row BETWEEN 2 
            AND 3
        UNION
    SELECT    * ,(
        SELECT  cte.value
            FROM cte
            WHERE row  =2
        )                    + value 'RT'
        FROM cte
        WHERE row >3
    GO
    DROP TABLE #tmp
    

    【讨论】: