mysql - Laravel 5 中的复杂 JOIN SQL 查询

标签 mysql laravel laravel-5

我需要加入三个表:productsorders_itemsorders

products 表显然包含产品。当用户将产品添加到他们的购物车时,它会在 order_items 表中创建一个 order 和一个订单项。当用户支付时,它将支付的总额放入orders表中。因此,从库存中移除的购买产品仅包括附加到已标记为已付款的订单的 order_item 的产品。

我需要退回所有产品,还需要计算库存中剩余的数量。产品表包含一个名为“initial_quantity”的字段,这是我们开始使用的产品数量。如果该字段为 NULL,则对产品没有限制。

这是我当前的查询,它可以很好地返回特定类型的所有产品:

$swims = Product::where('product_type_id', 1)
            ->whereDate('visible_date', '<=', Carbon::now())
            ->where('active', true)
            ->where(function ($query) {
                $query->where('end_date', '>=', Carbon::now())
                      ->orWhere('end_date', null);  
            })          
            ->get();

这是该查询的 SQL:

select * from `products` where `product_type_id` = 1 and date(`visible_date`) <= '2019-08-08 17:10:12' and `active` = 1 and (`end_date` >= '2019-08-08 17:10:12' or `end_date` is null)

上面的查询返回三个结果:

+----+-------------+------------+------------+--------------+------------------+-----------------+--------+
| id | name        | base_price | end_date   | visible_date | initial_quantity | product_type_id | active |
+----+-------------+------------+------------+--------------+------------------+-----------------+--------+
|  1 | membership  |      30.97 | NULL       | 2019-08-04   |             NULL |               1 |      1 |
| 12 | repellendus |     779.24 | 2027-03-16 | 1990-12-19   |             NULL |               1 |      1 |
| 16 | ducimus     |     708.33 | NULL       | 1999-03-24   |             NULL |               1 |      1 |
+----+-------------+------------+------------+--------------+------------------+-----------------+--------+

我可以运行另一个查询来查看每种产品的销量:

select product_id, SUM(quantity) sold from `order_items` inner join `orders` on `order_items`.`order_id` = `orders`.`id` and `orders`.`paid` is not null group by `product_id`

此查询返回:

+------------+------+
| product_id | sold |
+------------+------+
|          1 |    5 |
|          7 |    3 |
|         11 |    1 |
|         12 |    1 |
+------------+------+

我正在寻找的是一种组合这两个(或类似)查询的方法,这样我就可以获得我正在寻找的所有产品,加上已售出的产品数量,从而得到类似的结果对此:

+----+-------------+------------+------------+--------------+------------------+-----------------+--------+------+
| id | name        | base_price | end_date   | visible_date | initial_quantity | product_type_id | active | sold |
+----+-------------+------------+------------+--------------+------------------+-----------------+--------+------+
|  1 | membership  |      30.97 | NULL       | 2019-08-04   |             NULL |               1 |      1 |    5 |
| 12 | repellendus |     779.24 | 2027-03-16 | 1990-12-19   |             NULL |               1 |      1 |    1 |
| 16 | ducimus     |     708.33 | NULL       | 1999-03-24   |             NULL |               1 |      1 |    0 |
+----+-------------+------------+------------+--------------+------------------+-----------------+--------+------+

我想要一个返回我正在搜索的所有产品以及剩余数量的查询。我试过连接、左连接、右连接、子查询连接和联合。 Laravel 似乎没有外部连接,否则我也会尝试那些。

我已经尝试过这个查询和许多其他迭代,但我总是遇到语法错误:

select * from (`products` where `product_type_id` = 1 and date(`visible_date`) <= '2019-08-08 17:10:12' and `active` = 1 and (`end_date` >= '2019-08-08 17:10:12' or `end_date` is null)) x INNER JOIN (select product_id, SUM(quantity) sold from `order_items` inner join `orders` on `order_items`.`order_id` = `orders`.`id` and `orders`.`paid` is not null group by `product_id`) y ON x.id = y.product_id

任何人都可以提出我正在寻找的查询吗?如果不是在 Laravel 中,那么在原始 SQL 中就可以了,我可以按原样使用它或尝试将其 Laravelize 化。

提前谢谢你。

这是我的 MRE:

