我有一个包含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。
有没有办法将这两者合并为一个查询?
答案 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)
可以使用单个查询来回答问题:
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')
这需要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表中。
这有几个好处:
您可以根据需要存储任意数量的商品。现在的方式,“购买”字段最终将充满购买,你会做什么呢?
更容易编写查询。
(如果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';