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;
};

しかし、それは醜く、1 ページあたり 20 個のクエリが増えます。多すぎませんか? もっと良い方法があるべきだと思います。

問題は、20 件の投稿のタグを冗長性が最も少ない方法で取得するにはどうすればよいかということです。

4

2 に答える 2

1

私はあなたが前にあなたの最初の/外側のクエリを組み合わせることができると思います

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

内部クエリを使用すると、データベースに20回ではなく1回ヒットします。

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 に答える