MYSQL 每个商店按五个字段加入和分组

MYSQL join and group by five field per store

我试图获得一个复杂的(至少对我而言)MySQL 查询,但我无法获得我想要的结果。

我有一个 DB 和 2 个表:

店铺

id, name

产品

id, store_id, hardware, name, price, url, notify

我希望每个 store_id 获得 3 件产品,通知 = 1,硬件 = 'gpu' 并按价格递增订购。

所以如果我启动这个 SQL 句子:

SELECT s.name as store, p.id as id, p.name as name, p.hardware as hw, p.price as price, p.url as url, p.notify as notify
FROM products p JOIN stores s
ON p.store_id = s.id
AND p.hardware='gpu'
AND p.notify = 1
GROUP BY store
ORDER BY p.price asc;

我每个 store_id 只得到一个产品,我想每个 store_id 得到(最大)树元素。类似于下一个示例:

store id name hw price url notify
store1 1 name1 gpu price url 1
store1 2 name2 gpu price url 1
store1 3 name3 gpu price url 1
store2 8 name8 gpu price url 1
store2 12 name12 gpu price url 1
store3 22 name22 gpu price url 1

等等...

我该怎么做?

示例数据

店铺

CREATE TABLE `stores` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` char(50) NOT NULL,
  `afiliate` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=utf8;

产品

CREATE TABLE `products` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `store_id` int(11) NOT NULL,
  `hardware` char(50) COLLATE utf8mb4_unicode_ci NOT NULL,
  `name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `price` decimal(10,2) NOT NULL,
  `notify` tinyint(4) NOT NULL
  PRIMARY KEY (`id`),
  KEY `Store_id_to_products` (`store_id`),
  CONSTRAINT `Store_id_to_products` FOREIGN KEY (`store_id`) REFERENCES `stores` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=1961 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
select id, name from stores;

结果

id name
1 Amazon
2 Ebay
3 BestBuy
4 Target
select * from products;

结果

id store_id hardware name price notify
1 3 gpu EVGA GeForce RTX 3070 FTW3 Ultra Gaming 8GB GDDR6 949.00 1
2 3 gpu Zotac Gaming GeForce RTX 3090 Trinity OC 24GB GDDR6X 2259.00 1
3 3 gpu EVGA GeForce RTX 3090 FTW3 Ultra Gaming 24GB GDDR6X 2749.00 1
4 3 gpu Asus TUF Gaming GeForce RTX 3090 OC Edition 24GB GDDR6X 2549.00 1
5 1 gpu Gigabyte GTX 1660 Super OC 6G 489.00 1
6 1 gpu Asus TUF GTX 1660 Super OC 6GB 428.99 1
8 1 gpu GIGABYTE RTX 3060 GAMING OC 12GB 689.00 1
9 1 gpu Gigabyte RTX 3080 Aorus Master 10GB 1398.99 1
10 2 gpu Asus ROG Strix RTX 3080 OC 10GB Blanca 1312.00 1
11 2 gpu Gigabyte RTX 3080 Gaming OC 10GB 1258.99 1
12 2 gpu Asus ROG Strix RTX 3090 OC Gaming 24GB 2599.00 1
13 4 gpu Asus TUF Gaming Radeon RX 6800 OC 16GB 1078.99 1
14 4 gpu GIGABYTE RX6800XT GAMING OC 16GB 450.00 1
15 4 gpu Gigabyte GeForce GTX 1660 Ti OC 6G 499.95 1
16 4 gpu ZOTAC GeForce GTX 1660 SUPER Twin Fan 529.95 1

我正在尝试做一个 SQL 句子,让每个商店获得 3 种最便宜的产品。这是我想要的结果:

id store_id hardware name price notify
1 3 gpu EVGA GeForce RTX 3070 FTW3 Ultra Gaming 8GB GDDR6 949.00 1
2 3 gpu Zotac Gaming GeForce RTX 3090 Trinity OC 24GB GDDR6X 2259.00 1
4 3 gpu Asus TUF Gaming GeForce RTX 3090 OC Edition 24GB GDDR6X 2549.00 1
5 1 gpu Gigabyte GTX 1660 Super OC 6G 489.00 1
6 1 gpu Asus TUF GTX 1660 Super OC 6GB 428.99 1
8 1 gpu GIGABYTE RTX 3060 GAMING OC 12GB 689.00 1
10 2 gpu Asus ROG Strix RTX 3080 OC 10GB Blanca 1312.00 1
11 2 gpu Gigabyte RTX 3080 Gaming OC 10GB 1258.99 1
12 2 gpu Asus ROG Strix RTX 3090 OC Gaming 24GB 2599.00 1
14 4 gpu GIGABYTE RX6800XT GAMING OC 16GB 450.00 1
15 4 gpu Gigabyte GeForce GTX 1660 Ti OC 6G 499.95 1
16 4 gpu ZOTAC GeForce GTX 1660 SUPER Twin Fan 529.95 1

提前致谢!!

如果您的 MySQL 版本低于 8+,您可以使用:

SELECT
      t1.id,
      name,
      hardware,
      price,
      notify
FROM (
        SELECT
              id,
              store_id,
              hardware,
              notify,
              price,
              @rn := IF(@prev = store_id, @rn + 1, 1) AS rn,
              @prev := store_id
        FROM products
        JOIN ( SELECT @prev := NULL, @rn := 0) AS vars
        where hardware='gpu' and notify=1
        ORDER BY  price ASC
    ) AS t1
INNER JOIN   stores st on  t1.store_id=st.id
WHERE rn <= 5
ORDER BY   id asc ; 

Demo

在MySQL8+

WITH my_table  AS (
  SELECT *, ROW_NUMBER() OVER (PARTITION BY store_id ORDER BY  price ASC ) AS rownum
  FROM products
)
SELECT my_table.id,st.name,hardware,my_table.name,price,notify
FROM my_table 
INNER JOIN  stores st on  my_table.store_id=st.id
WHERE  rownum <= 5
order by my_table.id asc;

Demo