0

我有一个产品、类别和“productsInCategories”的数据库,看起来像:


用户

id█  name  ▌
▀▀█▀▀▀▀▀▀▀▀▌
1 █  john  ▌
69█  jane  ▌

产品

id█  name  █ cost █description▌
▀▀█▀▀▀▀▀▀▀▀█▀▀▀▀▀▀█▀▀▀▀▀▀▀▀▀▀▀▌
21█snickers█  23  █ foo       ▌
34█  mars  █  20  █ bar       ▌
37█  daim  █  21  █ oofrab    ▌
79█ banana █  8   █ foobar    ▌
80█  apple █  10  █ barfoo    ▌

类别

id█  userId █   name  ▌
▀▀█▀▀▀▀▀▀▀▀▀█▀▀▀▀▀▀▀▀▀▌
10█    69   █chocolate▌
55█    69   █favorites▌
20█    1    █ fruit   ▌

产品分类

categoryId█productId▌
▀▀▀▀▀▀▀▀▀▀█▀▀▀▀▀▀▀▀▀▌
    10    █   21    ▌
    10    █   34    ▌
    20    █   79    ▌
    20    █   80    ▌
    55    █   21    ▌
    55    █   37    ▌

这产生了一些可以被视为:

Users
   john
      fruit
         banana
         apple
   jane
      chocolate
         snickers
         mars
         daim
      favorites
         snickers
         daim

当我想获取某个类别的所有产品时,我会执行以下操作:

SELECT *
FROM Products
        INNER JOIN ProductsInCategories
        ON Products.Id=ProductsInCategories.product
        WHERE category=@0
,@0=categoryId

这一切都很好,插入或删除产品非常简单。但是我现在有一个问题,我无法解决问题。

删除类别。我将如何继续这样做?我已经为此工作了几个小时,但似乎无法使其正常工作。如果用户删除一个类别,我希望仅存在于该类别中的所有产品连同关联的 productInCategories 记录一起被删除。如果说用户“简”删除了她的类别“巧克力”,那么我想删除产品“火星”而不是“士力架”或“火星”,因为它们也存在于“收藏夹”类别中

4

2 回答 2

5

除非您在模式中设置级联删除,否则您需要使用 3 个删除语句,每个表一个。

-- Delete category 10 from Categories table.
DELETE FROM Categories WHERE Id=10;

-- Delete category 10 from ProductsInCategories table.
DELETE FROM ProductsInCategories WHERE CategoryId=10;

-- Delete all products that are no longer in a category    
DELETE Products
FROM Products
LEFT JOIN ProductsInCategories
  ON ProductId=Products.Id
WHERE ProductId IS NULL;

一个用于测试的 SQLfiddle

于 2013-05-12T09:02:54.240 回答
1

一些pseodocode让你去:

 Delete from ProductsIncategories where category = X

 Delete from products where productID in (
    select productID from
        products left outer join productsincategories 
        on products.productID = productsincategories.productID
    where 
        productsincategories.categoryid is null
 )

 delete from categories where category = x
  1. 如果您首先删除类别中的产品,因为它取决于其他表,而没有任何东西取决于它。

  2. 现在在任何类别中查找产品 - 这些是仅在要删除的类别中的产品 - 这是通过从产品到 productsincategories 的左外连接来完成的 - 这给出了产品的所有行,如果它们没有来自产品的匹配记录,则为 null在类别中

  3. 删除类别本身,因为现在没有任何东西链接到它。

作为旁注,请考虑不要仅删除此类别中的产品,而是提供这些产品的报告供人们查看和清理。在我看来,否则工作可能会经常丢失。也许至少让他们有机会在您删除它们之前确认

另请注意,中间声明将删除不在一个类别中的每个产品.. 关于此类问题有两种思想流派

  1. 任何不属于某个类别的产品都是错误的,因此请尽可能将它们全部清理干净
  2. 一个产品可能没有类别的原因有很多,这对我没用!

如果您只想删除仅属于此类别的产品并且一揽子删除并不好,那么这样的事情可能会有所帮助:

select productID form
from
    products as p
    inner join productsincategories as pic
        on PIC.productid = p.productid
    inner join (
        select distinct productID from productsincategories 
        where categoryid = X
    ) as t
        on t.productid = p.productid
 group by 
    productid
 having 
    count(*) = 1

这是使用 Joachim Isaksson 的小提琴进行的选择(现在为您的答案 +1 Joachim)

http://sqlfiddle.com/#!3/5a744/22

左外连接 - 快速笔记

table a
id
1
2


table b
aID   value
1     x
1     y


a left outer join b (select * from a left outer join b on a.id = b.aID)
id  aID value
1   1   x
1   1   y
2   NULLNULL

b left outer join a (select * from b left outer join a on a.id = b.aID)
aID value id
1   x     1
1   y     1

左外连接为您提供左侧表中的所有内容并匹配右侧表中的所有内容。如果左表中有一行而不是右表,则右侧表的所有列都为 NULL。希望这会有所帮助,但值得进行谷歌搜索和实验以适应。

当您想说查看所有商品的销售额但您希望获得商品列表(无论是否有销售)时,它非常有用。或者就像我们在这里使用它来查找一个表中的所有内容而不是另一个表中的所有内容,方法是仅选择“正确”表为空的位置

于 2013-05-12T08:53:52.847 回答