【问题标题】:SQL Query to calculate weight or distribute weight based on value/nullSQL Query 根据值/空来计算权重或分配权重
【发布时间】:2009-12-17 16:08:13
【问题描述】:

我有一个包含列的表格 - id、x1、x2、x3、x4

如果我有价值观

1,y,y,y,y
2,y,null,n,null
3,y,null,null,null

然后说,我想计算 (1)/(y 的数量) 并将行显示为

1,.25,.25,.25,.25
2,1,0,0,0
3,1,0,0,0

是否可以使用 sql 查询来做到这一点?

【问题讨论】:

    标签: .net sql-server sql-server-2005 tsql stored-procedures


    【解决方案1】:

    这是另一个使用子查询的蛮力攻击。设置一些测试数据:

    CREATE TABLE MyTable
     (
       Id   int     not null
      ,Col1 char(1) null
      ,Col2 char(1) null
      ,Col3 char(1) null
      ,Col4 char(1) null
     )
    
    INSERT MyTable
               select 1, 'Y', 'Y', 'Y', 'Y'
     union all select 2, 'Y', null, 'N', null
     union all select 3, 'Y', null, null, null
     union all select 4, null, null, null, null
    

    我使用字符数据作为目标值,但将其设为数字​​应该没有问题。我添加了第四行来检查除以零(感谢 ps!)。所以,

    SELECT
       mt.ID
      ,case mt.Col1 when 'Y' then xx.distrib else 0 end
      ,case mt.Col2 when 'Y' then xx.distrib else 0 end
      ,case mt.Col3 when 'Y' then xx.distrib else 0 end
      ,case mt.Col4 when 'Y' then xx.distrib else 0 end
     from MyTable mt
      inner join (select
                    ID
                    ,1.0 / (  case Col1 when 'Y' then 1 else 0 end
                            + case Col2 when 'Y' then 1 else 0 end
                            + case Col3 when 'Y' then 1 else 0 end
                            + case Col4 when 'Y' then 1 else 0 end) distrib
                   from MyTable) xx
       on xx.Id = mt.Id
    

    似乎产生了预期的结果。 (单独运行子查询,你会得到除以零......但老实说,我不知道为什么运行整个查询不会。

    【讨论】:

    • 带有 unpivot 的优雅的东西可能会起作用,但可能是矫枉过正。
    【解决方案2】:

    这里的幼稚版本是

    SELECT 
        id,
        CASE 
        WHEN x1 IS NULL THEN
            0
        WHEN f_eval(x1) + f_eval(x2,0) + f_eval(x3,0) + f_eval(x4,0) = 0 THEN
            -- default value
        ELSE
            1 / (f_eval(x1) + f_eval(x2,0) + f_eval(x3,0) + f_eval(x4,0))
        END,
        -- repeat for each column
    FROM
        Table
    

    其中 f_eval 或多或少被定义为:

    CREATE FUNCTION f_eval(
          @x_value varchar(1)
    BEGIN
    
        DECLARE @return_val int
        SELECT
            @return_val = 
            case
            WHEN ISNULL(@x_value, 'n') = 'y' THEN
                1
            ELSE
                0
            END
    
         RETURN @return_val
    END
    

    【讨论】:

    • 已编辑以考虑非空值。
    【解决方案3】:

    试一试

    select 
    
    (SUM(case when x1 is null then 0 else 1 end))* 1.0/ ((SUM(case when x1 is null then 0 else 1 end) + SUM(case when x2 is null then 0 else 1 end)+ SUM(case when x3 is null then 0 else 1 end) + + SUM(case when x4 is null then 0 else 1 end)) * 1.0),
    (SUM(case when x2 is null then 0 else 1 end))* 1.0/ ((SUM(case when x1 is null then 0 else 1 end) + SUM(case when x2 is null then 0 else 1 end)+ SUM(case when x3 is null then 0 else 1 end) + + SUM(case when x4 is null then 0 else 1 end)) * 1.0),
    (SUM(case when x3 is null then 0 else 1 end))* 1.0/ ((SUM(case when x1 is null then 0 else 1 end) + SUM(case when x2 is null then 0 else 1 end)+ SUM(case when x3 is null then 0 else 1 end) + + SUM(case when x4 is null then 0 else 1 end)) * 1.0),
    (SUM(case when x4 is null then 0 else 1 end))* 1.0/ ((SUM(case when x1 is null then 0 else 1 end) + SUM(case when x2 is null then 0 else 1 end)+ SUM(case when x3 is null then 0 else 1 end) + + SUM(case when x4 is null then 0 else 1 end)) * 1.0)
    from table group by id
    

    你可能已经确保你不被零除

    编辑 2

    当分母为 0 和 1 时,再增加一个 case。 你也应该改变

       case when x1 is null then 0 else 1 end
    

     case when x1 = 'y' then 1 else 0 end
    

    【讨论】:

      【解决方案4】:

      试试这个

      样本数据

      declare  @t table( Id int,Col1 char(1) null,Col2 char(1) null,Col3 char(1) null,Col4 char(1) null)
      INSERT @t select 1, 'Y', 'Y', 'Y', 'Y' union all select 2, 'Y', null, null, null
       union all select 3, 'Y', null, null, null  
      

      查询:

      select t.id 
       ,case Col1 when 'Y' then LEFT(cast( 1.0/x.cntys as varchar(20)),4) else cast( 0 as varchar(1)) end x1
       ,case Col2 when 'Y' then LEFT(cast( 1.0/x.cntys as varchar(20)),4) else cast( 0 as varchar(1)) end x2
       ,case Col3 when 'Y' then LEFT(cast( 1.0/x.cntys as varchar(20)),4) else cast( 0 as varchar(1)) end x3
       ,case Col4 when 'Y' then LEFT(cast( 1.0/x.cntys as varchar(20)),4) else cast( 0 as varchar(1)) end x4
      
       from @t t
       join(
       select ROW_NUMBER() over(order by getdate()) rn, 
        COUNT(col1) + COUNT(col2) + COUNT(col3) + COUNT(col4) cntys from @t 
      group by id)X
      on t.Id = X.rn 
      

      输出:

      id x1 x2 x3 x4 
      1 0.25 0.25 0.25 0.25 
      2 1.00 0 0 0 
      3 1.00 0 0 0 
      

      【讨论】:

        猜你喜欢
        • 2022-01-16
        • 1970-01-01
        • 1970-01-01
        • 2011-09-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多