我有一个代表书店的数据库。有一个表格包含书籍所属的类别。有些类别只是使用包含类别 - 项目关系的另一个表格来定义。但是也有一些类别可以通过编程方式定义 - 可以使用查询定义特定作者的类别(SELECT item_id FROM items WHERE author =“John Smith”)。所以我的类别表有一个“查询”列;如果它不是null,我用它来获取类别中的项目,否则我使用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不能在表达式中使用,它只是一个顶级语句。建议?
答案 0 :(得分:2)
当您想要按出版商列出图书时会发生什么?国家?语言?您必须将它们全部放入单个“category_items”表中。您将如何选择要执行的动态查询?查询中的查询方法不起作用。
我认为你的“类别”概念过于宽泛,导致SQL过于复杂。我会将“类别”替换为仅代表“类型”(用于书籍)。类型在自己的表中定义,item_genres将它们连接到items表。逐个作者和逐个书籍应该只是在应用程序级别的单独查询,而不是尝试在数据库/ SQL级别使用相同(种类)查询。 (如果你有音乐和书籍,它们可能不应该都存储在一个“项目”表中,因为它们是不同的概念......有不同的类型,作者与艺术家等等。)
我知道这并没有以你想要的方式解决你的问题,但我认为你不会那样做更快乐。
答案 1 :(得分: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");
}
}