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

Hi Monks,
Anyone knows if it's possible to get all the names of the tables from a SQL2000 DB and based on the choice of the db table print all it's row names? Has anyone done something like that before? Thanks a lot!!!!

Replies are listed 'Best First'.
Re: Reading DB
by hardburn (Abbot) on Nov 06, 2003 at 20:40 UTC

    See the table_info() method in DBI.

    ----
    I wanted to explore how Perl's closures can be manipulated, and ended up creating an object system by accident.
    -- Schemer

    : () { :|:& };:

    Note: All code is untested, unless otherwise stated

      Cake walk.

      Check out your SqlServer docs (or the online ones) for the system stored procedures sp_tables and sp_columns if the DBI module can't help you. Be sure to actually call those procs from DBI, though! Otherwise my perlmonk comment is wasted. ;)

      Hanlon's Razor - "Never attribute to malice that which can be adequately explained by stupidity"
Re: Reading DB
by ChrisR (Hermit) on Nov 07, 2003 at 02:14 UTC
    I have never used SQL2000 before but found it fairly simple for MySQL. Here are some subroutines that I use to manage an sql database on a webserver.
    sub GetDatabases { my @tempdbname; my @databases2; my @databases = DBI->data_sources("mysql"); for my $x(0..$#databases) { @tempdbname = split(/:/,$databases[$x]); push @databases2, $tempdbname[$#tempdbname]; } return @databases2; } sub GetTables { my $database = shift; my @tables2; my $datasource = "dbi:mysql:dbname=$database;host=localhost;"; my $dbh = DBI->connect($datasource,'dbuser','password' ,{PrintErro +r => 0}) or return @tables2; my $statement = "SHOW TABLES"; my $sth = $dbh->prepare($statement); my $rc = $sth->execute(); if($rc ne "0E0") { my $tables = $sth->fetchall_arrayref; for my $xx(0..$#{$tables}) { push @tables2,$tables->[$xx][0]; } } return @tables2; } sub GetFields { my $database = shift; my $table = shift; my @fields; my $counter = 0; my $test; my $datasource = "dbi:mysql:dbname=$database;host=localhost;"; my $dbh = DBI->connect($datasource,'dbuser','password'); my $statement = "DESCRIBE $table;"; my $sth = $dbh->prepare($statement99); my $rc = $sth->execute(); while($test = $sth->fetchrow_hashref) { $counter++; for my $t(keys %{$test}) { # field field info $fields[$counter]{$t} = $test->{$t}; } } return @fields; }
    I know it may not be very pretty or efficient but it is effective and simple. I'll leave the implementation up to you.
Re: Reading DB
by injunjoel (Priest) on Nov 06, 2003 at 21:24 UTC
    Greetings all,
    Let me preface this post with the fact that I do not work with SQL2000 (Im more of an opensource proponent).
    However if you are using DBI you can get the column names of any particular table:
    use strict; use DBI; my $dbh = DBI->connect('DBI:database_type:database_name','user','passw +ord') || die DBI->errstr; my $sth = $dbh->prepare("SELECT * FROM table_name WHERE 0=1") || die $ +dbh->errstr; $sth->execute() || die $sth->errstr; my @column_names = @{$sth->{NAME}}; $sth->finish(); $dbh->disconnect();
    Now @column_names will contain the column names for your table.
    Im sure it can be done a lot more elegantly then I have illustrated here, but thats a start.
    As for a list of tables with the database...I have no suggestions. Im not sure about the behaviour of SQL2000 or even if there is support in DBI.
    Hope that helps get you at least part of the way to your solution.
    -injunjoel

    UPDATE Added the $sth->execute();
    Updated prepared query for portability(though I would hate to be the developer without access to LIMIT... InterBase anyone?)
    Thanks to (jZed & mpeppler) for catching that.
    -injunjoel
      While you should be commended to point at a lowest common denominator solution it should be pointed out that the LIMIT keyword is non-standard (and your code snippet is also missing the $sth->execute call :-).

      It shouldn't be necessary to even fetch a single row for this. A WHERE clause that evaluates to false achieves this with minimal impact on the server:

      use strict; use DBI; my $dbh = DBI->connect('DBI:database_type:database_name','user','passw +ord') || die DBI->errstr; my $sth = $dbh->prepare("SELECT * FROM table_name WHERE 0=1") || die $ +dbh->errstr; $sth->excecute || die $sth->errstr; my @column_names = @{$sth->{NAME}}; $sth->finish(); # may be unnecessary $dbh->disconnect();

      Update Fixed typo in WHERE clause...

      Michael

        The snippet doesn't work I can't print anything thing and WHERE 0=1 1 is not ODBC friendly.
      In general your code is a good way to approach getting column names, but you get a bit tripped up on some of the specifics at least if the code has any hope of being portable.

      my $sth=$dbh->prepare("SELECT * FROM table_name LIMIT 1")... my @column_names = @{$sth->{NAME}};

      1. LIMIT is not standard SQL and doesn't exist for many RDBMSs, unfortunately even "WHERE 1=0" isn't usable everywhere

      2. $sth->{NAME} is not necessarily valid until after an execute.

      3. It's best to specify $sth->{NAME_lc} or $sth->{NAME_uc} since different databases store the column names differently even if they ignore the case in actual SQL.

Re: Reading DB
by menolly (Hermit) on Nov 06, 2003 at 20:34 UTC

    And your Perl question is?

    Most RDBMSs I've seen have built-in capability to list tables, and to list columns of a table, yes. Exacly how that's done varies.