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 ;
在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;
我试图获得一个复杂的(至少对我而言)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 ;
在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;