2012-07-15 34 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