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

Sure this is a noob question..and sure you hear that alot but I'll ask away :). The below is a snipet of code. It's printing the Headers before it prints the hash keys and values.
print OUTPUT "New Student Registrations\n----------------------\n"; foreach my $Inst (sort keys %RegStudentNew) { if ($RegStudentNew{$Inst} ) { print OUTPUT "$Inst\t$RegStudentNew{$Inst}\n"; } } print OUTPUT "\nNew Instructor Registrations\n--------------------\n"; foreach my $Inst (sort keys %RegInstructorNew) { if ($RegInstructorNew{$Inst} ) { print OUTPUT "$Inst\t$RegInstructorNew{$Inst}\n"; } } print OUTPUT "\nExisting Student Registrations\n-----------------\n"; foreach my $Inst (sort keys %RegStudentExisting) { if ($RegStudentExisting{$Inst} ) { print OUTPUT "$Inst\t$RegStudentExisting{$Inst}\n"; } }

The Output looks like this:

New Student Registrations
---------------------------

New Instructor Registrations
------------------------

Existing Student Registration
-----------------------

With the data following after. Any ideas on how to get the headers to show up in the right spot?

Replies are listed 'Best First'.
Re: Printing out of order...
by ELISHEVA (Prior) on Mar 05, 2009 at 09:00 UTC

    Given that your disordered output is going to a single stream, it is unlikely that there is a buffering problem. Order-related buffering problems tend to apply primarily to output that involves multiple streams (e.g. STDERR and STDOUT).

    Even though you think that the hashes are filled, how exactly did you determine that the output you are seeing for hash X really belongs to hash X? It seems to me that the normal way of showing that: a title, followed by a hash content dump is exactly what you are doing - and it says otherwise. Additionally, pudelli has demonstrated that when prepopulated hashes are used (without all the SQL to populate it), your code works as expected.

    The SQL query within the foreach loop is pretty complicated, and that is even after you have simplified it to remove security information. So the more likely thing is that the branches that fill the various hashes aren't actually being visited in the way you expect and hence haven't been filled. Have you tried distinctive print STDERR statements at each place where you think the hash members are being added -e.g. print STDERR "filling new student reg hash key=<$key> value=<$value>"?.

    BTW, no need to apologize for asking a "noob" question - the only way to "unnoob" yourself is to be a noob and ask. This is especially true when it comes to debugging - learning what to focus on takes time and happens much more quickly when we can share experiences. Thumbs up for a well formulated question.

    Best, beth

Re: Printing out of order...
by chromatic (Archbishop) on Mar 05, 2009 at 06:41 UTC

    I don't believe that's your actual code, unless there's something unexpected in the data you haven't explained. Post some sample data and we'll have a better chance of explaining what's happening.

      Below is the first 15ish lines or so of output.
      New Student Registrations --------------------------- New Instructor Registrations ------------------------ Existing Student Registrations ----------------------- Existing Instructor Registrations --------------------- Student Logins ---------------------------------------- AALBORG UNIVERSITY 2 AARHUS ENGINEERING COLLEGE 1 ABRAHAM BALDWIN AGRICULTURAL CLG 24 ACADIA UNIVERSITY 3 ADAMS STATE COLLEGE 2 ADELPHI UNIVERSITY 5
      As you can see most of the headers are appearing at the top.

        Have you checked that those hashes actually contain data? If the hashes are empty, the output is correct.

        --
        seek $her, $from, $everywhere if exists $true{love};
