当前位置: 首页 > 知识库问答 >
问题:

MySQL:如何找到客户在不同订单中重复订购的产品

熊博远
2023-03-14

我尝试了很多,但当我找不到解决方案时,我将第一个问题发布在这里:

我有四张桌子:

    products
    ---------------
    id, name

    customers
    ------------------
    id, name

    orders
    -------------
    id, customer_id

    orders_products
    ---------------------------
    id, order_id, product_id

当然,一个客户只能在一个订单中订购一次产品

在一个查询中,我想返回每个customer\u id以及order\u id和product\u id,这些客户在多个订单中订购了任何产品。

换句话说,对于每个客户,我希望找到客户多次订购的不同产品(在单独的订单中),以及product\u id和order\u id。因此product\u id/order\u id应该重复,因为产品将在多个订单中订购多次。我不想返回只订购一次产品的记录。

我希望我足够清楚。

我已经有了样本数据和表格。编辑我的问题以发布用于创建数据库和表的sql

CREATE DATABASE IF NOT EXISTS `test`
USE `test`;


CREATE TABLE IF NOT EXISTS `products` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(50) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7;

INSERT INTO `products` (`id`, `name`) VALUES
    (1, 'Car'),
    (2, 'Bus'),
    (3, 'Truck'),
    (4, 'Fan'),
    (5, 'Photo'),
    (6, 'Watch');

CREATE TABLE IF NOT EXISTS `customers` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6;

INSERT INTO `customers` (`id`, `name`) VALUES
    (1, 'Sukh'),
    (2, 'Sukh2'),
    (3, 'Ravi'),
    (4, 'Ravinder'),
    (5, 'Jas');


CREATE TABLE IF NOT EXISTS `orders` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `customer_id` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8;


INSERT INTO `orders` (`id`, `customer_id`) VALUES
    (1, 1),
    (2, 2),
    (3, 1),
    (4, 2),
    (5, 5),
    (6, 4),
    (7, 1);

CREATE TABLE IF NOT EXISTS `order_products` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `order_id` int(11) NOT NULL DEFAULT '0',
  `product_id` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7;

INSERT INTO `order_products` (`id`, `order_id`, `product_id`) VALUES
    (1, 1, 1),
    (2, 2, 1),
    (3, 1, 2),
    (4, 4, 1),
    (5, 3, 5),
    (6, 7, 5);


select p.name, c.name, o.id as order_id, c.id as customer_id, p.id as product_id
from customers c inner join orders o on c.id=o.customer_id
inner join order_products op on op.order_id=o.id
inner join products p on p.id=op.product_id order by order_id

sukh2订购了订单号2和订单号4的汽车(一位客户多次订购的汽车),所以我想退回这两份记录,sukh订购了订单号3和订单号7的照片(一位客户多次订购的照片),所以这两份记录也应该总共退回4份。

我尝试了很多下面查询的变体,但没有得到正确的结果。我想我唯一错过的是在子查询结果上加入customer_id。所以我尝试了下面给定的查询,它似乎确实有效。@barmar建议有所帮助。

SELECT p.name, c.name, o.id AS order_id, c.id AS customer_id, p.id AS product_id
FROM customers c
INNER JOIN orders o ON c.id=o.customer_id
INNER JOIN order_products op ON op.order_id=o.id
INNER JOIN products p ON p.id=op.product_id
INNER JOIN (
SELECT customer_id, p.id AS product_id
FROM customers c
INNER JOIN orders o ON c.id=o.customer_id
INNER JOIN order_products op ON op.order_id=o.id
INNER JOIN products p ON p.id=op.product_id
GROUP BY c.id, p.id
HAVING COUNT(p.id) > 1) q2 ON q2.product_id=p.id AND q2.customer_id=c.id

能不能写的好一点,夜深了,我多试试,结果不对就发帖。

谢谢大家的帮助。

共有1个答案

宋华灿
2023-03-14

您可以将子查询中的联接表减少为订单和订单产品,因为它们已经保存了所有需要的信息(客户id和产品id)。您也可以使用计数(*)而不是计数(p.id)

SELECT p.name, c.name, o.id AS order_id, c.id AS customer_id, p.id AS product_id
FROM customers c
INNER JOIN orders o ON c.id=o.customer_id
INNER JOIN order_products op ON op.order_id = o.id
INNER JOIN products p ON p.id = op.product_id
INNER JOIN (
    SELECT o.customer_id, op.product_id
    FROM  orders o 
    INNER JOIN order_products op ON op.order_id = o.id
    GROUP BY o.customer_id, op.product_id
    HAVING COUNT(*) > 1
) q2 ON q2.product_id = p.id AND q2.customer_id = c.id

