Diff for /loncom/interface/loncoursedata.pm between versions 1.124 and 1.134

version 1.124, 2004/03/08 16:14:37 version 1.134, 2004/06/04 17:46:10
Line 475  about both the response and part data. Line 475  about both the response and part data.
 'transaction', and 'timestamp'.    'transaction', and 'timestamp'.  
 The primary key is based on the first 3 columns.  The primary key is based on the first 3 columns.
   
   =item $weight_table
   
   The weight table holds the weight for the problems used in the class.
   Whereas the weight of a problem can vary by section and student the data
   here is applied to the class as a whole.
   Columns: 'symb_id','part_id','response_id','weight'.
   
 =back  =back
   
 =back  =back
Line 518  my $parameters_table; Line 525  my $parameters_table;
 my $fulldump_response_table;  my $fulldump_response_table;
 my $fulldump_part_table;  my $fulldump_part_table;
 my $fulldump_timestamp_table;  my $fulldump_timestamp_table;
   my $weight_table;
   
 my @Tables;  my @Tables;
 ################################################  ################################################
Line 539  store student data. Line 547  store student data.
 ################################################  ################################################
 ################################################  ################################################
 sub init_dbs {  sub init_dbs {
     my $courseid = shift;      my ($courseid,$drop) = @_;
     &setup_table_names($courseid);      &setup_table_names($courseid);
     #      #
     # Drop any of the existing tables      # Drop any of the existing tables
     foreach my $table (@Tables) {      if ($drop) {
         &Apache::lonmysql::drop_table($table);          foreach my $table (@Tables) {
               &Apache::lonmysql::drop_table($table);
           }
     }      }
     #      #
     # Note - changes to this table must be reflected in the code that       # Note - changes to this table must be reflected in the code that 
Line 572  sub init_dbs { Line 582  sub init_dbs {
                       restrictions => 'NOT NULL',                        restrictions => 'NOT NULL',
                       auto_inc     => 'yes', },                        auto_inc     => 'yes', },
                     { name => 'part',                      { name => 'part',
                       type => 'VARCHAR(100)',                        type => 'VARCHAR(100) BINARY',
                       restrictions => 'NOT NULL'},                        restrictions => 'NOT NULL'},
                     ],                      ],
         'PRIMARY KEY' => ['part (100)'],          'PRIMARY KEY' => ['part (100)'],
