2017-04-06 6 views
4

Zum BeispielKomplizierte JOIN mit mehreren Tabellen

ich mehrere Profiltabellen haben, wie

  • music_profile
  • sports_profile
  • art_profile

Alle diese Tabellen haben passende Namen und alle haben eine title Spalte.

Eine zweite Tabelle enthält alternative Titel für jede Zeile einer Profiltabelle.

Ihre Säulen sind im Wesentlichen:

id, parent_id, parent_table, alt_title_001, alt_title_002, alt_title_003, alt_title_004, status, created, updated. 

Ich möchte

mehrere Spaltenwerte
FROM music_profile SELECT, sports_profile, art_profile
WHERE Titel, alt_title_001, alt_title_002, alt_title_003, alt_title_004 sind wie ein Wert

Ich kann derzeit Spalten mit WHERE title LIKE und UNION auswählen, aber ich habe keine Ahnung, wie die alternate_titles Tabelle in der SELECT-Anweisung zu kombinieren.

Ich habe meinen aktuellen Code unten zur Verfügung gestellt. Die Tabelle für alternate_titles wurde hier nicht implementiert.

Ich möchte nicht unbedingt eine codierte Lösung für dieses Problem; Ich möchte nur einen Hinweis, um mich auf den Weg zu bringen.

sub AdvancedSearchFormResults { 
    my $self = shift; 
    my $opts = ref $_[0] eq 'HASH' ? shift : {@_}; 

    my $mode = shift; 
    my $order = shift; 
    my $limit = shift; 

    my @array; 
    my $where; 
    my $mode = $$opts{mode}; 

    my $left_join_clause; 
    my (@where_stmt, @where_vals, @join); 

    if (defined $$opts{platform}) { 
     $where = $$opts{platform}; 
    } 
    if ($$opts{'title_like'}) { 
     push(@where_stmt, "title like ?"); 
     push(@where_vals, '%'.$$opts{'title_like'}.'%'); 
    } 
    if ($$opts{'publisher'}) { 
     push(@where_stmt, "publisher = ?"); 
     push(@where_vals, $$opts{'publisher'}); 
    } 
    if ($$opts{'status'}) { 
     push(@where_stmt, "status = ?"); 
     push(@where_vals, $$opts{'status'}); 
    } 

    my $left_join_clause = scalar @join ? join("\n", @join) : ""; 

    my $where_clause = @where_stmt ? "WHERE ".join(" AND ", @where_stmt) : ""; 
    my $order_clause = length($order) ? "ORDER BY $order"     : ""; 
    my $limit_clause = length($limit) ? "LIMIT $limit"      : ""; 

    my $select_stmt; 

    if ($mode eq 'BUILD') { 
     $select_stmt = "SELECT 
          '$where' AS event, 
          ident, 
          title, 
          publisher 
         FROM $where 
          $left_join_clause 
          $where_clause 
          $order_clause 
          $limit_clause"; 

     my $sth = $schema->prepare($select_stmt) or die $schema->errstr; 
     $sth->execute(@where_vals) or die $sth->errstr; 

     while (my $row = $sth->fetchrow_hashref()) { 
      push(@array, $row); 
     } 

    } 
    elsif ($mode eq 'UNION') { 

     my @select_stmts; 
     my @platforms  = $self->ProfileTables(); 
     my $total_platforms = -1; 

     foreach my $table (@platforms) { 
      $total_platforms++; 
      my $stmt = "(SELECT '$table' AS event,ident,title,publisher,status FROM $table $where_clause)"; 
      push(@select_stmts, $stmt); 
     } 

     my $select_stmt .= "$select_stmts[0] UNION ALL"; 
     $select_stmt .= join(' UNION ALL ', @select_stmts[ 1 .. 28 ]); 

     my @new_vals = (@where_vals, (@where_vals) x $total_platforms); 

     my $sth = $schema->prepare($select_stmt) or die $schema->errstr; 
     $sth->execute(@new_vals) or die $sth->errstr; 

     while (my $row = $sth->fetchrow_hashref()) { 
      push(@array, $row); 
     } 
    } 
    elsif ($mode eq 'REFRESH') { 
     print ' 
     <div class="alert alert-danger" role="alert"> 
      <strong>Please fill out at least one field.</strong> 
     </div>'; 
    } 

    return @array; 
} 

Eine praktische Anwendung des Codes ist unten.

Diese Variablen werden als Beispiel verwendet. Diese Daten würden normalerweise über ein Formular bereitgestellt werden.

my $title  = 'Mario'; 
my $publisher = ''; 

my %params = (
    title_like => $title, 
    publisher => $publisher, 
    status  => 'a', 
); 

my @results = $results->AdvancedSearchFormResults(\%params); 

print Data::Dumper::Dumper(\@results); 

Dumper Ergebnisse

$VAR1 = [ 
      { 
      'ident' => '2109', 
      'title' => 'Mario Bros.', 
      'publisher' => 'Atari' 
      }, 
      { 
      'ident' => '30', 
      'title' => 'Mario Bros.', 
      'publisher' => 'Atari' 
      }, 
      { 
      'publisher' => 'Atari', 
      'ident' => '43', 
      'title' => 'Mario Bros.' 
      }, 
    ]; 
+3

Ich habe Ihre Frage bearbeitet. Bitte überprüfen Sie, was ich geändert habe und stellen Sie sicher, dass es immer noch sagt, was Sie gemeint haben. Das ist ungewöhnlich schöner und klarer Perl-Code: sehr gut gemacht. Das einzige, was ich ändern würde ist, dass Dinge wie '$$ opts {'status'}' besser als '$ opts -> {status} geschrieben werden. – Borodin

+0

Danke für Ihre Hilfe, ich hatte Angst, dass ich meine Worte übermäßig verkompliziert habe. :) – user3049982

+0

Könnten Sie einige Beispieldaten posten? –

Antwort

0

Nach einem wenig Kopfschmerzen und einig intensiven googeln ich in der Lage war, mit einer Lösung zu kommen.

Die einfachste Lösung für mein Problem ist:

my @profiles = ('art', 'music', 'sports'); 
my @results; 
my $blah; 
my $sql; 

foreach my $profile (@profiles) { 
    $sql = "SELECT 
       $profile.ident, 
       $profile.title, 
       $profile.status 
      FROM $profile 
      LEFT JOIN alternate_titles ON $profile.ident = alternate_titles.parent_ident 
      WHERE title like '%$blah%' 
       OR 
       CONCAT_WS(' ',alternate_titles.alt_title_001,alternate_titles.alt_title_002,alternate_titles.alt_title_003,alternate_titles.alt_title_004 
       AND alternate_titles.parent_table = '$profile'"; 
} 
my $sth = $schema->prepare($sql) or die $schema->errstr; 
$sth->execute() or die $sth->errstr; 

while (my $data = $sth->fetchrow_hashref()) { 
    push(@results, $data); 
} 

Diese in meinem Code Beispiel nicht sofort umsetzbaren, aber das funktioniert wie ein guter Ausgangspunkt.

Ich weiß nicht, dass dies effizient ist, wenn jemand eine bessere Lösung hat, würde ich es gerne sehen.

Verwandte Themen