在选择特定列从中提取的同时连接表
Joining tables while choosing which one a specific column pulls from
编辑:我使用的是 10.4.11-MariaDB 版本。这是一些代码来创建如图所示 tables
CREATE TABLE cats (
c_id INT PRIMARY KEY AUTO_INCREMENT,
c_name VARCHAR(255) NOT NULL UNIQUE
);
CREATE TABLE stock (
p_id INT PRIMARY KEY AUTO_INCREMENT,
c_id INT NOT NULL,
level DECIMAL(10,2) NOT NULL,
rating DECIMAL(10,2) NOT NULL DEFAULT 0.00
);
CREATE TABLE orders (
p_id INT NOT NULL,
sales INT NOT NULL
);
INSERT INTO cats (c_id, c_name) VALUES
(1, 'Boat'),
(2, 'Plane'),
(3, 'Car'),
(4, 'Bike');
INSERT INTO stock (p_id, c_id, level, rating) VALUES
(1, 1, 145.65, 41),
(2, 1, 915.06, 49),
(3, 1, 981.36, 64),
(4, 1, 727.81, 29),
(5, 2, 678.19, 51),
(6, 2, 808.13, 43),
(7, 2, 711.10, 17),
(8, 3, 503.34, 92),
(9, 4, 292.41, 19),
(10, 4, 15.67, 36);
INSERT INTO orders (p_id, sales) VALUES
(1, 2),
(2, 4),
(9, 4),
(3, 2),
(8, 4),
(6, 3),
(2, 1),
(10, 2),
(8, 3),
(1, 4);
我将尝试彻底解决这个问题,因为我之前已经解决了这个问题,所以如果我需要提供任何其他信息,请告诉我。我将从代表我正在处理的数据的三个样本 table 开始,分别命名为 cats
、stock
和 orders
(全部小写,如果事项)。
基本思想是每个 p_id
都有一个关联的 rating
、level
和 sales
值,并且 p_id
值可以分类为他们共享 c_id
。 stock
中的每个p_id
都是独一无二的,只属于一个c_id
。我的目标是生成一个 table,它对按 c_name
分组的 rating
、level
和 sales
列的聚合执行一些简单的计算。我根据 c_id
所属的内容对每个 p_id
进行了颜色编码,希望能让事情更容易理解。下面是我想要生成的 table 的示例:
编辑:汽车的最低评分应为 92,而不是 8
如您所见,我想要select四列:
c_name
中的每个值
- 共享
c_id
对应 c_name
的 p_id
个值的数量
- 每个类别
p_id
中包含的最小值 rating
- 每个类别中所有
p_id
值的平均值 level
- 每个类别中所有
p_id
值的总和 sales
我还希望在底部有一行,其中包含对整个 p_id
值总体进行的相同计算,忽略类别。即,总和为# of P_id's
、最小值为min rating
、平均值为avg level
、总和为# of sales
的一行。请注意,orders
不包括stock
中的每个p_id
,并且某些p_id
值是重复的;重要的是中间三行每个 p_id
只包含一次,无论它们在 orders
中出现多少次。同样,最后一列必须对存在的 p_id
值的销售额求和并按类别对它们进行分组。
我写了这个查询来尝试生成这个:
SELECT c_name, COUNT(p_id), MIN(rating), FORMAT(AVG(level),2), (SELECT SUM(sales) FROM orders JOIN stock USING(p_id))
FROM stock
JOIN cats USING(c_id)
GROUP BY c_name ASC WITH ROLLUP
这几乎完全符合我的要求,除了最后一列有问题,它只显示所有 p_id
值组合的总销售额,而不考虑类别。我想在 SELECT 语句中使用子查询来计算此列,就好像我在 JOINing stock
with cats
之后改为 LEFT JOIN orders
with stock
, 每个 列将仅根据在orders
中找到的p_id
值执行计算。我的想法是通过简单地 select 为我在子查询中需要的最后一列设置我需要的值来避免这种情况,但我正在努力弄清楚如何按 category_id 对结果进行分组从 product_id
到 category_id
的映射仅存在于 stock
.
中
本质上,我认为我的问题归结为不知道如何让我的中间三列基于 stock
中的 p_id
列聚合数据,同时确保最后一列只需要来自 orders
。谁能给我建议?
如果我需要更具体的信息,请告诉我。
对于您的样本数据,这将起作用:
SELECT c.c_name, t.`# of p_ids`, t.`min rating`, t.`avg level`,
COALESCE(
SUM(o.sales),
(SELECT SUM(sales) FROM orders)
) `# of sales`
FROM (
SELECT c_id,
COUNT(p_id) `# of p_ids`,
MIN(rating) `min rating`,
FORMAT(AVG(level), 2) `avg level`
FROM stock
GROUP BY c_id WITH ROLLUP
) t
LEFT JOIN cats c ON c.c_id = t.c_id
LEFT JOIN stock s ON s.c_id = t.c_id
LEFT JOIN orders o ON o.p_id = s.p_id
GROUP BY t.c_id, c.c_name, t.`# of p_ids`, t.`min rating`, t.`avg level`
ORDER BY c.c_name IS NULL, c.c_id
参见demo。
结果:
| c_name | # of p_ids | min rating | avg level | # of sales |
| ------ | ---------- | ---------- | --------- | ---------- |
| Boat | 4 | 29 | 692.47 | 13 |
| Plane | 3 | 17 | 732.47 | 3 |
| Car | 1 | 92 | 503.34 | 7 |
| Bike | 2 | 19 | 154.04 | 6 |
| | 10 | 17 | 577.87 | 29 |
您可以通过使用几个聚合作为 table 表达式来获得您想要的结果;然后你只需将它们连接在一起即可产生完整的结果。
例如:
select
x.c_name,
x.number_of_pids,
x.min_rating,
x.avg_level,
s.sum_sales
from (
select
c.c_id,
max(c.c_name) as c_name,
count(distinct s.p_id) as number_of_pids,
min(s.rating) as min_rating,
avg(s.level) as avg_level
from cats c
left join stock s on s.c_id = c.c_id
group by c.c_id
) x
left join (
select
s.c_id, sum(sales) as sum_sales
from stock s
left join orders o on o.p_id = s.p_id
group by s.c_id
) s on s.c_id = x.c_id
编辑:我使用的是 10.4.11-MariaDB 版本。这是一些代码来创建如图所示 tables
CREATE TABLE cats (
c_id INT PRIMARY KEY AUTO_INCREMENT,
c_name VARCHAR(255) NOT NULL UNIQUE
);
CREATE TABLE stock (
p_id INT PRIMARY KEY AUTO_INCREMENT,
c_id INT NOT NULL,
level DECIMAL(10,2) NOT NULL,
rating DECIMAL(10,2) NOT NULL DEFAULT 0.00
);
CREATE TABLE orders (
p_id INT NOT NULL,
sales INT NOT NULL
);
INSERT INTO cats (c_id, c_name) VALUES
(1, 'Boat'),
(2, 'Plane'),
(3, 'Car'),
(4, 'Bike');
INSERT INTO stock (p_id, c_id, level, rating) VALUES
(1, 1, 145.65, 41),
(2, 1, 915.06, 49),
(3, 1, 981.36, 64),
(4, 1, 727.81, 29),
(5, 2, 678.19, 51),
(6, 2, 808.13, 43),
(7, 2, 711.10, 17),
(8, 3, 503.34, 92),
(9, 4, 292.41, 19),
(10, 4, 15.67, 36);
INSERT INTO orders (p_id, sales) VALUES
(1, 2),
(2, 4),
(9, 4),
(3, 2),
(8, 4),
(6, 3),
(2, 1),
(10, 2),
(8, 3),
(1, 4);
我将尝试彻底解决这个问题,因为我之前已经解决了这个问题,所以如果我需要提供任何其他信息,请告诉我。我将从代表我正在处理的数据的三个样本 table 开始,分别命名为 cats
、stock
和 orders
(全部小写,如果事项)。
基本思想是每个 p_id
都有一个关联的 rating
、level
和 sales
值,并且 p_id
值可以分类为他们共享 c_id
。 stock
中的每个p_id
都是独一无二的,只属于一个c_id
。我的目标是生成一个 table,它对按 c_name
分组的 rating
、level
和 sales
列的聚合执行一些简单的计算。我根据 c_id
所属的内容对每个 p_id
进行了颜色编码,希望能让事情更容易理解。下面是我想要生成的 table 的示例:
编辑:汽车的最低评分应为 92,而不是 8
如您所见,我想要select四列:
c_name
中的每个值
- 共享
c_id
对应c_name
的 - 每个类别
p_id
中包含的最小值rating
- 每个类别中所有
p_id
值的平均值level
- 每个类别中所有
p_id
值的总和sales
p_id
个值的数量
我还希望在底部有一行,其中包含对整个 p_id
值总体进行的相同计算,忽略类别。即,总和为# of P_id's
、最小值为min rating
、平均值为avg level
、总和为# of sales
的一行。请注意,orders
不包括stock
中的每个p_id
,并且某些p_id
值是重复的;重要的是中间三行每个 p_id
只包含一次,无论它们在 orders
中出现多少次。同样,最后一列必须对存在的 p_id
值的销售额求和并按类别对它们进行分组。
我写了这个查询来尝试生成这个:
SELECT c_name, COUNT(p_id), MIN(rating), FORMAT(AVG(level),2), (SELECT SUM(sales) FROM orders JOIN stock USING(p_id))
FROM stock
JOIN cats USING(c_id)
GROUP BY c_name ASC WITH ROLLUP
这几乎完全符合我的要求,除了最后一列有问题,它只显示所有 p_id
值组合的总销售额,而不考虑类别。我想在 SELECT 语句中使用子查询来计算此列,就好像我在 JOINing stock
with cats
之后改为 LEFT JOIN orders
with stock
, 每个 列将仅根据在orders
中找到的p_id
值执行计算。我的想法是通过简单地 select 为我在子查询中需要的最后一列设置我需要的值来避免这种情况,但我正在努力弄清楚如何按 category_id 对结果进行分组从 product_id
到 category_id
的映射仅存在于 stock
.
本质上,我认为我的问题归结为不知道如何让我的中间三列基于 stock
中的 p_id
列聚合数据,同时确保最后一列只需要来自 orders
。谁能给我建议?
如果我需要更具体的信息,请告诉我。
对于您的样本数据,这将起作用:
SELECT c.c_name, t.`# of p_ids`, t.`min rating`, t.`avg level`,
COALESCE(
SUM(o.sales),
(SELECT SUM(sales) FROM orders)
) `# of sales`
FROM (
SELECT c_id,
COUNT(p_id) `# of p_ids`,
MIN(rating) `min rating`,
FORMAT(AVG(level), 2) `avg level`
FROM stock
GROUP BY c_id WITH ROLLUP
) t
LEFT JOIN cats c ON c.c_id = t.c_id
LEFT JOIN stock s ON s.c_id = t.c_id
LEFT JOIN orders o ON o.p_id = s.p_id
GROUP BY t.c_id, c.c_name, t.`# of p_ids`, t.`min rating`, t.`avg level`
ORDER BY c.c_name IS NULL, c.c_id
参见demo。
结果:
| c_name | # of p_ids | min rating | avg level | # of sales |
| ------ | ---------- | ---------- | --------- | ---------- |
| Boat | 4 | 29 | 692.47 | 13 |
| Plane | 3 | 17 | 732.47 | 3 |
| Car | 1 | 92 | 503.34 | 7 |
| Bike | 2 | 19 | 154.04 | 6 |
| | 10 | 17 | 577.87 | 29 |
您可以通过使用几个聚合作为 table 表达式来获得您想要的结果;然后你只需将它们连接在一起即可产生完整的结果。
例如:
select
x.c_name,
x.number_of_pids,
x.min_rating,
x.avg_level,
s.sum_sales
from (
select
c.c_id,
max(c.c_name) as c_name,
count(distinct s.p_id) as number_of_pids,
min(s.rating) as min_rating,
avg(s.level) as avg_level
from cats c
left join stock s on s.c_id = c.c_id
group by c.c_id
) x
left join (
select
s.c_id, sum(sales) as sum_sales
from stock s
left join orders o on o.p_id = s.p_id
group by s.c_id
) s on s.c_id = x.c_id