reuben12 has asked for the wisdom of the Perl Monks concerning the following question:

I need to query a table ,retrieve two columns of info in multiple rows. I need to parse through each row after finding out how many rows are there and extract the column data and store it in a vcariable. For example , if there are 5 rows of information

For i=0 to 5

do

Get row of ouput from isql

$lname$i=<extract first column>

$fname$i=<extract second column>

Go to next row of output from isql

done

These variables i use to query database in later part of the script.

Is it possible? I have done it in ksh but am very new to perl.

I know how to open a file,write query to it and execute using isql through perl. I just dont know how to implement the above pseudo code.

Can somebody please help??

Thanks..

I'm afraid i have no idea what DBI is but i guess its sort of extension to perl that i need to install. I cant be sure that i can get it installed in customer place. But normal isql seems to solve my problem.

After getting these data i need to create a view on sybase server and then bcp out the data. I have written the perl script for it and it is working fine but for a fixed number of inputs.

The fname,lname form part of the WHERE clause of the query. How can i write SQL statement to create view with variable number of conditions in WHERE clause

CREATE VIEW cust_view AS select * from customer where fname='AAAA' AND fname='BBBB' AND ...

How do i handle this assuming i have all the 'fnames' in an array and so know the count of array elements.??

Replies are listed 'Best First'.
Re: how to parse output from isql utility
by Joost (Canon) on Jul 26, 2004 at 22:36 UTC
    I would use DBI for this. Generally, using a seperate database program to get at the data is error prone (though I must admit I've done it myself a couple of times when I couldn't get the DBI modules installed fast enough).

    This should get you started (UNTESTED):

    use DBI; my $dbh = DBI->connect( @some_connect_info, { RaiseError => 1 } ); my ($count) = $dbh->fetchrow_array("COUNT * FROM table"); my $sth = $dbh->prepare("SELECT col1,col2 FROM table"); $sth->execute(); while (my $res = $sth->fetchrow_hashref) { # in this block # value1 == $res->{col1}; # value2 == $res->{col2}; }
    update: note that I don't need the $count variable at all. It's just there because you specified it in your post. In perl, this is generally true; most looping constructs do not need a count. see also the perlsyn manpage
Re: how to parse output from isql utility
by graff (Chancellor) on Jul 27, 2004 at 01:33 UTC
    I know how to open a file,write query to it and execute using isql through perl. I just dont know how to implement the above pseudo code.

    If the DBI and appropriate DBD module are not in place for the perl you're using (and installing them is "outside your scope" -- nothing to be ashamed of), then your initial approach of using a known, working command line tool (like isql) is fine.

    As for how to handle the data within the perl script, your pseudo-code suggests that you're not familiar with perl data types and data structures. I could point you to the "perldata" man page, but if you have trouble with that, try perldsc (data structures cookbook), or any basic book on learning perl, to get a handle on scalars, arrays and hashes, and more elaborate structures built from combinations of arrays and/or hashes. Once you understand how the data storage and structuring works, it can be pretty easy to figure out what sort of structure you need for your app, and how to build it up from (and apply it to) your database queries.

    So taking the command-line "isql" tool as the data source, one way to get started would be:

    # you already have this part: my $qry_file = "some_name.sql"; # or whatever open( QRY, ">$qry_file" ) or die "can't write $qry_file: $!"; print QRY "select foo from bar where baz='x'\n"; close QRY; # Run isql by opening it as a pipeline # (I'm guessing at the command-line usage): my @fnames, @lnames; # query output will be stored here # update: using the correct variable name for the query file: open( DB, "isql $qry_file |" ) or die "can't run isql: $!"; while (<DB>) { # assuming the tool prints one line per row chomp; # remove newline my ( $lname, $fname ) = split(/\t/); # assuming fields are tab-del +imited push @fnames, $fname; push @lnames, $lname; } close DB; # now you can do whatever you want, iterating over # the contents of @lnames and/or @fnames for my $i ( 0..$#fnames ) { print "Row = $i, Full_name = $fnames[$i] $lnames[i]\n"; }
    It's likely that your app could use some other sort of data structure to good advantage, in place of the two parallel arrays suggested above, but you haven't said enough about what you're doing.
Re: how to parse output from isql utility
by mpeppler (Vicar) on Jul 27, 2004 at 06:28 UTC
    Once upon a time, way back in the mists of time (i.e. sometime in 1990 :-) I started my first version of "sybperl" like this: write the SQL to a temp file, run isql and parse the output. Then I got an email from Larry about using pseudo-TTYs and running isql as a sub-processes - I still have that code somewhere (1990 vintage perl...) if anyone is interested.

    Assuming that this is Sybase (maybe MS-SQL has it as well) you should use the "-s" command-line argument to specify a column separator that is unlikely to occur in the data. You should also specify the "-w" argument with a large integer to make sure that isql doesn't wrap any of the output lines. So something like this could work:

    open(TMP, ">/tmp/t$$.sql") || die "can't open temp file: $!"; # Set nocount to avoid the "xxx rows affected" message in isql print TMP "set nocount on\ngo\nselect * from the_table\ngo\n"; close(TMP); # Note: -b flag suppresses column headers. open(ISQL, "isql -Ujoe -Pjoespwd -Smyserver -s'%%^^%%' -w 1024 -b -i / +tmp/t$$.sql") || die "Can't run isql: $!"; while(<ISQL>) { chomp; my @row = split(/%%^^%%/, $_); .... do something with the @row of data.... } close(ISQL);
    That being said - using DBI and the appropriate DBD driver is a lot better. It's faster, and error handling is much easier.

    Michael

Re: how to parse output from isql utility
by Plankton (Vicar) on Jul 26, 2004 at 22:39 UTC
    The typical Perl way to interact with a RDBMS is to use a DBI and the DBD for you RDBMS which I assume is Sybase. You might have to google around to find the correct DBD package. Another way deal with this would be to treat the output from isql just as you would any other program.
    my $cmd="isql $connect-string"; open ISQL, "|$cmd" or die "couldn't open $cmd:$!\n"; print ISQL <<end; select * from whatever; ...
    ... that code snippet would query the database. You would need a second script that would execute and read the output. Something like this ...
    my $cmd="exec_isql.pl"; open OUT, "$cmd|" or die "couldn't open $cmd:$!\n"; my @results = <OUT>; print "First row is " . $results[0] ."\n";

    Plankton: 1% Evil, 99% Hot Gas.
Re: how to parse output from isql utility
by naChoZ (Curate) on Jul 27, 2004 at 00:34 UTC

    Yes, definitely use DBI.

    Here's a few lines from one of my old scripts that read from a sybase. The environment stuff is important. IIRC, it will be the same even if you're using the freetds libs.

    use DBI; BEGIN { # path to sybase or freetds libs $ENV{'SYBASE'} = "/opt/sybase"; # Sybase server as listed in your 'interfaces' file $ENV{'DSQUERY'} = "server.host.name"; } my (@available_drivers, $dbh, $sql_statement, $sth, @array) = (); my $username = "dbusername"; my $password = "dbpassword"; my $dbh = DBI->connect('dbi:Sybase:', $username, $password);

    After that, you're good to go with normal DBI methods straight from the docs.

    --
    "A long habit of not thinking a thing wrong, gives it a superficial appearance of being right." -- Thomas Paine
    naChoZ

Re: how to parse output from isql utility
by periapt (Hermit) on Jul 27, 2004 at 12:17 UTC
    I think that graff has the basic idea. There are some specific gotchas about isql from the command line that I have come across over the years.
    my $qrycmd = '-S[Server] -U[userid] -P[password] -h-1 -n -s:'; # -h-1 suppresses headers # -n removes numbering and the prompt symbol (>) from input lines # -s: sets the field seperator to a colon, :, this eliminates a space # between fields and in the first position of the line (tabs, \t, # doesn't work reliably open( DB, "isql $qrycmd -iperlmonk34.sql |" ) or die "can't run isql: +$!"; while (<DB>) { # assuming the tool prints one line per row chomp; # remove newline my ( $lname, $fname ) = split(/:/); # the if statement accounts for the last two lines of the isql output # which consists of a blank line followed by a line listing rows # affected if(defined $fname){ push @fnames, $fname; push @lnames, $lname; } } close DB;

    PJ
    unspoken but ever present -- use strict; use warnings; use diagnostics; (if needed)