这将返回与查询相同的结果。

name    product_id  name    customer_id     order_id
Car              1  Sukh2             2            2
Car              1  Sukh2             2            4
Photo            5  Sukh              1            3
Photo            5  Sukh              1            7

演示:https://www.db-fiddle.com/f/bq2WbLNGdKHGjowkR25VAr/0

但是,如果可以使用稍微不同的数据格式,则可以避免使用子查询,并使用聚合函数使用相同的表进行连接。

SELECT p.name, op.product_id, c.name, o.customer_id, GROUP_CONCAT(o.id) AS order_ids
FROM  orders o 
INNER JOIN order_products op ON op.order_id = o.id
INNER JOIN customers c ON c.id = o.customer_id
INNER JOIN products p on p.id = op.product_id
GROUP BY o.customer_id, op.product_id
HAVING COUNT(*) > 1

结果:

name    product_id  name    customer_id     order_ids
Photo            5  Sukh              1     7,3
Car              1  Sukh2             2     4,2

演示:https://www.db-fiddle.com/f/n1zvoPjpBVAW9yvjPH1fro/0

但是为了更好的性能,在子查询中进行聚合仍然是有意义的,从而减少需要为GROUP BY排序的行的大小。所以我可能会这样写查询:

SELECT p.name, q.product_id, c.name, q.customer_id, q.order_ids
FROM (
    SELECT o.customer_id, op.product_id, GROUP_CONCAT(o.id) order_ids
    FROM  orders o 
    INNER JOIN order_products op ON op.order_id = o.id
    GROUP BY o.customer_id, op.product_id
    HAVING COUNT(*) > 1
) q
INNER JOIN products p ON p.id = q.product_id
INNER JOIN customers c ON c.id = q.customer_id

演示:https://www.db-fiddle.com/f/v7xXW1cLgwAUR4DSGAomev/0

 类似资料:
  • 问题内容: 我很难提出一个查询,该查询将找到同时购买了PROD1和PROD2的所有客户。 这是一个伪查询,看起来像我想要做的:(显然这是行不通的) 因此,基本上,我正在尝试对表中有product_id’ ‘和’ ‘事务的不同用户ID的数量进行计数。每个事务都存储在表中的一行中。 问题答案: 我通过以下方式进行这种类型的查询: @najmeddine显示的解决方案还会产生您想要的答案,但在MySQL

  • mysql会员订阅数据表的设计应该如何设计?产品有订阅商品和非订阅的,每次都只能购买一个。 订阅有1个月 3个月的 每次到期自动扣费。如果在一个月类购买了几个订阅商品 则扣费按照最新的一个 然后延长到期时间。其实是不是每次订阅都不需要生成新订单的 翻阅了其他资料都找不到很好的设计

  • 问题内容: 我正在为我的网上商店订购系统。我有2张桌子: 产品,存储有关产品的信息 订单,存储客户订单的一般ID和信息。 现在,我想拥有一种将复杂的客户订单存储在数据库中的方法。我需要一些东西让我知道订单中每种产品的大小(S,M或L)有多少。 棘手的部分是我希望能够添加/编辑/删除产品(当然不影响过去的订单),因此该方法应该灵活 我应该怎么做呢? 每个订单都有一个单独的表格,产品作为行? 所有订单

  • 现在来考虑 Customer,Order, LineItem 和 Product 关系的模型。Customer 和 Order 之间 是一对多的关系,但是我们怎么来描述 Order / LineItem / Product呢? 我可以把 LineItem 作为描述 Order 和 Product 多对多关系的关联类,在 Hibernate,这叫做组合元素。 映射文件如下: <hibernate-

  • 根据订购的产品,我需要发送两封不同的“新订单”电子邮件。这种情况下,产品存储在不同的位置,我需要发送一封电子邮件,其中只包含存储1中的产品,另一封邮件包含存储2中的产品。如果仅订购了位于存储1的产品,则不应发送电子邮件2,反之亦然。 存储信息是每个产品上的自定义元字段。 我添加了一个自定义电子邮件类,它是的副本,但仅在需要时更改了名称。 我一直在寻找钩子和过滤器,但我不能一路走下去。我也一直在考虑

  • 问题内容: 我目前有使用PIVOT生成如下表的查询: 我想做的是,但看起来像是拉伸,结果是值递减。 这是查询: 这样做会产生错误,因此可以指定列吗? 问题答案: 试试这个: