2012-07-15 38 views
0

我正在编写另一个实践的博客引擎,使用SQLite和Perl Dancer框架。RYO博客引擎 - 显示几个职位的标签

的表是这样的:

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的(或计算器)的大家伙可以显示标签右边的主页上,回答每个问题之后,我想实现这一点。问题是我该怎么做。

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

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

收集所有的p_ids到一个数组并使用的,而不是=,像这样构造你的查询,假设@pids是你的数组:

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

虽然你真的应该看JOIN来替换你的子查询。

+0

该查询会给我一个页面上存在的所有标签的数组,不是吗?我担心加入会给我carthesian产品,我不想要。 – user1526661 2012-07-15 15:38:28

+0

的确,JOIN工作得很好,你的代码示例非常有用。非常感谢,这个问题的查询就像'SELECT p_date,t_url,t_name FROM posts JOIN tags_posts_junction ON p_id = tp_post JOIN tags ON t_id = tp_tag WHERE p_id IN(1,2,3,4);' – user1526661 2012-07-16 10:38:23

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; 
+0

添加了查询,结合考试将会很棒,就像DBIx一样:简单 - 不确定是否有相应的Dancer插件,无论如何,我认为我应该保留原始SQL,因为它更像是一个学习项目。其他。感谢您的回答。 – user1526661 2012-07-15 10:18:26

+0

我也认为我可以查询'tags'和'tags_post_junction'表并处理应用程序中的输出。这是三个查询,但仍然不是20. – user1526661 2012-07-15 11:16:39

+0

您不应该需要DBIx :: Simple的插件,只需将现有的$ dbh传递给DBIx-Simple连接方法即可。 – MkV 2012-07-15 12:11:18