7

我有一个代表书店之类的数据库。有一个表包含书籍可以在其中的类别。一些类别是简单地使用另一个包含类别-项目关系的表来定义的。但也有一些类别可以通过编程方式定义——可以使用查询定义特定作者的类别(SELECT item_id FROM items WHERE author = "John Smith")。所以我的类别表有一个“查询”列;如果它不为空,我使用它来获取类别中的项目,否则我使用 category_items 表。

目前,我让应用程序(PHP 代码)做出此决定,但这意味着当我们遍历所有类别时需要进行大量单独的查询。有没有办法将此动态 SQL 合并到连接中?就像是:

SELECT c.category, IF(c.query IS NULL, count(i.items), count(EXECUTE c.query)
FROM categories c
LEFT OUTER JOIN category_items i
ON c.category = i.category

EXECUTE 需要一个准备好的语句,但我需要为每一行准备一个不同的语句。此外,EXECUTE 不能用于表达式,它只是一个顶级语句。建议?

4

2 回答 2

2

当您想按出版商列出书籍时会发生什么?国家?语?您必须将它们全部放入一个“category_items”表中。您将如何选择要执行的动态查询?查询中的查询方法不起作用。

我认为您的“类别”概念过于宽泛,导致 SQL 过于复杂。我将替换“类别”以仅代表“类型”(用于书籍)。流派在它们自己的表中定义,并且 item_genres 将它们连接到 items 表。Books-by-author 和 books-by-genre 应该只是应用程序级别的单独查询,而不是尝试在数据库/SQL 级别使用相同(某种)查询来完成它们。(如果您有音乐和书籍,它们可能不应该全部存储在一个“项目”表中,因为它们是不同的概念......有不同的流派、作者与艺术家等)

我知道这并不能真正以您想要的方式解决您的问题,但我认为您不尝试那样做会更快乐。

于 2012-07-12T00:27:36.910 回答
1

这是我最终在 PHP 客户端中解决这个问题的方法。

我决定只保留 category_items 表中的成员资格,并在提交期间使用动态查询来更新此表。

这是我的脚本中调用的函数,用于在提交或更新期间更新项目的类别。它需要一个用户选择的类别列表(只能从没有动态查询的类别中选择),并使用这个和动态查询来确定项目当前所在的类别与那些类别之间的区别它应该在其中,并根据需要插入/删除以使它们同步。(请注意,我的数据库中的实际表名与我的问题中的不同,我使用了一些通用术语。)

function update_item_categories($dbh, $id, $requested_cats) {
    $data = mysql_check($dbh, mysqli_query($dbh, "select id, query from t_ld_categories where query is not null"), 'getting dynamic categories');
    $clauses = array();
    while ($row = mysqli_fetch_object($data))
        $clauses[] = sprintf('select %d cat_id, (%d in (%s)) should_be_in',
            $row->id, $id, $row->query);
    if (!$requested_cats) $requested_cats[] = -1; // Dummy entry that never matches cat_id
    $requested_cat_string = implode(', ', $requested_cats);
    $clauses[] = "select c.id cat_id, (c.id in ($requested_cat_string)) should_be_in
                  from t_ld_categories c
                  where member_type = 'lessons' and query is null";
    $subquery = implode("\nunion all\n", $clauses);
    $query = "select c.cat_id cat_id, should_be_in, (member_id is not null) is_in
              from ($subquery) c
              left outer join t_ld_cat_members m
              on c.cat_id = m.cat_id
              and m.member_id = $id";
    // printf("<pre>$query</pre>");
    $data = mysql_check($dbh, mysqli_query($dbh, $query), 'getting current category membership');
    $adds = array();
    $deletes = array();
    while ($row = mysqli_fetch_object($data)) {
        if ($row->should_be_in && !$row->is_in) $adds[] = "({$row->cat_id}, $id)";
        elseif (!$row->should_be_in && $row->is_in) $deletes[] = "(cat_id = {$row->cat_id} and member_id = $id)";
    }
    if ($deletes) {
        $delete_string = implode(' or ', $deletes);
        mysql_check($dbh, mysqli_query($dbh, "delete from t_ld_cat_members where $delete_string"), 'deleting old categories');
    }
    if ($adds) {
        $add_string = implode(', ', $adds);
        mysql_check($dbh, mysqli_query($dbh, "insert into t_ld_cat_members (cat_id, member_id) values $add_string"),
            "adding new categories");
    }
}
于 2012-08-14T21:27:06.983 回答