使用多个表的复杂 JOIN
Complicated JOIN using multiple tables
例如
我有几个配置文件table,比如
music_profile
sports_profile
art_profile
所有这些 table 都有匹配的名称,并且它们都有一个 title
列。
第二个 table 包含每个给定配置文件 table 行的替代标题。
他们的专栏基本上是:
id, parent_id, parent_table, alt_title_001, alt_title_002, alt_title_003, alt_title_004, status, created, updated.
我要
SELECT multiple column values
FROM music_profile, sports_profile, art_profile
WHERE title, alt_title_001, alt_title_002, alt_title_003, alt_title_004 are like a value
我目前可以使用 WHERE title LIKE
和 UNION
来 select 列,但我不知道如何将 alternate_titles
table 组合到 SELECT 语句。
我在下面提供了我当前的代码。 alternate_titles
的 table 这里没有实现。
我不一定想要这个问题的编码解决方案;我只是想要一个提示,让我继续前进。
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.'
},
];
经过一阵头疼和激烈的谷歌搜索后,我想出了一个解决方案。
我的问题最基本的解决方案是:
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);
}
这不能立即在我的代码示例中实现,但这是一个很好的起点。
不知道这样有没有效率,如果谁有更好的解决方案,我很乐意看到。
例如
我有几个配置文件table,比如
music_profile
sports_profile
art_profile
所有这些 table 都有匹配的名称,并且它们都有一个 title
列。
第二个 table 包含每个给定配置文件 table 行的替代标题。
他们的专栏基本上是:
id, parent_id, parent_table, alt_title_001, alt_title_002, alt_title_003, alt_title_004, status, created, updated.
我要
SELECT multiple column values
FROM music_profile, sports_profile, art_profile
WHERE title, alt_title_001, alt_title_002, alt_title_003, alt_title_004 are like a value
我目前可以使用 WHERE title LIKE
和 UNION
来 select 列,但我不知道如何将 alternate_titles
table 组合到 SELECT 语句。
我在下面提供了我当前的代码。 alternate_titles
的 table 这里没有实现。
我不一定想要这个问题的编码解决方案;我只是想要一个提示,让我继续前进。
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.'
},
];
经过一阵头疼和激烈的谷歌搜索后,我想出了一个解决方案。
我的问题最基本的解决方案是:
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);
}
这不能立即在我的代码示例中实现,但这是一个很好的起点。
不知道这样有没有效率,如果谁有更好的解决方案,我很乐意看到。