有没有办法在一个查询中回答这个问题?

时间:2011-04-03 05:03:34

标签: mysql sql

我有一个包含3个表的MySQL数据库:

予。 (身份证,姓名,购买)
II。 购买(id,product,date_purchased)
III。 目录(ID,产品,每单位成本)

.purchases持有Purchase.id。也就是说,每次有人购买东西时,订单ID都会记录在Person.purchases中。例如。 Person.purchases存储了1,300,292。

每个购买条目都会记录购买的任何商品的实例。所以,Purchase.id = 300可能是“foo”。

目录包含有关“foo”的说明。

我想知道的是如何回答:“谁买了”foo“?我知道如何分两步回答这个问题:

步骤1: SELECT Purchases.id FROM Purchases INNER JOIN目录WHERE Purchases.product = Catalog.product;

我会将第1步的结果存储在变量 tmp ;

第2步: SELECT Person FROM Person WHERE Person.orders LIKE“% tmp %”;

我在上面使用LIKE因为Person.orders存储了多个Purchase.id。

有没有办法将这两者合并为一个查询?

4 个答案:

答案 0 :(得分:2)

这是一个糟糕的数据库设计,它阻碍了你回答一个相对简单的问题。我的设计表有点像这样:

customers (id, name)
purchases (id, product_id, customer_id, date_purchased)
products (id, product_name, cost_per_unit)

因此,您的查询可以找出'谁买了foo?'是:

SELECT c.id, c.name
FROM products pr 
   LEFT JOIN purchases pu ON (pr.id = pu.product_id)
   INNER JOIN customers c ON (pu.customer_id = c.id)
WHERE product_id = foo 
-- could replace with product_name = 'foo' here, but you should know product_id

这使您的数据库处于某种正常形式(我不记得哪一个),因此您可以利用关系数据库提供的功能。

在此处制作另一个表格,将其称为receipts,并将purchases重命名为line_items可能也很有用。这可确保您可以跟踪在一次购买中购买多件商品的客户等。

答案 1 :(得分:2)

可以使用单个查询来回答问题:

使用EXISTS

SELECT a.name
  FROM PERSON a
 WHERE EXISTS(SELECT NULL
                FROM PURCHASE b 
                JOIN CATALOG c ON c.product = b.product
               WHERE FIND_IN_SET(b.id, a.purchases) > 0
                 AND c.product = 'foo')

使用JOIN:

这需要DISTINCT(或GROUP BY),因为如果某个人/客户多次购买“foo”,则可能存在重复。

SELECT DISTINCT a.name
  FROM PERSON a
  JOIN PURCHASE b ON FIND_IN_SET(b.id, a.purchases) > 0
  JOIN CATALOG c ON c.product = b.product
 WHERE c.product = 'foo'

附录

我同意数据模型差的其他答案 - 在PURCHASE表中应该有个人/客户ID,而不是PERSON表。但它并没有彻底改变事情。

答案 2 :(得分:1)

表格的更好结构是:

予。 (人物,姓名)---从此处删除的购买

II。 购买(purchaseid,buyerid,productid,date_purchased)--- buyerid已添加

III。 目录(产品,产品,每单位成本)

因此,不是将人的购买存储在Person表中,而是将它们存储在Purchase表中。

这有几个好处:

  1. 您可以根据需要存储任意数量的商品。现在的方式,“购买”字段最终将充满购买,你会做什么呢?

  2. 更容易编写查询。


  3. (如果Person.purchases中存储了“,1,300,292”,例如字段开头和结尾的逗号,没有空格),您的问题可以在一个查询中回答:

    如果在开始和结束时都有空格且没有逗号,则条件会更复杂,但肯定可以完成。

    SELECT p.id, p.name
    FROM Person p
      JOIN Purchase pur
        ON p.purchases LIKE CONCAT("%,",CAST(pur.id AS CHAR),",%")
    WHERE pur.product LIKE "foo"
    

    由于Catalog名称也位于Product表中,因此您不需要Purchase加入。

    如果您确实希望获得Catalog的信息,也可以让其他人加入:

    SELECT p.id, p.name, cat.*
    FROM Person p
      JOIN Purchase pur
        ON p.purchases LIKE CONCAT("%,",CAST(pur.id AS CHAR),",%")
      JOIN Catalog cat
        ON pur.product = cat.product
    WHERE pur.product LIKE "foo"     ---or cat.product LIKE "foo"
    

答案 3 :(得分:1)

对于MySQL,这可能是更好的解决方案:

SELECT person.*
FROM person
JOIN purchases
ON FIND_IN_SET(purchases.id,person.purchases) > 0
WHERE purchases.product = 'foo';