我正在编写另一个用于练习的博客引擎,使用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_hashref
中的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个帖子获取最不冗余的标签?
答案 0 :(得分: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;
答案 1 :(得分: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来替换您的子查询。