CREATE TABLE `products` (
  `id` bigint(20) UNSIGNED NOT NULL,
  `name` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL,
  `base_price` double(5,2) NOT NULL,
  `end_date` date DEFAULT NULL,
  `visible_date` date DEFAULT NULL,
  `initial_quantity` smallint(5) UNSIGNED DEFAULT NULL,
  `product_type_id` int(10) UNSIGNED NOT NULL,
  `active` tinyint(3) UNSIGNED NOT NULL DEFAULT '1'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;


INSERT INTO `products` (`id`, `name`, `base_price`, `end_date`, `visible_date`, `initial_quantity`, `product_type_id`, `active`) VALUES
(1, 'membership', 30.97, NULL, '2019-08-04', NULL, 1, 1),
(2, 'delectus', 347.44, NULL, '1975-06-08', 45, 1, 0),
(3, 'aut', 283.36, '1981-05-30', '1973-08-18', NULL, 3, 0),
(4, 'adipisci', 984.00, '1986-01-04', '1989-03-29', NULL, 3, 0),
(5, 'voluptas', 310.55, '2012-05-04', '1992-11-16', 45, 2, 1),
(6, 'quia', 657.81, '1976-11-23', '1978-10-23', 57, 2, 0),
(7, 'delectus', 601.91, NULL, '1987-03-09', 53, 2, 1),
(8, 'consequatur', 723.25, '1994-09-24', '1985-01-23', 33, 1, 0),
(9, 'perferendis', 427.33, NULL, '1995-12-08', 51, 3, 1),
(10, 'id', 674.39, '1974-12-13', '2007-05-12', 41, 2, 0),
(11, 'maxime', 133.49, NULL, '1986-07-15', NULL, 2, 1),
(12, 'repellendus', 779.24, '2027-03-16', '1990-12-19', NULL, 1, 1),
(13, 'sit', 956.76, NULL, '1993-07-02', 39, 2, 0),
(14, 'molestiae', 425.16, NULL, '1981-03-25', NULL, 3, 1),
(15, 'omnis', 418.78, '1976-11-03', '2007-10-07', NULL, 3, 1),
(16, 'ducimus', 708.33, NULL, '1999-03-24', NULL, 1, 1),
(17, 'numquam', 328.26, '2011-09-19', '2001-10-07', NULL, 3, 1),
(18, 'est', 962.26, NULL, '1970-12-24', NULL, 1, 0),
(19, 'quis', 520.18, NULL, '1978-03-25', NULL, 3, 0),
(20, 'facere', 891.89, NULL, '1979-10-31', 36, 3, 0),
(21, 'voluptatem', 518.47, '1982-06-26', '1975-03-14', NULL, 1, 1);
COMMIT;

    CREATE TABLE `order_items` (
      `order_id` bigint(20) UNSIGNED NOT NULL,
      `product_id` bigint(20) UNSIGNED NOT NULL,
      `quantity` tinyint(3) UNSIGNED NOT NULL DEFAULT '1',
      `price` double(5,2) NOT NULL,
      `tax` double(5,2) NOT NULL,
      `buy_now` tinyint(3) UNSIGNED NOT NULL DEFAULT '1',
      `created_at` timestamp NULL DEFAULT NULL,
      `updated_at` timestamp NULL DEFAULT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

    INSERT INTO `order_items` (`order_id`, `product_id`, `quantity`, `price`, `tax`, `buy_now`, `created_at`, `updated_at`) VALUES
    (1, 1, 1, 30.97, 4.03, 1, '2019-08-04 11:35:26', '2019-08-04 11:35:26'),
    (1, 12, 1, 779.24, 654.56, 1, '2019-08-04 11:35:26', '2019-08-04 11:35:26'),
    (2, 1, 1, 30.97, 4.03, 1, '2019-08-04 11:56:16', '2019-08-04 11:56:16'),
    (3, 1, 1, 30.97, 4.03, 1, '2019-08-07 17:25:43', '2019-08-07 17:25:43'),
    (3, 7, 1, 601.91, 210.67, 1, '2019-08-07 17:25:43', '2019-08-07 17:25:43'),
    (4, 1, 1, 30.97, 4.03, 1, '2019-08-08 15:44:45', '2019-08-08 15:44:45'),
    (4, 7, 1, 601.91, 210.67, 1, '2019-08-08 15:44:45', '2019-08-08 15:44:45'),
    (5, 1, 1, 30.97, 4.03, 1, '2019-08-08 15:46:07', '2019-08-08 15:46:07'),
    (5, 11, 1, 133.49, 88.10, 1, '2019-08-08 15:46:07', '2019-08-08 15:46:07'),
    (6, 1, 1, 30.97, 4.03, 1, '2019-08-08 15:46:55', '2019-08-08 15:46:55'),
    (6, 16, 1, 708.33, 687.08, 1, '2019-08-08 15:46:55', '2019-08-08 15:46:55'),
    (7, 1, 1, 30.97, 4.03, 1, '2019-08-08 15:47:37', '2019-08-08 15:47:37'),
    (7, 7, 1, 601.91, 210.67, 1, '2019-08-08 15:47:37', '2019-08-08 15:47:37'),
    (8, 1, 1, 30.97, 4.03, 1, '2019-08-08 15:48:13', '2019-08-08 15:48:13'),
    (8, 11, 1, 133.49, 88.10, 1, '2019-08-08 15:48:13', '2019-08-08 15:48:13');

    CREATE TABLE `orders` (
      `id` bigint(20) UNSIGNED NOT NULL,
      `user_id` bigint(20) UNSIGNED NOT NULL,
      `subtotal` double(7,2) DEFAULT NULL,
      `tax` double(7,2) DEFAULT NULL,
      `paid` double(7,2) DEFAULT NULL,
      `transaction` varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
      `created_at` timestamp NULL DEFAULT NULL,
      `updated_at` timestamp NULL DEFAULT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

    INSERT INTO `orders` (`id`, `user_id`, `subtotal`, `tax`, `paid`, `transaction`, `created_at`, `updated_at`) VALUES
    (1, 1, 810.21, 658.59, 12343.00, NULL, '2019-08-04 11:35:26', '2019-08-04 11:35:26'),
    (2, 1, 30.97, 4.03, NULL, NULL, '2019-08-04 11:56:16', '2019-08-04 11:56:16'),
    (3, 1, 632.88, 214.70, 847.58, NULL, '2019-08-05 17:25:43', '2019-08-07 17:25:43'),
    (4, 5, 632.88, 214.70, 847.58, NULL, '2019-08-08 15:44:45', '2019-08-08 15:44:45'),
    (5, 5, 164.46, 92.13, 256.59, NULL, '2019-08-08 15:46:07', '2019-08-08 15:46:07'),
    (6, 5, 739.30, 691.11, NULL, NULL, '2019-08-08 15:46:55', '2019-08-08 15:46:55'),
    (7, 10, 632.88, 214.70, 847.58, NULL, '2019-08-08 15:47:37', '2019-08-08 15:47:37'),
    (8, 10, 164.46, 92.13, NULL, NULL, '2019-08-08 15:48:13', '2019-08-08 15:48:13');

最佳答案

SELECT a.*
     , COALESCE(b.sold,0) sold
  FROM 
     ( SELECT * 
         FROM products p
        WHERE p.product_type_id = 1 
          AND DATE(p.visible_date) <= '2019-08-08 17:10:12' 
          AND p.active = 1 
          AND (p.end_date >= '2019-08-08 17:10:12' or p.end_date IS NULL)
     ) a
  LEFT
  JOIN   
     ( SELECT product_id
            , SUM(quantity) sold 
         FROM order_items oi
         JOIN orders o
           ON o.id = oi.order_id
          AND o.paid is not null 
        GROUP 
           BY product_id
     ) b
    ON b.product_id = a.id;

...或者,更好...

SELECT p.*
     , COALESCE(y.sold,0) sold
  FROM products p
  LEFT
  JOIN 
     ( SELECT product_id
            , SUM(quantity) sold 
         FROM order_items oi
         JOIN orders o
           ON o.id = oi.order_id 
          AND o.paid is not null 
        GROUP 
           BY product_id
     ) y 
    ON y.product_id = p.id
 WHERE p.product_type_id = 1 
   AND DATE(p.visible_date) <= '2019-08-08 17:10:12' 
   AND p.active = 1 
   AND (p.end_date >= '2019-08-08 17:10:12' OR p.end_date IS NULL) 

关于mysql - Laravel 5 中的复杂 JOIN SQL 查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57410369/

相关文章:

mysql - 尝试将坐标从 .txt 文件加载到 MySQL 时出错

laravel - 具有替代键的 Eloquent ManyToMany

VSCode 中的 Laravel 9 + PHP 8.0.8 显示语法错误,意外的 '->' (T_OBJECT_OPERATOR)

php - Laravel 5 如何检查密码重置 token 是否已过期

mysql - 数据库问题错误无法修复

mysql - 使用 mySQL Workbench 向用户添加表权限

javascript - 如何使用 node.js 和 redis Laravel 5 监听事件

Laravel 中正确字符和排序规则的 MySQL 设置

mysql - WPF vb.net使用Mysql数据库填充Listview

laravel 验证器不返回输入字段