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

MySQL:如何查找不同订单客户重复订购的产品,mysql,Mysql,我已经尝试了很多,但当我找不到解决方案时,我将我的第一个问题发布在这里: 我有四张桌子: products --------------- id, name customers ------------------ id, name orders ------------- id, customer_id orders_products --------------------------- i

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

我有四张桌子:

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

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

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

    orders_products
    ---------------------------
    id, order_id, product_id
当然,客户在一次订单中只能订购一次产品

在一个查询中,我想返回每个在多个订单中订购任何产品的客户id以及订单id和产品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条记录中返回

我尝试了很多下面的查询,但没有得到正确的结果。我想我唯一错过的就是在子查询结果中加入客户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 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
能写得更好吗?已经很晚了。如果结果不正确,我会尝试更多并发布


谢谢大家的帮助。

您可以将子查询中的联接表缩减为
订单
订单产品
,因为它们已经保存了所有需要的信息(
客户id
产品id
)。您也可以使用
COUNT(*)
而不是
COUNT(p.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
演示:

但是,如果可以使用稍微不同的数据格式,则可以避免使用子查询,并使用
GROUP\u CONCAT()
aggregate函数与相同的表进行连接

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
演示:

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

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

演示:

您可以将子查询中的联接表缩减为
订单
订单产品
,因为它们已经保存了所有需要的信息(
客户id
产品id
)。您也可以使用
COUNT(*)
而不是
COUNT(p.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
演示:

但是,如果可以使用稍微不同的数据格式,则可以避免使用子查询,并使用
GROUP\u CONCAT()
aggregate函数与相同的表进行连接

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
演示:

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

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

演示:

请在您的问题中添加一些示例数据并提供所需的结果。加入一个返回按客户和产品ID分组的
COUNT(*)
的查询,并仅选择计数大于1的部分。欢迎使用Stack Overflow!StackOverflow不是免费的编码服务。请更新您的问题,以显示您已在某个应用程序中尝试过的内容。有关更多信息,请参阅,并以:)为例计算正在分组的对象的数量有点不寻常。请在问题中添加一些示例数据并提供所需结果。加入一个查询,该查询返回按客户和产品ID分组的
count(*)
,并仅选择计数大于1的。欢迎使用堆栈溢出!StackOverflow不是免费的编码服务。请更新您的问题,以显示您已在某个应用程序中尝试过的内容。有关更多信息,请参阅,并使用:)计算您分组的内容有点不寻常。谢谢您的帮助。我需要每个订单的结果,所以第一次查询就可以了。我想在子查询中添加其他表,因为用户可以按客户和产品名称进行搜索,所以我可以在子查询和外部查询中添加where条件。出于性能原因:1。如果搜索了产品和/或客户名称,则最好在子查询中有条件地内部联接products和customers表,并将其添加到子查询和外部查询的where子句中。或2。将子查询保持原样,不与产品和客户联接,并仅将where条件添加到外部查询。@最好在子查询中进行筛选。它将减少需要排序的行数。实际上,当您想在客户和产品名称上添加WHERE条件时,您将以原始查询结束:-)我不认为只向子查询添加过滤器就足够了。再次感谢你。最后一个问题,如果我做count(*)或count(p.id),会有什么不同谢谢你的帮助。我需要每个订单的结果,所以第一次查询就可以了。我想在子查询中添加其他表,因为用户可以按客户和产品名称进行搜索,所以我可以在子查询和外部查询中添加where条件。出于性能原因:1。如果搜索了产品和/或客户名称,则最好在子查询中有条件地内部联接products和customers表,并将其添加到子查询和外部查询的where子句中。或2。将子查询保持原样,不与产品和客户联接,并仅将where条件添加到外部查询。@最好在子查询中进行筛选。它将减少需要排序的行数。实际上,当您想要在客户和产品名称上添加WHERE条件时,您将以原始查询结束:-)我只是忽略了只在子查询中添加过滤器的想法