Re: Printing out of order...
by puudeli (Pilgrim) on Mar 05, 2009 at 06:47 UTC

    Please tell us more about OUTPUT. When I changed the output to be STDOUT (with default $|) it worked just fine. Maybe your file handle does some buffering?

    %RegStudentNew = qw( foo 1 bar 2 ); %RegInstructorNew = qw( foo 1 bar 2 ); %RegStudentExisting = qw( foo 1 bar 2 ); print "New Student Registrations\n----------------------\n"; foreach my $Inst (sort keys %RegStudentNew) { if ($RegStudentNew{$Inst} ) { print "$Inst\t$RegStudentNew{$Inst}\n"; } } print "\nNew Instructor Registrations\n--------------------\n"; foreach my $Inst (sort keys %RegInstructorNew) { if ($RegInstructorNew{$Inst} ) { print "$Inst\t$RegInstructorNew{$Inst}\n"; } } print "\nExisting Student Registrations\n-----------------\n"; foreach my $Inst (sort keys %RegStudentExisting) { if ($RegStudentExisting{$Inst} ) { print "$Inst\t$RegStudentExisting{$Inst}\n"; } }
    cpt2jmo@phantom:~/misc$ perl print.pl New Student Registrations ---------------------- bar 2 foo 1 New Instructor Registrations -------------------- bar 2 foo 1 Existing Student Registrations ----------------- bar 2 foo 1
    --
    seek $her, $from, $everywhere if exists $true{love};
      Here's the entire script. Some elements where deleted due to security reasons.
      #!/usr/bin/perl use strict; use warnings; use DBD::mysql; ###################### #### CONFIG VARS ##### ###################### #Specify start and end dates to filter data my $start_date = '2009-02-01'; my $end_date = '2009-02-31'; #Specify blocked institutions my @blocked_institutions = (); my $domain_filter = ""; my $output_file = 'Modern_Registration_2-1_to_2-31.txt'; ###################### #### PRIVATE VARS #### ###################### my %hosts = (); my $db_user = ''; my $db_pass = ''; my %RegStudentNew; my %RegInstructorNew; my %RegStudentExisting; my %RegInstructorExisting; my %StudentLogins; my %InstructorLogins; ###################### #### MAIN BODY ####### ###################### open OUTPUT, ">$output_file"; while (my ($host, $default_db) = each(%hosts)) { #get database urls for host my @databases = get_databases($host, $default_db, $db_user, $db_pa +ss); @databases = sort(@databases); #process data on each database foreach my $database (@databases) { print join ("/", $host, $database) . "\n"; #Existing Accounts that added Product(s) my $dbh = DBI->connect("DBI:mysql:database=$database:host=$hos +t",$db_user,$db_pass,{RaiseError=>1})|| die "$DBI::errstr\n"; my $sql = "SELECT ar.UserID, i.Name, u.Parent FROM $default_db +.AccessRights AS ar JOIN Users AS u ON ar.userID=u.ID JOIN $default_d +b.Institutions AS i ON ar.InstitutionID=i.ID WHERE CONVERT(ar.LastModified, Date) BETWEEN '$start_date' + AND '$end_date' AND CONVERT(u.CreatedAt,Date) < '$start_date' "; my $sth = $dbh->prepare ( $sql ); $sth->execute(); while (my @row = $sth->fetchrow_array()) { if ($row[2] == '1') { $RegStudentExisting{$row[1]} += 1 } if ($row[2] == '2') { $RegInstructorExisting{$row[1]} += +1 } } $sql = "SELECT u.ID, u.Parent, i.Name FROM Users AS u JOIN + $default_db.Institutions AS i ON u.InstitutionID=i.ID WHERE CONVERT( +from_unixtime(u.LastLoginAt/1000), Date) BETWEEN '$start_date' AND '$ +end_date' "; $sth = $dbh->prepare ( $sql ); $sth->execute(); while (my @rows = $sth->fetchrow_array() ) { if ($rows[1] == '1') { $StudentLogins{$rows[2]} += 1 } if ($rows[1] == '2') { $InstructorLogins{$rows[2]} += +1 } } $sql = "SELECT ar.UserID, i.Name, u.Parent FROM $defau +lt_db.AccessRights AS ar JOIN Users AS u ON ar.userID=u.ID JOIN $defa +ult_db.Institutions AS i ON ar.InstitutionID=i.ID WHERE (CONVERT(ar.LastModified, Date) BETWEEN '$st +art_date' AND '$end_date') AND (CONVERT(u.CreatedAt,Date) BETWEEN '$s +tart_date' AND '$end_date') "; $sth = $dbh->prepare ( $sql ); $sth->execute(); while (my @rows1 = $sth->fetchrow_array() ) { if ($rows1[2] == '1') { $RegStudentNew{$rows1[1]} += 1 + } if ($rows1[2] == '2') { $RegInstructorNew{$rows1[1]} ++= 1 } } $sth->finish(); $dbh->disconnect(); } } # PRINT RESULTS (Will turn into sr) print OUTPUT "New Student Registrations\n---------------------------\n +"; foreach my $Inst (sort keys %RegStudentNew) { if ($RegStudentNew{$Inst} ) { print OUTPUT "$Inst\t$RegStudentNew{$Inst}\n"; } } print OUTPUT "\nNew Instructor Registrations\n------------------------ +\n"; foreach my $Inst (sort keys %RegInstructorNew) { if ($RegInstructorNew{$Inst} ) { print OUTPUT "$Inst\t$RegInstructorNew{$Inst}\n"; } } print OUTPUT "\nExisting Student Registrations\n---------------------- +-\n"; foreach my $Inst (sort keys %RegStudentExisting) { if ($RegStudentExisting{$Inst} ) { print OUTPUT "$Inst\t$RegStudentExisting{$Inst}\n"; } } print OUTPUT "\nExisting Instructor Registrations\n------------------- +--\n"; foreach my $Inst (sort keys %RegInstructorExisting) { if ($RegInstructorExisting{$Inst} ) { print OUTPUT "$Inst\t$RegInstructorExisting{$Inst}\n"; } } print OUTPUT "\nStudent Logins\n-------------------------------------- +--\n"; foreach my $Inst (sort keys %StudentLogins) { if ($StudentLogins{$Inst} ) { print OUTPUT "$Inst\t$StudentLogins{$Inst}\n"; } } print OUTPUT "\nInstructor Logins\n----------------------------------- +---\n"; foreach my $Inst (sort keys %InstructorLogins) { if ($InstructorLogins{$Inst} ) { print OUTPUT "$Inst\t$InstructorLogins{$Inst}\n"; } } close OUTPUT; ###################### #### PRIVATE SUBS #### ###################### sub get_databases { my @database_urls; my ($host, $default_db, $db_user, $db_pass) = @_; my $dbh = DBI->connect("DBI:mysql:database=$default_db:host=$host" +,$db_user,$db_pass,{RaiseError=>1})|| die "$DBI::errstr\n"; my $sql = "SELECT DISTINCT IF(DatabaseURL = '.', '$default_db', SU +BSTRING_INDEX(SUBSTRING_INDEX(DatabaseURL, '/', -1), '?', 1)) AS Data +baseURL FROM Institutions WHERE WebSiteURL = '.' AND ID != ''"; my $sth = $dbh->prepare ( $sql ); $sth->execute(); while (my @row = $sth->fetchrow_array()) { my $url = $row[0]; push (@database_urls, $url); } $sth->finish(); $dbh->disconnect(); return @database_urls; }
      The hashes do contain data. The buffering may be something to look at though not sure where to start for that.

        The hashes do contain data

        What you've posted so far shows otherwise*, so we'll need more than your word for it.

        * — Specifically, you've shown the hashes don't contain any values that evaluate to true. They could have keys whose values evaluate to false.

        Perhaps only the %StudentLogins or %InstructorLogins hashes have data with true values. Something like this will confirm it:

        use Data::Dumper; print Data::Dumper->Dump([\%RegStudentNew, \%RegInstructorNew, \%RegStudentExisting, \%RegInstructorExisting, \%StudentLogins, \%InstructorLogins ], [qw( RegStudentNew, RegInstructorNew, RegStudentExisting, RegInstructorExisting, StudentLogins, InstructorLogins )]);