Line 587  sub init_dbs { Line 597  sub init_dbs {
                       restrictions => 'NOT NULL',                        restrictions => 'NOT NULL',
                       auto_inc     => 'yes', },                        auto_inc     => 'yes', },
                     { name => 'student',                      { name => 'student',
                       type => 'VARCHAR(100)',                        type => 'VARCHAR(100) BINARY',
                       restrictions => 'NOT NULL UNIQUE'},                        restrictions => 'NOT NULL UNIQUE'},
                     { name => 'section',                      { name => 'section',
                       type => 'VARCHAR(100)',                        type => 'VARCHAR(100) BINARY',
                       restrictions => 'NOT NULL'},                        restrictions => 'NOT NULL'},
                     { name => 'status',                      { name => 'status',
                       type => 'VARCHAR(15)',                        type => 'VARCHAR(15) BINARY',
                       restrictions => 'NOT NULL'},                        restrictions => 'NOT NULL'},
                     { name => 'classification',                      { name => 'classification',
                       type => 'varchar(100)', },                        type => 'VARCHAR(100) BINARY', },
                     { name => 'updatetime',                      { name => 'updatetime',
                       type => 'INT UNSIGNED'},                        type => 'INT UNSIGNED'},
                     { name => 'fullupdatetime',                      { name => 'fullupdatetime',
Line 621  sub init_dbs { Line 631  sub init_dbs {
                       type => 'MEDIUMINT UNSIGNED',                        type => 'MEDIUMINT UNSIGNED',
                       restrictions => 'NOT NULL' },                        restrictions => 'NOT NULL' },
                     { name => 'part',                      { name => 'part',
                       type => 'VARCHAR(100)',                        type => 'VARCHAR(100) BINARY',
                       restrictions => 'NOT NULL'},                                            restrictions => 'NOT NULL'},                    
                     { name => 'solved',                      { name => 'solved',
                       type => 'TINYTEXT' },                        type => 'TINYTEXT' },
                     { name => 'tries',                      { name => 'tries',
                       type => 'SMALLINT UNSIGNED' },                        type => 'SMALLINT UNSIGNED' },
                     { name => 'awarded',                      { name => 'awarded',
                       type => 'TINYTEXT' },                        type => 'REAL' },
                     { name => 'award',                      { name => 'award',
                       type => 'TINYTEXT' },                        type => 'TINYTEXT' },
                     { name => 'awarddetail',                      { name => 'awarddetail',
Line 663  sub init_dbs { Line 673  sub init_dbs {
                     { name => 'award',                      { name => 'award',
                       type => 'TINYTEXT' },                        type => 'TINYTEXT' },
                     { name => 'awarded',                      { name => 'awarded',
                       type => 'TINYTEXT' },                        type => 'REAL' },
                     { name => 'previous',                      { name => 'previous',
                       type => 'SMALLINT UNSIGNED' },                        type => 'SMALLINT UNSIGNED' },
 #                    { name => 'regrader',  #                    { name => 'regrader',
Line 701  sub init_dbs { Line 711  sub init_dbs {
                     { name => 'awarddetail',                      { name => 'awarddetail',
                       type => 'TINYTEXT' },                        type => 'TINYTEXT' },
 #                    { name => 'message',  #                    { name => 'message',
 #                      type => 'CHAR' },  #                      type => 'CHAR BINARY'},
                     { name => 'response_specific',                      { name => 'response_specific',
                       type => 'TINYTEXT' },                        type => 'TINYTEXT' },
                     { name => 'response_specific_value',                      { name => 'response_specific_value',
Line 740  sub init_dbs { Line 750  sub init_dbs {
                   { columns=>['transaction'] },                    { columns=>['transaction'] },
                   ],                    ],
     };      };
   
     #      #
     my $parameters_table_def = {      my $parameters_table_def = {
         id => $parameters_table,          id => $parameters_table,
Line 760  sub init_dbs { Line 769  sub init_dbs {
         'PRIMARY KEY' => ['symb_id','student_id','parameter (255)'],          'PRIMARY KEY' => ['symb_id','student_id','parameter (255)'],
     };      };
     #      #
       my $weight_table_def = {
           id => $weight_table,
           permanent => 'no',
           columns => [{ name => 'symb_id',
                         type => 'MEDIUMINT UNSIGNED',
                         restrictions => 'NOT NULL'  },
                       { name => 'part_id',
                         type => 'MEDIUMINT UNSIGNED',
                         restrictions => 'NOT NULL'  },
                       { name => 'weight',
                         type => 'REAL',
                         restrictions => 'NOT NULL'  },
                       ],
           'PRIMARY KEY' => ['symb_id','part_id'],
       };
       #
     # Create the tables      # Create the tables
     my $tableid;      my $tableid;
     $tableid = &Apache::lonmysql::create_table($symb_table_def);      $tableid = &Apache::lonmysql::create_table($symb_table_def);
Line 816  sub init_dbs { Line 841  sub init_dbs {
                                  &Apache::lonmysql::get_error());                                   &Apache::lonmysql::get_error());
         return 9;          return 9;
     }      }
       $tableid = &Apache::lonmysql::create_table($weight_table_def);
       if (! defined($tableid)) {
           &Apache::lonnet::logthis("error creating weight_table: ".
                                    &Apache::lonmysql::get_error());
           return 10;
       }
     return 0;      return 0;
 }  }
   
Line 1052  sub populate_student_table { Line 1083  sub populate_student_table {
     }      }
     #      #
     &setup_table_names($courseid);      &setup_table_names($courseid);
       &init_dbs($courseid,0);
     my $dbh = &Apache::lonmysql::get_dbh();      my $dbh = &Apache::lonmysql::get_dbh();
     my $request = 'INSERT IGNORE INTO '.$student_table.      my $request = 'INSERT IGNORE INTO '.$student_table.
         "(student,section,status) VALUES ";          "(student,section,status) VALUES ";
Line 1077  sub populate_student_table { Line 1109  sub populate_student_table {
     return;      return;
 }  }
   
   
 ################################################  ################################################
 ################################################  ################################################
   
Line 1548  sub ensure_tables_are_set_up { Line 1579  sub ensure_tables_are_set_up {
     my @CurrentTable = &Apache::lonmysql::tables_in_db();      my @CurrentTable = &Apache::lonmysql::tables_in_db();
     my ($found_symb,$found_student,$found_part,      my ($found_symb,$found_student,$found_part,
         $found_performance,$found_parameters,$found_fulldump_part,          $found_performance,$found_parameters,$found_fulldump_part,
         $found_fulldump_response,$found_fulldump_timestamp);          $found_fulldump_response,$found_fulldump_timestamp,
           $found_weight);
     foreach (@CurrentTable) {      foreach (@CurrentTable) {
         $found_symb        = 1 if ($_ eq $symb_table);          $found_symb        = 1 if ($_ eq $symb_table);
         $found_student     = 1 if ($_ eq $student_table);          $found_student     = 1 if ($_ eq $student_table);
Line 1558  sub ensure_tables_are_set_up { Line 1590  sub ensure_tables_are_set_up {
         $found_fulldump_part      = 1 if ($_ eq $fulldump_part_table);          $found_fulldump_part      = 1 if ($_ eq $fulldump_part_table);
         $found_fulldump_response  = 1 if ($_ eq $fulldump_response_table);          $found_fulldump_response  = 1 if ($_ eq $fulldump_response_table);
         $found_fulldump_timestamp = 1 if ($_ eq $fulldump_timestamp_table);          $found_fulldump_timestamp = 1 if ($_ eq $fulldump_timestamp_table);
           $found_weight      = 1 if ($_ eq $weight_table);
     }      }
     if (!$found_symb        ||       if (!$found_symb          || 
         !$found_student     || !$found_part   ||          !$found_student       || !$found_part              ||
         !$found_performance || !$found_parameters ||          !$found_performance   || !$found_parameters        ||
         !$found_fulldump_part || !$found_fulldump_response ||          !$found_fulldump_part || !$found_fulldump_response ||
         !$found_fulldump_timestamp ) {          !$found_fulldump_timestamp || !$found_weight ) {
         if (&init_dbs($courseid)) {          if (&init_dbs($courseid,1)) {
             return 'error';              return 'error';
         }          }
     }      }
Line 1974  sub get_problem_statistics { Line 2007  sub get_problem_statistics {
     $dbh->do($request);      $dbh->do($request);
     #      #
     # Collect the first suite of statistics      # Collect the first suite of statistics
     $request = 'SELECT COUNT(*),SUM(tries),MAX(tries),AVG(tries),STD(tries) '.      $request = 'SELECT COUNT(*),SUM(tries),'.
           'AVG(tries),STD(tries) '.
         'FROM '.$stats_table;          'FROM '.$stats_table;
     my ($num,$tries,$mod,$mean,$STD) = &execute_SQL_request      my ($num,$tries,$mean,$STD) = &execute_SQL_request
         ($dbh,$request);          ($dbh,$request);
       #
       $request = 'SELECT MAX(tries),MIN(tries) FROM '.$stats_table.
           ' WHERE awarded>0';
       if (defined($time_requirements)) {
           $request .= ' AND '.$time_requirements;
       }
       my ($max,$min) = &execute_SQL_request($dbh,$request);
       #
     $request = 'SELECT SUM(awarded) FROM '.$stats_table;      $request = 'SELECT SUM(awarded) FROM '.$stats_table;
       if (defined($time_requirements)) {
           $request .= ' AND '.$time_requirements;
       }
     my ($Solved) = &execute_SQL_request($dbh,$request);      my ($Solved) = &execute_SQL_request($dbh,$request);
       #
     $request = 'SELECT SUM(awarded) FROM '.$stats_table.      $request = 'SELECT SUM(awarded) FROM '.$stats_table.
         " WHERE solved='correct_by_override'";          " WHERE solved='correct_by_override'";
       if (defined($time_requirements)) {
           $request .= ' AND '.$time_requirements;
       }
     my ($solved) = &execute_SQL_request($dbh,$request);      my ($solved) = &execute_SQL_request($dbh,$request);
     #      #
       $Solved -= $solved;
       #
     $num    = 0 if (! defined($num));      $num    = 0 if (! defined($num));
     $tries  = 0 if (! defined($tries));      $tries  = 0 if (! defined($tries));
     $mod    = 0 if (! defined($mod));      $max    = 0 if (! defined($max));
       $min    = 0 if (! defined($min));
     $STD    = 0 if (! defined($STD));      $STD    = 0 if (! defined($STD));
     $Solved = 0 if (! defined($Solved));      $Solved = 0 if (! defined($Solved) || $Solved < 0);
     $solved = 0 if (! defined($solved));      $solved = 0 if (! defined($solved));
     #      #
     # Compute the more complicated statistics      # Compute the more complicated statistics
Line 1997  sub get_problem_statistics { Line 2049  sub get_problem_statistics {
     #      #
     my $SKEW = 'nan';      my $SKEW = 'nan';
     my $wrongpercent = 0;      my $wrongpercent = 0;
       my $numwrong = 'nan';
     if ($num > 0) {      if ($num > 0) {
         ($SKEW) = &execute_SQL_request($dbh,'SELECT SQRT(SUM('.          ($SKEW) = &execute_SQL_request($dbh,'SELECT SQRT(SUM('.
                                      'POWER(tries - '.$STD.',3)'.                                       'POWER(tries - '.$STD.',3)'.
                                      '))/'.$num.' FROM '.$stats_table);                                       '))/'.$num.' FROM '.$stats_table);
         $wrongpercent=int(10*100*($num-$Solved+$solved)/$num)/10;          $numwrong = $num-$Solved;
           $wrongpercent=int(10*100*$numwrong/$num)/10;
     }      }
     #      #
     # Drop the temporary table      # Drop the temporary table
     $dbh->do('DROP TABLE '.$stats_table);  # May return an error      $dbh->do('DROP TABLE '.$stats_table);  # May return an error
     #      #
     # Store in metadata  
     if ($num) {  
  my %storestats=();  
         #  
         my $urlres=(&Apache::lonnet::decode_symb($symb))[2];  
         #  
  $storestats{$courseid.'___'.$urlres.'___timestamp'}=time;         
  $storestats{$courseid.'___'.$urlres.'___stdno'}=$num;  
  $storestats{$courseid.'___'.$urlres.'___avetries'}=$mean;     
  $storestats{$courseid.'___'.$urlres.'___difficulty'}=$DegOfDiff;  
         #  
  $urlres=~/^(\w+)\/(\w+)/;   
  &Apache::lonnet::put('nohist_resevaldata',\%storestats,$1,$2);   
     }  
     #  
     # Return result      # Return result
     return { num_students => $num,      return { num_students => $num,
              tries        => $tries,               tries        => $tries,
              max_tries    => $mod,               max_tries    => $max,
                min_tries    => $min,
              mean_tries   => $mean,               mean_tries   => $mean,
              std_tries    => $STD,               std_tries    => $STD,
              skew_tries   => $SKEW,               skew_tries   => $SKEW,
              num_solved   => $Solved,               num_solved   => $Solved,
              num_override => $solved,               num_override => $solved,
                num_wrong    => $numwrong,
              per_wrong    => $wrongpercent,               per_wrong    => $wrongpercent,
              deg_of_diff  => $DegOfDiff };               deg_of_diff  => $DegOfDiff };
 }  }
   
   ##
   ## This is a helper for get_statistics
 sub execute_SQL_request {  sub execute_SQL_request {
     my ($dbh,$request)=@_;      my ($dbh,$request)=@_;
 #    &Apache::lonnet::logthis($request);  #    &Apache::lonnet::logthis($request);
Line 2047  sub execute_SQL_request { Line 2090  sub execute_SQL_request {
     return ();      return ();
 }  }
   
   ######################################################
   ######################################################
   
   =pod
   
   =item &populate_weight_table
   
   =cut
   
   ######################################################
   ######################################################
   sub populate_weight_table {
       my ($courseid) = @_;
       if (! defined($courseid)) {
           $courseid = $ENV{'request.course.id'};
       }
       #
       &setup_table_names($courseid);
       my ($top,$sequences,$assessments) = get_sequence_assessment_data();
       if (! defined($top) || ! ref($top)) {
           # There has been an error, better report it
           &Apache::lonnet::logthis('top is undefined');
           return;
       }
       #       Since we use lonnet::EXT to retrieve problem weights,
       #       to ensure current data we must clear the caches out.
       &Apache::lonnet::clear_EXT_cache_status();
       my $dbh = &Apache::lonmysql::get_dbh();
       my $request = 'INSERT IGNORE INTO '.$weight_table.
           "(symb_id,part_id,weight) VALUES ";
       my $weight;
       foreach my $res (@$assessments) {
           my $symb_id = &get_symb_id($res->{'symb'});
           foreach my $part (@{$res->{'parts'}}) {
               my $part_id = &get_part_id($part);
               $weight = &Apache::lonnet::EXT('resource.'.$part.'.weight',
                                              $res->{'symb'},
                                              undef,undef,undef);
               if (!defined($weight) || ($weight eq '')) { 
                   $weight=1;
               }
               $request .= "('".$symb_id."','".$part_id."','".$weight."'),";
           }
       }
       $request =~ s/(,)$//;
   #    &Apache::lonnet::logthis('request = '.$/.$request);
       $dbh->do($request);
       if ($dbh->err()) {
           &Apache::lonnet::logthis("error ".$dbh->errstr().
                                    " occured executing \n".
                                    $request);
       }
       return;
   }
   
   ##########################################################
   ##########################################################
   
   =pod
   
   =item &limit_by_start_end_times
   
   Build SQL WHERE condition which limits the data collected by the start
   and end times provided
   
   Inputs: $starttime, $endtime, $table
   
   Returns: $time_limits
   
   =cut
   
   ##########################################################
   ##########################################################
   sub limit_by_start_end_time {
       my ($starttime,$endtime,$table) = @_;
       my $time_requirements = undef;
       if (defined($starttime)) {
           $time_requirements .= $table.".timestamp>='".$starttime."'";
           if (defined($endtime)) {
               $time_requirements .= " AND ".$table.".timestamp<='".$endtime."'";
           }
       } elsif (defined($endtime)) {
           $time_requirements .= $table.".timestamp<='".$endtime."'";
       }
       return $time_requirements;
   }
   
   ##########################################################
   ##########################################################
   
   =pod
   
   =item &limit_by_section_and_status
   
   Build SQL WHERE condition which limits the data collected by section and
   student status.
   
   Inputs: $Sections (array ref)
       $enrollment (string: 'any', 'expired', 'active')
       $tablename The name of the table that holds the student data
   
   Returns: $student_requirements,$enrollment_requirements
   
   =cut
   
   ##########################################################
   ##########################################################
   sub limit_by_section_and_status {
       my ($Sections,$enrollment,$tablename) = @_;
       my $student_requirements = undef;
       if ( (defined($Sections) && $Sections->[0] ne 'all')) {
           $student_requirements = '('.
               join(' OR ', map { $tablename.".section='".$_."'" } @$Sections
                    ).')';
       }
       #
       my $enrollment_requirements=undef;
       if (defined($enrollment) && $enrollment ne 'Any') {
           $enrollment_requirements = $tablename.".status='".$enrollment."'";
       }
       return ($student_requirements,$enrollment_requirements);
   }
   
   ######################################################
   ######################################################
   
   =pod
   
   =item rank_students_by_scores_on_resources
   
   Inputs: 
       $resources: array ref of hash ref.  Each hash ref needs key 'symb'.
       $Sections: array ref of sections to include,
       $enrollment: string,
       $courseid (may be omitted)
   
   Returns; An array of arrays.  The sub arrays contain a student name and
   their score on the resources.
   
   =cut
   
   ######################################################
   ######################################################
   sub RNK_student { return 0; };
   sub RNK_score   { return 1; };
   
   sub rank_students_by_scores_on_resources {
       my ($resources,$Sections,$enrollment,$courseid,$starttime,$endtime) = @_;
       return if (! defined($resources) || ! ref($resources) eq 'ARRAY');
       if (! defined($courseid)) {
           $courseid = $ENV{'request.course.id'};
       }
       #
       &setup_table_names($courseid);
       my $dbh = &Apache::lonmysql::get_dbh();
       my ($section_limits,$enrollment_limits)=
           &limit_by_section_and_status($Sections,$enrollment,'b');
       my $symb_limits = '('.join(' OR ',map {'a.symb_id='.&get_symb_id($_);
                                          } @$resources
                                  ).')';
       my $time_limits = &limit_by_start_end_time($starttime,$endtime,'a');
       my $request = 'SELECT b.student,SUM(a.awarded*w.weight) AS score FROM '.
           $performance_table.' AS a '.
           'NATURAL LEFT JOIN '.$weight_table.' AS w '.
           'LEFT JOIN '.$student_table.' AS b ON a.student_id=b.student_id '.
           'WHERE ';
       if (defined($section_limits)) {
           $request .= $section_limits.' AND ';
       }
       if (defined($enrollment_limits)) {
           $request .= $enrollment_limits.' AND ';
       }
       if (defined($time_limits)) {
           $request .= $time_limits.' AND ';
       }
       if ($symb_limits ne '()') {
           $request .= $symb_limits.' AND ';
       }
       $request =~ s/( AND )$//;   # Remove extra conjunction
       $request =~ s/( WHERE )$//; # In case there were no limits placed on it
       $request .= ' GROUP BY a.student_id ORDER BY score';
       #&Apache::lonnet::logthis('request = '.$/.$request);
       my $sth = $dbh->prepare($request);
       $sth->execute();
       my $rows = $sth->fetchall_arrayref();
       return ($rows);
   }
   
   ########################################################
   ########################################################
   
   =pod
   
   =item &get_sum_of_scores
   
   Inputs: $resource (hash ref, needs {'symb'} key),
   $part, (the part id),
   $students (array ref, contents of array are scalars holding 'sname:sdom'),
   $courseid
   
   Returns: the sum of the score on the problem part over the students and the
      maximum possible value for the sum (taken from the weight table).
   
   =cut
   
   ########################################################
   ########################################################
   sub get_sum_of_scores {
       my ($resource,$part,$students,$courseid,$starttime,$endtime) = @_;
       if (! defined($courseid)) {
           $courseid = $ENV{'request.course.id'};
       }
       #
       &setup_table_names($courseid);
       my $dbh = &Apache::lonmysql::get_dbh();
       my $time_limits = &limit_by_start_end_time($starttime,$endtime,'a');
       my $request = 'SELECT SUM(a.awarded*w.weight),SUM(w.weight) FROM '.
           $performance_table.' AS a '.
           'NATURAL LEFT JOIN '.$weight_table.' AS w ';
       $request .= 'WHERE a.symb_id='.&get_symb_id($resource->{'symb'}).
           ' AND a.part_id='.&get_part_id($part);
       if (defined($time_limits)) {
           $request .= ' AND '.$time_limits;
       }
       if (defined($students)) {
           $request .= ' AND ('.
               join(' OR ',map {'a.student_id='.&get_student_id(split(':',$_));
                            } @$students).
                                ')';
       }
       my $sth = $dbh->prepare($request);
       $sth->execute();
       my $rows = $sth->fetchrow_arrayref();
       if ($dbh->err) {
           &Apache::lonnet::logthis('error = '.$dbh->errstr());
           return (undef,undef);
       }
       return ($rows->[0],$rows->[1]);
   }
   
   ########################################################
   ########################################################
   
   =pod
   
   =item &score_stats
   
   Inputs: $Sections, $enrollment, $symbs, $starttime,
           $endtime, $courseid
   
   $Sections, $enrollment, $starttime, $endtime, and $courseid are the same as 
   elsewhere in this module.  
   $symbs is an array ref of symbs
   
   Returns: minimum, maximum, mean, s.d., number of students, and maximum
     possible of student scores on the given resources
   
   =cut
   
   ########################################################
   ########################################################
   sub score_stats {
       my ($Sections,$enrollment,$symbs,$starttime,$endtime,$courseid)=@_;
       if (! defined($courseid)) {
           $courseid = $ENV{'request.course.id'};
       }
       #
       &setup_table_names($courseid);
       my $dbh = &Apache::lonmysql::get_dbh();
       #
       my ($section_limits,$enrollment_limits)=
           &limit_by_section_and_status($Sections,$enrollment,'b');
       my $time_limits = &limit_by_start_end_time($starttime,$endtime,'a');
       my @Symbids = map { &get_symb_id($_); } @{$symbs};
       #
       my $stats_table = $courseid.'_problem_stats';
       my $symb_restriction = join(' OR ',map {'a.symb_id='.$_;} @Symbids);
       my $request = 'DROP TABLE '.$stats_table;
       $dbh->do($request);
       $request = 
           'CREATE TEMPORARY TABLE '.$stats_table.' '.
           'SELECT a.student_id,'.
           'SUM(a.awarded*w.weight) AS score FROM '.
           $performance_table.' AS a '.
           'NATURAL LEFT JOIN '.$weight_table.' AS w '.
           'LEFT JOIN '.$student_table.' AS b ON a.student_id=b.student_id '.
           'WHERE ('.$symb_restriction.')';
       if ($time_limits) {
           $request .= ' AND '.$time_limits;
       }
       if ($section_limits) {
           $request .= ' AND '.$section_limits;
       }
       if ($enrollment_limits) {
           $request .= ' AND '.$enrollment_limits;
       }
       $request .= ' GROUP BY a.student_id';
   #    &Apache::lonnet::logthis('request = '.$/.$request);
       my $sth = $dbh->prepare($request);
       $sth->execute();
       $request = 
           'SELECT AVG(score),STD(score),MAX(score),MIN(score),COUNT(score) '.
           'FROM '.$stats_table;
       my ($ave,$std,$max,$min,$count) = &execute_SQL_request($dbh,$request);
   #    &Apache::lonnet::logthis('request = '.$/.$request);
       
       $request = 'SELECT SUM(weight) FROM '.$weight_table.
           ' WHERE ('.$symb_restriction.')';
       my ($max_possible) = &execute_SQL_request($dbh,$request);
       # &Apache::lonnet::logthis('request = '.$/.$request);
       return($min,$max,$ave,$std,$count,$max_possible);
   }
   
   
   ########################################################
   ########################################################
   
   =pod
   
   =item &count_stats
   
   Inputs: $Sections, $enrollment, $symbs, $starttime,
           $endtime, $courseid
   
   $Sections, $enrollment, $starttime, $endtime, and $courseid are the same as 
   elsewhere in this module.  
   $symbs is an array ref of symbs
   
   Returns: minimum, maximum, mean, s.d., and number of students
     of the number of items correct on the given resources
   
   =cut
   
   ########################################################
   ########################################################
   sub count_stats {
       my ($Sections,$enrollment,$symbs,$starttime,$endtime,$courseid)=@_;
       if (! defined($courseid)) {
           $courseid = $ENV{'request.course.id'};
       }
       #
       &setup_table_names($courseid);
       my $dbh = &Apache::lonmysql::get_dbh();
       #
       my ($section_limits,$enrollment_limits)=
           &limit_by_section_and_status($Sections,$enrollment,'b');
       my $time_limits = &limit_by_start_end_time($starttime,$endtime,'a');
       my @Symbids = map { &get_symb_id($_); } @{$symbs};
       #
       my $stats_table = $courseid.'_problem_stats';
       my $symb_restriction = join(' OR ',map {'a.symb_id='.$_;} @Symbids);
       my $request = 'DROP TABLE '.$stats_table;
       $dbh->do($request);
       $request = 
           'CREATE TEMPORARY TABLE '.$stats_table.' '.
           'SELECT a.student_id,'.
           'COUNT(a.award) AS count FROM '.
           $performance_table.' AS a '.
           'LEFT JOIN '.$student_table.' AS b ON a.student_id=b.student_id '.
           'WHERE ('.$symb_restriction.')'.
           " AND a.award!='INCORRECT_ATTEMPTED'";
       if ($time_limits) {
           $request .= ' AND '.$time_limits;
       }
       if ($section_limits) {
           $request .= ' AND '.$section_limits;
       }
       if ($enrollment_limits) {
           $request .= ' AND '.$enrollment_limits;
       }
       $request .= ' GROUP BY a.student_id';
   #    &Apache::lonnet::logthis('request = '.$/.$request);
       my $sth = $dbh->prepare($request);
       $sth->execute();
       $request = 
           'SELECT AVG(count),STD(count),MAX(count),MIN(count),COUNT(count) '.
           'FROM '.$stats_table;
       my ($ave,$std,$max,$min,$count) = &execute_SQL_request($dbh,$request);
   #    &Apache::lonnet::logthis('request = '.$/.$request);
       return($min,$max,$ave,$std,$count);
   }
   
   ######################################################
   ######################################################
   
   =pod
   
   =item get_student_data
   
   =cut
   
   ######################################################
   ######################################################
 sub get_student_data {  sub get_student_data {
     my ($students,$courseid) = @_;      my ($students,$courseid) = @_;
     $courseid = $ENV{'request.course.id'} if (! defined($courseid));      $courseid = $ENV{'request.course.id'} if (! defined($courseid));
Line 2087  sub RD_tries         { return 5; } Line 2522  sub RD_tries         { return 5; }
 sub RD_sname         { return 6; }  sub RD_sname         { return 6; }
   
 sub get_response_data {  sub get_response_data {
     my ($students,$symb,$response,$courseid) = @_;      my ($Sections,$enrollment,$symb,$response,$courseid) = @_;
     return undef if (! defined($symb) ||       return undef if (! defined($symb) || 
                ! defined($response));                 ! defined($response));
     $courseid = $ENV{'request.course.id'} if (! defined($courseid));      $courseid = $ENV{'request.course.id'} if (! defined($courseid));
Line 2098  sub get_response_data { Line 2533  sub get_response_data {
     #      #
     my $dbh = &Apache::lonmysql::get_dbh();      my $dbh = &Apache::lonmysql::get_dbh();
     return undef if (! defined($dbh));      return undef if (! defined($dbh));
       #
       my ($student_requirements,$enrollment_requirements) = 
           &limit_by_section_and_status($Sections,$enrollment,'d');
     my $request = 'SELECT '.      my $request = 'SELECT '.
         'a.student_id, a.awarddetail, a.response_specific_value, '.          'a.student_id, a.awarddetail, a.response_specific_value, '.
         'a.submission, b.timestamp, c.tries, d.student '.          'a.submission, b.timestamp, c.tries, d.student '.
Line 2112  sub get_response_data { Line 2550  sub get_response_data {
         'ON a.student_id=d.student_id '.          'ON a.student_id=d.student_id '.
         'WHERE '.          'WHERE '.
         'a.symb_id='.$symb_id.' AND a.response_id='.$response_id;          'a.symb_id='.$symb_id.' AND a.response_id='.$response_id;
     if (defined($students)) {      if (defined($student_requirements) || defined($enrollment_requirements)) {
         $request .= ' AND ('.          $request .= ' AND ';
             join(' OR ', map {'a.student_id='.          if (defined($student_requirements)) {
                                   &get_student_id($_->{'username'},              $request .= $student_requirements.' AND ';
                                                   $_->{'domain'})          }
                               } @$students          if (defined($enrollment_requirements)) {
                  ).')';              $request .= $enrollment_requirements.' AND ';
           }
           $request =~ s/( AND )$//;
     }      }
     $request .= ' ORDER BY b.timestamp';      $request .= ' ORDER BY b.timestamp';
 #    &Apache::lonnet::logthis("request =\n".$request);  #    &Apache::lonnet::logthis("request =\n".$request);
Line 2177  sub get_response_data_by_student { Line 2617  sub get_response_data_by_student {
         'WHERE '.          'WHERE '.
         'a.symb_id='.$symb_id.' AND a.response_id='.$response_id.          'a.symb_id='.$symb_id.' AND a.response_id='.$response_id.
         ' AND a.student_id='.$student_id.' ORDER BY b.timestamp';          ' AND a.student_id='.$student_id.' ORDER BY b.timestamp';
     # &Apache::lonnet::logthis("request =\n".$request);  #    &Apache::lonnet::logthis("request =\n".$request);
     my $sth = $dbh->prepare($request);      my $sth = $dbh->prepare($request);
     $sth->execute();      $sth->execute();
     if ($dbh->err) {      if ($dbh->err) {
Line 2386  sub setup_table_names { Line 2826  sub setup_table_names {
     $fulldump_part_table      = $base_id.'_'.'partdata';      $fulldump_part_table      = $base_id.'_'.'partdata';
     $fulldump_response_table  = $base_id.'_'.'responsedata';      $fulldump_response_table  = $base_id.'_'.'responsedata';
     $fulldump_timestamp_table = $base_id.'_'.'timestampdata';      $fulldump_timestamp_table = $base_id.'_'.'timestampdata';
       $weight_table             = $base_id.'_'.'weight';
     #      #
     @Tables = (      @Tables = (
                $symb_table,                 $symb_table,
Line 2396  sub setup_table_names { Line 2837  sub setup_table_names {
                $fulldump_part_table,                 $fulldump_part_table,
                $fulldump_response_table,                 $fulldump_response_table,
                $fulldump_timestamp_table,                 $fulldump_timestamp_table,
                  $weight_table,
                );                 );
     return;      return;
 }  }

Removed from v.1.124  
changed lines
  Added in v.1.134


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>