Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/76.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
SQL四舍五入百分比,使总和100%-1/3为0.34、0.33、0.33_Sql_Teradata_Rounding - Fatal编程技术网

SQL四舍五入百分比,使总和100%-1/3为0.34、0.33、0.33

SQL四舍五入百分比,使总和100%-1/3为0.34、0.33、0.33,sql,teradata,rounding,Sql,Teradata,Rounding,我目前正试图用百分比列拆分一个值。但由于大多数百分比值是1/3,我无法得到一个100%的值,该值有两个小数点。例如: Product Supplier percentage totalvalue customer_split decimal(15,14) (decimal(18,2) decimal(18,2) -------- -------- ------------

我目前正试图用百分比列拆分一个值。但由于大多数百分比值是1/3,我无法得到一个100%的值,该值有两个小数点。例如:

Product    Supplier      percentage         totalvalue        customer_split
                         decimal(15,14)   (decimal(18,2)       decimal(18,2)
--------   --------     ------------     ---------------  ---------------
Product1    Supplier1    0.33            10.00                3.33
Product1    Supplier2    0.33            10.00                3.33
Product1    Supplier3    0.33            10.00                3.33

因此,在这里,我们在“值”列中缺少0.01,供应商希望将此缺少的0.01值与任意一个供应商进行随机比较。我一直试图在两组带有临时表的SQLs中实现这一点,但是有什么简单的方法可以做到这一点。如果可能的话,如何在上述行之一的百分比列中获得0.34?0.01是可以忽略的值,但当值列为100000000时,它是重要的。

运行此命令,它将给出如何解决问题的想法。 我创建了一个名为orders的表,其ID很容易理解:

create table orders(
customerID int)

insert into orders values(1)
go 3

insert into orders values(2)
go 3

insert into orders values(3)
go 3
这些值代表您拥有的33%

1   33.33
2   33.33
3   33.33
现在:

这段代码将基本上计算百分比和最大ID的顺序,然后获得从100到百分比和的差值,并将其添加到最大ID的顺序(您的随机顺序)


听起来你在做某种“分配”。这是一个常见的问题,当您试图将某些内容从较高的粒度分配到较低的粒度时,您需要能够正确地重新聚合到总值

当处理较大的分数时,这将成为一个更大的问题

例如,如果我尝试将总值(比如55.30美元)除以8,那么八个桶中的每一个都会得到一个十进制值6.9125美元。我是不是应该把一个四舍五入到6.92美元,把其余的四舍五入到6.91美元?如果我这样做,我会损失一分钱。我得把一个四舍五入到6.93美元,其他的四舍五入到6.91美元。当您添加更多要除以的桶时,情况会变得更糟

此外,当您开始四舍五入时,您会引入诸如“33.339应该四舍五入到33.34还是33.33?”

如果您的业务逻辑是这样的,您只想获取可能存在的超过2个有效数字的余数,并将其“随机”添加到一个美元值中,这样您就不会损失任何美分,@Diego的做法是正确的

在纯SQL中实现这一点有点困难。首先,你的百分比不是1/3,而是0.33,这将产生9.9的总价值,而不是10。我会将其存储为比率或高精度十进制字段(.33333)

您的计算似乎是基于每个供应商的产品总数的平均分布。如果是,则删除百分比,而只在表中存储每个供应商的项目计数可能是有利的


如果还可以存储一个标志,指示应用剩余值的行,则可以基于该标志而不是随机分配。

使用窗口聚合函数,这应该是一项简单的任务。您可能已经在计算
客户分割时使用了它们:

totalvalue  / COUNT(*) OVER (PARTITION BY Product) as customer_split
现在将客户_分割相加,如果总价值存在差异,则将其添加(或减去)到一个随机行

SELECT 
   Product                       
   ,Supplier                      
   ,totalvalue                    
   ,customer_split 
    + CASE
         WHEN COUNT(*) 
              OVER (PARTITION BY Product
                    ROWS UNBOUNDED PRECEDING) = 1 -- get a random row, using row_number/order you might define a specific row
         THEN totalvalue - SUM(customer_split)
                           OVER (PARTITION BY Product)
         ELSE 0
      END
FROM 
 (
   SELECT
      Product                       
      ,Supplier                      
      ,totalvalue                    
      ,totalvalue / COUNT(*) OVER (PARTITION BY Product) AS customer_split
   FROM dropme
 ) AS dt

经过多次试验,我想我找到了更好的解决办法

创意

  • 根据您的条件获取全部计数(计数(*)
  • 获取行号()
  • 检查(行数()值<计数(*)) 然后选择舍入(当前百分比,2) 其他的 得到所有其他百分比的总和(四舍五入)并从100中减去它 此步骤每次都将选择当前百分比,但最后一步除外 100-所有其他百分比的总和
  • 这是我代码的一部分

    Select your_cols
          ,(Select count(*) from [tbl_Partner_Entity] pa_et where [E_ID] =@E_ID) 
           AS cnt_all
         ,(ROW_NUMBER() over ( order by pe.p_id)) as row_num
         ,Case when (
            (ROW_NUMBER() over ( order by pe.p_id)) < 
            (Select count(*)   from [tbl_Partner_Entity] pa_et where [E_ID] =@E_ID))
          then round(([partnership_partners_perc]*100),2)
          else 
             100-
        ((select sum(round(([partnership_partners_perc]*100),2))  FROM [dbo].
         [tbl_Partner_Entity] PEE where [E_ID] =@E_ID and pee.P_ID != pe.P_ID))
          end AS [partnership_partners_perc_Last]
    
    FROM [dbo].[tbl_Partner_Entity] PE
    where [E_ID] =@E_ID
    
    选择您的
    ,(从[tbl_Partner_Entity]页面选择计数(*),其中[E_ID]=@E_ID)
    作为所有人
    ,(按pe.p_id排序)上的行数()作为行数
    ,例如(
    (按pe.p\U id排序)上方的行号()
    (从[tbl_Partner_Entity]页面选择计数(*),其中[E_ID]=@E_ID))
    然后是第二轮(([partnership_partners_perc]*100),第二轮)
    其他的
    100-
    (从[dbo]中选择总和(四舍五入([partnership_partners_perc]*100),2)。
    [tbl_Partner_Entity]PEE,其中[E_ID]=@E_ID和PEE.P_ID!=pe.P_ID))
    终止为[合伙企业\合伙人\最后一个]
    来自[dbo].[tbl\U合作伙伴\U实体]PE
    其中[E_ID]=@E_ID
    
    您的百分比有14位小数,为什么不在
    百分比
    列中输入
    0.33333
    ?如果我说“您只需更新供应商设置百分比=0.34,其中…”然后你可能会明白,仅仅通过阅读这个问题,理解你真正需要什么是多么困难……看看马丁·福勒的“数量”模式。特别是,看看关于资金分配的讨论。示例中的除法返回一个值数组,而不是单个值。值的数组加起来就是总数。我发现这很简单。我知道我们可以在已经计算的百分比的基础上更新/使用第二组sql,这就是我目前正在计算的。。但在我们计算百分比的同一个sql中,这不是有一个简单的逻辑吗?两组sql可以轻松地完成这项任务,这就是我目前正在做的。但我正在寻找一个单步流程,在该流程中,丢失的数据应该针对任何随机供应商自动分配,性能影响较小,因为它需要在Teradata上每小时运行数十亿行。这看起来几乎与我预期的一样。非常感谢你。现在,我必须应用这个逻辑和调优,以便在Teradata上实现这一点。非常感谢。如果您的主要索引在产品密钥上,您应该会获得相当好的性能,因为每个放大器都应该处理每个计算。是的。但我在这里给出的示例与我的场景并不完全相同。我已经有了一套SQL,它可以用更复杂的连接完成大部分的拆分工作。上面提供的示例是为了使其易于理解。非常感谢你,N West。
    totalvalue  / COUNT(*) OVER (PARTITION BY Product) as customer_split
    
    SELECT 
       Product                       
       ,Supplier                      
       ,totalvalue                    
       ,customer_split 
        + CASE
             WHEN COUNT(*) 
                  OVER (PARTITION BY Product
                        ROWS UNBOUNDED PRECEDING) = 1 -- get a random row, using row_number/order you might define a specific row
             THEN totalvalue - SUM(customer_split)
                               OVER (PARTITION BY Product)
             ELSE 0
          END
    FROM 
     (
       SELECT
          Product                       
          ,Supplier                      
          ,totalvalue                    
          ,totalvalue / COUNT(*) OVER (PARTITION BY Product) AS customer_split
       FROM dropme
     ) AS dt
    
    Select your_cols
          ,(Select count(*) from [tbl_Partner_Entity] pa_et where [E_ID] =@E_ID) 
           AS cnt_all
         ,(ROW_NUMBER() over ( order by pe.p_id)) as row_num
         ,Case when (
            (ROW_NUMBER() over ( order by pe.p_id)) < 
            (Select count(*)   from [tbl_Partner_Entity] pa_et where [E_ID] =@E_ID))
          then round(([partnership_partners_perc]*100),2)
          else 
             100-
        ((select sum(round(([partnership_partners_perc]*100),2))  FROM [dbo].
         [tbl_Partner_Entity] PEE where [E_ID] =@E_ID and pee.P_ID != pe.P_ID))
          end AS [partnership_partners_perc_Last]
    
    FROM [dbo].[tbl_Partner_Entity] PE
    where [E_ID] =@E_ID