0

我正在编写另一个用于练习的博客引擎,使用 SQLite 和 Perl Dancer 框架。

表格是这样的:

CREATE TABLE posts (
    p_id INTEGER PRIMARY KEY,
    p_url VARCHAR(255),
    p_title VARCHAR(255),
    p_text TEXT,
    p_date DATETIME DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE tags (
    t_id INTEGER PRIMARY KEY,
    t_tag VARCHAR(255),
    t_url VARCHAR(255)
);

CREATE TABLE tags_posts_junction (
    tp_tag INTEGER NOT NULL,
    tp_post INTEGER NOT NULL,
    FOREIGN KEY(tp_tag) REFERENCES tags.t_id,
    FOREIGN KEY(tp_post) REFERENCES tags.p_id
);

所有像 Wordpress(或 stackoverflow)这样的大人物都可以在主页上显示标签,在每个问题之后,我也想实现它。问题是我该怎么做。

到目前为止,帖子都存储在数据库中,当我需要渲染一个显示最新 20 篇帖子的页面时,我将哈希引用 ( fetchall_hashreffrom DBI) 传递给模板。那么如何在那里添加标签呢?当然我可以做类似的事情

my $dbh = database->prepare('SELECT * FROM posts ORDER BY p_date DESC 
                    LIMIT 20 OFFSET 0');
$dbh->execute;
my $posts = $dbh->fetchall_hashref('p_date');
foreach my $key (keys $post) {
    my $dbh = database->prepare('SELECT * FROM tags WHERE t_id IN (
                    SELECT tp_tag FROM tags_posts_junction WHERE tp_post = ?)');
    $dbh->execute($post->{"$key"}->{"p_id"});
    my $tags = $dbh->fetchall_hashref(t_id);
    $post->{"$key"}->{"$tag_hash"} = $tags;
};

但这很丑陋,每页还有 20 个查询,不是太多了吗?我认为应该有更好的方法。

所以问题是我如何以最少冗余的方式获得 20 个帖子的标签?

4

2 回答 2

1

我认为您之前可以结合您的第一个/外部查询

my $posts = $dbh->fetchall_hashref('p_date');

使用您的内部查询,然后您将访问数据库一次而不是 20 次。

您还可以通过使用 DBIx::Simple - https://metacpan.org/module/DBIx::Simple来简化您的代码。

把它放在一起会给出类似的东西:

my $sql =   'SELECT t.*, p.*
             FROM tags t 
             JOIN tags_posts_junction tpj ON t.t_tag = tpj.t_tag
             JOIN posts p ON p.p_id = tpj.tp_post
             WHERE tpj.tp_post IN (
                SELECT p_id FROM posts ORDER BY p_date DESC 
                LIMIT 20 OFFSET 0
              )';
my $db = DBIx::Simple->connect($dbh);
my $posts = $db->query($sql)->hashes;
于 2012-07-15T09:54:32.940 回答
0

将所有 p_ids 收集到一个数组中,并使用 IN 而不是 = 构造您的查询,类似这样,假设 @pids 是您的数组:

my $dbh = database->prepare('SELECT * FROM tags WHERE t_id IN (
                    SELECT tp_tag FROM tags_posts_junction WHERE tp_post IN (' .
                    join(', ', ('?')x@pids).') )');
$dbh->execute(@pids);

尽管您真的应该寻找 JOIN 来替换您的子查询。

于 2012-07-15T12:21:50.847 回答