在sql中计算两列不同的行

时间:2015-08-06 09:40:08

标签: sql oracle

我有桌子t1

ID    NAME        AGE GENDER   BALANCE
----- ----- --------- ----- ---------
1001  John         10 M            10
1002  Meena         5 F             0
1003  Nikh         11 M             0
1004  divs          7 F             0
1005  neha          4 F             0

从第二行开始,如果Gender为M,则应为Balance(第二行) 年龄(2)+平衡(1)

else Balance(1)-age(2)

最终结构应该像

ID    NAME        AGE GENDER   BALANCE
----- ----- --------- ----- ---------
1001  John         10 M            10
1002  Meena         5 F             5
1003  Nikh         11 M             16
1004  divs          7 F             9
1005  neha          4 F             5

请帮我查询/程序

3 个答案:

答案 0 :(得分:3)

这样的事情怎么样?

with sample_data as (select 1001 id, 'John' name, 10 age, 'M' gender, 10 balance from dual union all
                     select 1002 id, 'Meena' name, 5 age, 'F' gender, 0 balance from dual union all
                     select 1003 id, 'Nikh' name, 11 age, 'M' gender, 0 balance from dual union all
                     select 1004 id, 'divs' name, 7 age, 'F' gender, 0 balance from dual union all
                     select 1005 id, 'neha' name, 4 age, 'F' gender, 0 balance from dual)
select id,
       name,
       age,
       gender,
       sum(case when gender = 'F' then -1 * age else age end) over (order by id) balance
from   sample_data;

        ID NAME         AGE GENDER    BALANCE
---------- ----- ---------- ------ ----------
      1001 John          10 M              10
      1002 Meena          5 F               5
      1003 Nikh          11 M              16
      1004 divs           7 F               9
      1005 neha           4 F               5

我猜测第一行的余额(我在这里假设一个id的顺序)是10,因为这是约翰的年龄和他的年龄。男性,而不是一些任意数字。

ETA:以上是上述解决方案的替代方案。我 HIGHLY 建议您针对类似生产的数据量测试所有内容(我使用with子句来模仿一个名为sample_data的表,包含5行,您只需要使用您的表)。这样,您就可以获得应该突出显示场景中性能最佳的方法的时间;希望你的经理不会对事实视而不见(如果他是,那就跑。快跑!)

1)没有分析函数的SQL语句:

with sample_data as (select 1001 id, 'John' name, 10 age, 'M' gender, 10 balance from dual union all
                     select 1002 id, 'Meena' name, 5 age, 'F' gender, 0 balance from dual union all
                     select 1003 id, 'Nikh' name, 11 age, 'M' gender, 0 balance from dual union all
                     select 1004 id, 'divs' name, 7 age, 'F' gender, 0 balance from dual union all
                     select 1005 id, 'neha' name, 4 age, 'F' gender, 0 balance from dual)
select sd1.id,
       sd1.name,
       sd1.age,
       sd1.gender,
       sum(case when sd2.gender = 'F' then -1 * sd2.age else sd2.age end) balance
from   sample_data sd1
       inner join sample_data sd2 on (sd1.id >= sd2.id)
group by sd1.id,
         sd1.name,
         sd1.age,
         sd1.gender
order by id;

        ID NAME         AGE GENDER    BALANCE
---------- ----- ---------- ------ ----------
      1001 John          10 M              10
      1002 Meena          5 F               5
      1003 Nikh          11 M              16
      1004 divs           7 F               9
      1005 neha           4 F               5

2)程序(逐行慢行{yawn})方法(不推荐):

create or replace procedure calc_balance1
as
  v_balance number := 0;
  cursor cur is
    with sample_data as (select 1001 id, 'John' name, 10 age, 'M' gender, 10 balance from dual union all
                     select 1002 id, 'Meena' name, 5 age, 'F' gender, 0 balance from dual union all
                     select 1003 id, 'Nikh' name, 11 age, 'M' gender, 0 balance from dual union all
                     select 1004 id, 'divs' name, 7 age, 'F' gender, 0 balance from dual union all
                     select 1005 id, 'neha' name, 4 age, 'F' gender, 0 balance from dual)
    select id,
           name,
           age,
           gender,
           balance
    from   sample_data;
begin
  for rec in cur
  loop
    v_balance := v_balance + case when rec.gender = 'F' then -1 * rec.age 
                                  else rec.age
                             end;
    dbms_output.put_line('id = '||rec.id||', name = '||rec.name||', age = '||rec.age||', gender = '||rec.gender||', balance = '||v_balance);
  end loop;
end calc_balance1;
/

begin
  calc_balance;
end;
/

id = 1001, name = John, age = 10, gender = M, balance = 10
id = 1002, name = Meena, age = 5, gender = F, balance = 5
id = 1003, name = Nikh, age = 11, gender = M, balance = 16
id = 1004, name = divs, age = 7, gender = F, balance = 9
id = 1005, name = neha, age = 4, gender = F, balance = 5

但是,如果您必须为此提出一个程序,我将使用带有分析函数的查询并将其粘贴在引用游标中,例如:

create or replace procedure calc_balance2 (p_refcur out sys_refcursor)
as
begin
  open p_refcur for with sample_data as (select 1001 id, 'John' name, 10 age, 'M' gender, 10 balance from dual union all
                                         select 1002 id, 'Meena' name, 5 age, 'F' gender, 0 balance from dual union all
                                         select 1003 id, 'Nikh' name, 11 age, 'M' gender, 0 balance from dual union all
                                         select 1004 id, 'divs' name, 7 age, 'F' gender, 0 balance from dual union all
                                         select 1005 id, 'neha' name, 4 age, 'F' gender, 0 balance from dual)
                    select id,
                           name,
                           age,
                           gender,
                           sum(case when gender = 'F' then -1 * age else age end) over (order by id) balance
                    from   sample_data
                    order by id;
end calc_balance2;
/

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

我看到你写的程序;我会怎么做呢:

-- mimicking your test_divs table:
create table test_divs as
select 1001 id, 'John' name, 10 age, 'M' gender, 10 balance from dual union all
select 1002 id, 'Meena' name, 5 age, 'F' gender, 0 balance from dual union all
select 1003 id, 'Nikh' name, 11 age, 'M' gender, 0 balance from dual union all
select 1004 id, 'divs' name, 7 age, 'F' gender, 0 balance from dual union all
select 1005 id, 'neha' name, 4 age, 'F' gender, 0 balance from dual;

create or replace procedure t1_d12_v2
as
begin
  merge into test_divs tgt
  using (select id,
                name,
                age,
                gender,
                sum(case when gender = 'F' then -1 * age else age end) over (order by id) balance
         from   test_divs) src
    on (tgt.id = src.id)
  when matched then
    update set tgt.balance = src.balance;
end t1_d12_v2;
/

select * from test_divs;

        ID NAME         AGE GENDER    BALANCE
---------- ----- ---------- ------ ----------
      1001 John          10 M              10
      1002 Meena          5 F               0
      1003 Nikh          11 M               0
      1004 divs           7 F               0
      1005 neha           4 F               0

begin
  t1_d12_v2;
  commit;
end;
/

select * from test_divs;

        ID NAME         AGE GENDER    BALANCE
---------- ----- ---------- ------ ----------
      1001 John          10 M              10
      1002 Meena          5 F               5
      1003 Nikh          11 M              16
      1004 divs           7 F               9
      1005 neha           4 F               5

HIGHLY 建议您使用类似生产的数据测试这两种方法,看看哪种方法效果更好。 (如果您的经理真的死于分析函数,我会将" src"子查询交换为我想出的另一个sql语句 - 具有join和group by的那个。)

像你一样逐行地进行更新,每次通过循环都会在sql和pl / sql之间进行两次上下文切换。当你可以在一个sql语句中完成整个事情时,为什么还要烦恼呢。严重。

答案 1 :(得分:0)

select ID, NAME, AGE, GENDER,  @b:=if(GENDER='M', @b+AGE, @b-AGE) BALANCE 
  from t1, (select @b:=0) b

Demo on sqlfiddle.com

答案 2 :(得分:0)

public static void main(String args[]) throws FileNotFoundException {
    Properties ps =new Properties();
    // Create the file object
    File fileObj = new File("data.txt");
    try {

        FileInputStream fis = new FileInputStream(fileObj);
        ps.load(fis);
        System.out.println("Properties:"+ps);
        System.out.println("Get A:"+ps.getProperty("a"));

    } catch (Exception err) {

        err.printStackTrace();
    }
}