Decode360's Blog

业精于勤而荒于嬉 QQ:150355677 MSN:decode360@hotmail.com

  BlogJava :: 首页 :: 新随笔 :: 联系 ::  :: 管理 ::
  397 随笔 :: 33 文章 :: 29 评论 :: 0 Trackbacks
两段好玩的SQL[AskTom]
 
    Tom的下面两段SQL都写得比较好玩,没有用到很复杂的函数,主要是思路很受益。第一段SQL的题目比较新奇,以前没遇到过这样的情况,Tom的答案也比较规整,基本就是自己创建一个标志位,然后在外层向左推进一位,当然用PLSQL肯定可以有更加便捷的方法。第二段SQL主要是中间的那句的思路,换我的话估计就是sum()over()之后再sign+decode了,用least+greatest真的比较精彩的逻辑。
 

 
4 stars can we move not null values into one side and null values into one side?   May 11, 2004 - 7am US/Eastern
Reviewer: dmv from india
 
Tom
   we have a table with the following structure :
 
inv_id  addr_1   addr_2   addr_3   addr_4
  
    1    xxx      null     null      yyy
    2    null     xxx      null      yyy
    3    null     null     xxx       yyy
    4    null     null     null      xxx
    5    xxx      null     yyy       null
    6    xxx      null     yyy       zzz
 
output should be :
 
inv_id  addr_1   addr_2   addr_3   addr_4
  
    1    xxx      yyy      null      null
    2    xxx      yyy      null      null
    3    xxx      yyy      null      null
    4    xxx      null     null      null     
    5    xxx      yyy      null      null
    6    xxx      yyy      zzz       null
 
    all Null values should move into one side, and all Not Null values should move into one side.
 
Is it possible in a single update command?
 
Thanks
dmv
 
 
 
Followup   May 11, 2004 - 9am US/Eastern:

SQL
> select * from t;
 
        ID          A          B          C          D
---------- ---------- ---------- ---------- ----------
         1          1                                2
         2                     1                     2
         3                                1          2
         4                                           2
         5          1                     2
         6          1                     2          3
 
6 rows selected.
 
SQL
>
SQL
> update
  2  (
  3  select id, olda, oldb, oldc, oldd,
  4         a,
  5             b,
  6         decode(shift,0,c,d) c,
  7             decode(shift,0,d,null) d
  8    from (
  9  select t.*, decode(c,null,1,0) shift
10    from (
11  select id, olda, oldb, oldc, oldd,
12         a,
13         decode(shift,0,b,1,c,2,d) b,
14         decode(shift,0,c,1,d) c,
15         decode(shift,0,d,null) d
16    from (
17  select t.*, decode(b,null,decode(c,null,2,1),0) shift
18    from (
19  select id, olda, oldb, oldc, oldd,
20         decode(shift,0,a,1,b,2,c,3,d) a,
21         decode(shift,0,b,1,c,2,d) b,
22         decode(shift,0,c,1,d) c,
23         decode(shift,0,d,1,null) d
24    from (
25  select a olda, b oldb, c oldc, d oldd, t.*,
decode(a,null,decode(b,null,decode(c,null,3,2),1),0) shift
26    from t
27         )
28             ) t
29             )
30             ) t
31             )
32  )
33  set olda = a, oldb = b, oldc = c, oldd = d
34  /
 
6 rows updated.
 
SQL
> select * from t;
 
        ID          A          B          C          D
---------- ---------- ---------- ---------- ----------
         1          1          2
         2          1          2
         3          1          2
         4          2
         5          1          2
         6          1          2          3
 
6 rows selected.
 

There are probably an infinite number of ways to do it, that was just the first that popped into
mind.   make sure all 4 columns are the SAME TYPE of course.
 
 
 
 

 
5 stars Update without a cursor   January 17, 2005 - 1am US/Eastern
Reviewer: siva from India
Tom,
I have a similar question on update. I'm providing the  sample script below.
 
      create table testupdate
      (sno number(4),
      itemcode varchar2(8),
      value number(4),
      appliedvalue number(4))
 

     insert into testupdate (sno,itemcode,value) values(1,'item1',200);
     insert into testupdate (sno,itemcode,value) values(2,'item2',100);
     insert into testupdate (sno,itemcode,value) values(3,'item3',300);
     insert into testupdate (sno,itemcode,value) values(4,'item4',200);
     insert into testupdate (sno,itemcode,value) values(5,'item5',50);
     insert into testupdate (sno,itemcode,value) values(6,'item6',200);
     insert into testupdate (sno,itemcode,value) values(7,'item7',400);
 

     SNO ITEMCODE      VALUE APPLIEDVALUE
-------- -------- ---------- ------------
       1 item1           200
       2 item2           100
       3 item3           300
       4 item4           200
       5 item5            50
       6 item6           200
       7 item7           400
Now:
I'm writing a stored procedure in which I have to update the appliedvalue column of the above
table.
For this I have something called the actualValue which is stored in the variable vnum_actualValue.
This value in the variable vnum_actualValue should be distributed among the appliedvalue column as
follows.
 

     vnum_actualValue = 1000;
 
After the distribution of the value 1000, the updated table should look like this:
 

     SNO ITEMCODE      VALUE APPLIEDVALUE
-------- -------- ---------- ------------
       1 item1           200          200
       2 item2           100          100
       3 item3           300          300
       4 item4           200          200
       5 item5            50           50
       6 item6           200          150
       7 item7           400            0
 
                              ( TOTAL:1000 )
 
Now, I can very well do this with a cursor. Is there any way to do this with a single update
statement? I'm using 9i R2.
 
Thanks very much in advance.
               
 
 
 
Followup   January 17, 2005 - 8am US/Eastern:
 
SQL> select * from t;
 
       SNO ITEMCODE      VALUE APPLIEDVALUE
---------- -------- ---------- ------------
         1 item1           200
         2 item2           100
         3 item3           300
         4 item4           200
         5 item5            50
         6 item6           200
         7 item7           400
 
7 rows selected.
 
SQL> merge into t
  2  using (
  3  select sno, itemcode, value,
  4         greatest( least( value, :x -(sum(value) over (order by sno)-value)),0) new_appliedvalue
  5    from t
  6  ) X
  7  on (t.sno = x.sno )
  8  when matched then update set appliedvalue = new_appliedvalue
  9  when not matched then insert (sno) values (null) -- NEVER can happen
10  /
 
7 rows merged.
 
SQL> select * from t;
 
       SNO ITEMCODE      VALUE APPLIEDVALUE
---------- -------- ---------- ------------
         1 item1           200          200
         2 item2           100          100
         3 item3           300          300
         4 item4           200          200
         5 item5            50           50
         6 item6           200          150
         7 item7           400            0
 
7 rows selected.
 
 
 
 
posted on 2009-04-04 22:43 decode360 阅读(242) 评论(0)  编辑  收藏 所属分类: 05.SQL

只有注册用户登录后才能发表评论。


网站导航: