SQL:如何检查列中的值等于行中其他列的任意组合的总和

时间:2017-07-28 18:40:32

标签: sql oracle sum combinations

我遇到了一个我有表结构的场景:

Column0 Column1 Column2 Column3 Column4 Column5 
100     U       V       X       Y       Z

我需要找到:

  • 100 = UVXYZ
  • 100 = X + Y + Z + V
  • 100 = X + Y
  • 100 = V + Z

有关如何实现这一目标的任何建议?

案例陈述将永远写下来。我不写PL / SQL代码,但我对它很熟悉。

3 个答案:

答案 0 :(得分:3)

撰写Case声明并不像您所暗示的那样难。我在大约20秒内使用文本编辑器生成了以下Case语句,它应该处理示例中的所有情况:

Select  Case
            When Column0 = Column1  Then 1
            When Column0 = Column2  Then 1
            When Column0 = Column3  Then 1
            When Column0 = Column4  Then 1
            When Column0 = Column5  Then 1

            When Column0 = Column1 + Column2    Then 1
            When Column0 = Column1 + Column3    Then 1
            When Column0 = Column1 + Column4    Then 1
            When Column0 = Column1 + Column5    Then 1

            When Column0 = Column2 + Column3    Then 1
            When Column0 = Column2 + Column4    Then 1
            When Column0 = Column2 + Column5    Then 1

            When Column0 = Column3 + Column4    Then 1
            When Column0 = Column3 + Column5    Then 1

            When Column0 = Column4 + Column5    Then 1

            When Column0 = Column1 + Column2 + Column3  Then 1
            When Column0 = Column1 + Column2 + Column4  Then 1
            When Column0 = Column1 + Column2 + Column5  Then 1

            When Column0 = Column1 + Column3 + Column4  Then 1
            When Column0 = Column1 + Column3 + Column5  Then 1

            When Column0 = Column1 + Column4 + Column5  Then 1

            When Column0 = Column2 + Column3 + Column4  Then 1
            When Column0 = Column2 + Column3 + Column5  Then 1

            When Column0 = Column2 + Column4 + Column5  Then 1

            When Column0 = Column3 + Column4 + Column5  Then 1

            When Column0 = Column1 + Column2 + Column3 + Column4    Then 1
            When Column0 = Column1 + Column2 + Column3 + Column5    Then 1

            When Column0 = Column1 + Column3 + Column4 + Column5    Then 1

            When Column0 = Column2 + Column3 + Column4 + Column5    Then 1

            When Column0 = Column1 + Column2 + Column3 + Column4 + Column5  Then 1

            Else 0
        End As SumOfOtherColumns
From    YourTable

答案 1 :(得分:0)

即使答案已经被接受,这是我的替代解决方案。在性能方面,很可能更糟糕(待测试)但我认为值得展示的原因如下:

正如您所看到的,有5列,很容易错过一些案例,只有31个案例需要检查。如果添加一列,则为63checks,下一个为127 ...您不必担心这里因为它会动态生成所有情况

另一个有趣的一点是,如果您有兴趣查看每一行的详细信息及其匹配的原因,那么查询就可以免费使用。你只需要选择子视图

最后一点是,我认为它在学术上很有趣。解决方案包含UNPIVOTing数据,递归自连接,动态动态表达式评估。当然,我不是客观的,但这很有趣:)

--Table and data to test the query
create table my_table ( column0 number, column1 number, column2 number, 
                        column3 number, column4 number, column5 number );

INSERT INTO my_table values (100,20,20,10,40,10); -- must match on the sum of 5 columns
INSERT INTO my_table values (100,50,200,300,150,250); -- must not match
INSERT INTO my_table values (100,50,50,100,150,250); -- must match twice ( on col1+col2 and col3 )

-- If your table has a unique key, you can remove the datas_with_id and put
-- your table directly in the unpivoted_data subquery
with datas_with_id  as ( select rowid as row_id, t.* from my_table t),
     unpivoted_data as ( select row_id, column0 as sum_to_check, column_name, column_value 
                         from datas_with_id 
                         unpivot ( column_value for column_name in (column1,column2,column3,column4,column5))),
     calculated_sum as ( select row_id, xmlquery(sys_connect_by_path(u.column_value,'+')||' = '|| sum_to_check
                         returning content).getStringVal() result
                         from unpivoted_data u connect by nocycle prior column_name>column_name 
                         and prior row_id=row_id and level < 6)
select * from my_table where rowid in ( select row_id from calculated_sum where result = 'true' )

如果你想添加另一列,请在unpivot子句中添加,在级别加1并且你很好

如果添加sys_connect_by_path(u.column_name,'+')||' ='||在calculate_sum中sum_to_check,您可以看到匹配的每个公式

答案 2 :(得分:0)

在这里,我写了一些你可以动态使用它的代码

1 - 首先我创建表并为其生成一行

create table my_table ( column0 number, column1 number, column2 number, 
                        column3 number, column4 number, column5 number );

INSERT INTO my_table values (100,20,20,10,40,10);

2 - 创建类型如下行

create or replace type Key_Value_Typ as object
(

  column_name   varchar2(100),
  column_val    varchar2(100)  
)

3 - 你可以在这里看到一个例子

declare
  lv_count number;
  lv_row   my_table%rowtype;

  type my_list is table of Key_Value_Typ;
  list1 my_list;

  ------------------------------------------------------------

  -- function for control column condition

  function check_fun(
    lv_list my_list, 
      -- the function input is array of key value include column name and column value
      -- you can implement your code here, for example as input parameter declare your own parameters 
    -- for example
    --   lv_column0 my_table.column0%type;
    lv_where varchar2
    -- the condition that you want check it
    ) return number is

    lv_str   varchar2(200);
    lv_count number;
  begin

    lv_str := lv_where;

    for i in 1 .. lv_list.count Loop

      lv_str := replace(lv_str,
                        lv_list(i).column_name,
                        lv_list(i).column_val);

    ENd Loop;

    execute immediate 'select count(*) from dual where ' || lv_str
      into lv_count;

    -- if the function return 1 result is true and o means result is false
    return lv_count;

  end check_fun;

  ------------------------------------------------------------

begin
  -- fetch data from my_table and get one of them 
  select * into lv_row from my_table where column0 = 100;

  -- create list of data include columns and values
  list1 := my_list(Key_Value_Typ('column0', lv_row.column0),
                   Key_Value_Typ('column1', lv_row.column1),
                   Key_Value_Typ('column2', lv_row.column2),
                   Key_Value_Typ('column3', lv_row.column3),
                   Key_Value_Typ('column4', lv_row.column4),
                   Key_Value_Typ('column5', lv_row.column5));


  lv_count := check_fun(list1, 'column0=column1+column2+column3+column4+column5');

  dbms_output.put_line('result ()' || lv_count);

end;