Tuesday, December 27, 2011

Finding average balance from HDFC bank statement


Here is a perl script which parses a text delimeted account statement and generates an SQL script that gives average balance maintained for the statement period. If the statement is for a quarter, it gives average quarterly balance (AQB).

#!/usr/bin/perl

# Usage: perl gen_aqb_calc.pl < stmt_file.txt > aqb_calc.sql

$seq = 1;

print "set feedback off;\n\n";
print "create table xcts(sn number, dt date, bal number(20,2));\n\n";

while(<stdin>)
{
 next unless /^\s*\d\d\/\d\d\/\d\d/; # Skip heading and blank lines
 @fields = split(',');

 # Example format of downloaded statement is
 # 20/10/11  ,POS 4214 BHARTI AIRTEL LI  ,20/10/11 , 444.00  , 0.00 ,1011413 ,  23730.59 

 $date = $fields[0];
 $closing_bal = $fields[6];

 $date =~ s/\s//g;
 $closing_bal =~ s/\s//g;

 print "insert into xcts values ($seq, to_date('$date', 'dd/mm/yy'), $closing_bal); \n";

 $seq++;
}

print "\ncommit;\n";

print "
with closing_balances as(select x1.dt, x1.bal
                  from xcts x1,
                       (select max(sn) maxsn, dt from xcts group by dt) x2
                 where x1.sn = x2.maxsn
                 order by x1.dt)
 select round( sum(t1.bal * nvl(t2.dt - t1.dt, 1)) / (max(t1.dt) - min(t1.dt) + 1) , 2 ) average_balance
  from (select rownum rn, dt, bal
          from closing_balances) t1,
       (select rownum - 1 rn, dt
          from closing_balances) t2
 where t1.rn = t2.rn(+);
";

print "\ndrop table xcts purge;\n";

The perl script generates below SQL script. When we execute it against Oracle database, it gives average balance.
 
set feedback off;

create table xcts(sn number, dt date, bal number(20,2));

insert into xcts values (1, to_date('01/10/11', 'dd/mm/yy'), 45651.08);
-- Some more insert statements here, removed from clarity

commit;

with closing_balances as(select x1.dt, x1.bal
                  from xcts x1,
                       (select max(sn) maxsn, dt from xcts group by dt) x2
                 where x1.sn = x2.maxsn
                 order by x1.dt)
 select round( sum(t1.bal * nvl(t2.dt - t1.dt, 1)) / (max(t1.dt) - min(t1.dt) + 1) , 2 ) average_balance
  from (select rownum rn, dt, bal
          from closing_balances) t1,
       (select rownum - 1 rn, dt
          from closing_balances) t2
 where t1.rn = t2.rn(+);

drop table xcts purge;

udev rules to change ownership of LVM partition (RHEL/OEL 5)

When a logical volume is used for ASM disk, the logical volume should be given ownership grid infrastructure user and group. This can be set simply by adding chown commands /etc/rc.local file (a dirty work around). The same thing can be accomplished even by using udev rules like below.

In this example, we are trying to use logical volume vol05 in volume group vg1 for grid infrastructure.


Add below line to /etc/udev/rules.d/91-lvm-
asmdisk.rules (entire content in single line)

SUBSYSTEM=="block", KERNEL=="dm-*", ACTION=="add|change", PROGRAM="/sbin/dmsetup info -c --noheadings -o name -j %M -m %m", RESULT=="vg1-vol05", RUN+="/bin/chown grid:asmadmin /dev/mapper/vg1-vol05"

Deactivate and activate logical volume to verify if udev rule is working fine.
# lvchange -an vg1/vol05
# lvchange -ay vg1/vol05
 
Now ownership is changed for logical volume.
# ls -l /dev/mapper/vg1-vol05
brw-rw---- 1 grid asmadmin 253, 4 Dec 14 22:33 /dev/mapper/vg1-vol05

Finding related tables recursively


When we try to refresh a set of tables from one database to another database, we have to refresh all direct/indirect parent/child tables to those set of tables for data integrity. To find out all those related tables, here is the query.

select
    distinct related_table
from
    ( /* All related tables in the database */
      ( /* Related tables are parent tables in this subquery */
       select
              parent_con.owner       related_table_owner,
              parent_con.table_name  related_table,
              child_con.owner        given_table_owner,
              child_con.table_name   given_table
       from
              all_constraints  parent_con,
              all_constraints  child_con
       where
              child_con.r_constraint_name = parent_con.constraint_name
      )
      union
      ( /* Related tables are child tables in this subquery */
       select
              child_con.owner        related_table_owner,
              child_con.table_name   related_table,
              parent_con.owner       given_table_owner,
              parent_con.table_name  given_table
       from
              all_constraints  parent_con,
              all_constraints  child_con
       where
              child_con.r_constraint_name = parent_con.constraint_name
      )
    )
connect by nocycle prior related_table = given_table
start with
        given_table_owner = 'MURTY'
    and given_table in ('TAB1', 'TAB2')
order by 1;