2017-04-06 103 views
4

例如複雜的JOIN使用多個表

我有幾個配置文件表,如

  • music_profile
  • sports_profile
  • art_profile

所有這些表都匹配名稱,他們都有一個title列。

第二個表包含每個給定配置文件錶行的備選標題。

它們的列基本上是:

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

我想

選擇多個列的值
FROM music_profile,sports_profile,art_profile
WHERE標題,alt_title_001,alt_title_002,alt_title_003,alt_title_004 就像一個值

我目前可以使用WHERE title LIKEUNION選擇列,但我不知道如何在SELECT語句中組合alternate_titles表。

我在下面提供了我的當前代碼。 alternate_titles的表尚未在此實施。

我不一定需要針對此問題的編碼解決方案;我只想提示一下我的路。

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; 
} 

該代碼的實際應用如下。

這些變量用作示例。這些數據通常通過表格提供。

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

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

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

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

自卸車結果

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

我編輯了你的問題。請檢查我改變了什麼,並確保它仍然說明你的意思。這是非常好的和清晰的Perl代碼:非常好。我唯一會改變的是'$$ opts {'status'}'可以更好地寫成'$ opts - > {status}'。 – Borodin

+0

謝謝你的幫助,我擔心我過於複雜了我的話。 :) – user3049982

+0

你可以發佈一些示例數據? –

回答

0

有點頭痛和一些激烈google搜索我能拿出一個解決方案之後。

最基本的解決我的問題是:

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); 
} 

這不是我的代碼示例立即實現的,但是這可以作爲一個很好的起點。

我不知道這是否有效,如果有人有更好的解決方案,我很樂意看到它。