ak8*_*k85 10 mysql sql join subquery
我试图得到一个项目的平均值,所以我使用子查询.
更新:我本来应该更清楚,但我希望avg仅用于最后5项
首先我开始
SELECT
y.id
FROM (
SELECT *
FROM (
SELECT *
FROM products
WHERE itemid=1
) x
ORDER BY id DESC
LIMIT 15
) y;
Run Code Online (Sandbox Code Playgroud)
哪个运行但是相当无用,因为它只是向我展示了ID.
然后我在下面添加了
SELECT
y.id,
(SELECT AVG(deposit) FROM (SELECT deposit FROM products WHERE id < y.id ORDER BY id DESC LIMIT 5)z) AVGDEPOSIT
FROM (
SELECT *
FROM (
SELECT *
FROM products
WHERE itemid=1
) x
ORDER BY id DESC
LIMIT 15
) y;
Run Code Online (Sandbox Code Playgroud)
当我这样做时,我在'where子句'中得到错误未知列'y.id',在进一步阅读这里我相信这是因为当查询进入下一级时,它们需要加入?
所以我尝试了以下**删除了不需要的suquery
SELECT
y.id,
(SELECT AVG(deposit) FROM (
SELECT deposit
FROM products
INNER JOIN y as yy ON products.id = yy.id
WHERE id < yy.id
ORDER BY id DESC
LIMIT 5)z
) AVGDEPOSIT
FROM (
SELECT *
FROM products
WHERE itemid=1
ORDER BY id DESC
LIMIT 15
) y;
Run Code Online (Sandbox Code Playgroud)
但我得到表'test.y'不存在.我在这里走在正确的轨道上吗?我需要改变什么来获得我在这之后的目标?
这个例子可以在sqlfiddle中找到.
CREATE TABLE products
(`id` int, `itemid` int, `deposit` int);
INSERT INTO products
(`id`, `itemid`, `deposit`)
VALUES
(1, 1, 50),
(2, 1, 75),
(3, 1, 90),
(4, 1, 80),
(5, 1, 100),
(6, 1, 75),
(7, 1, 75),
(8, 1, 90),
(9, 1, 90),
(10, 1, 100);
Run Code Online (Sandbox Code Playgroud)
根据我在这个例子中的数据,我的预期结果如下,其中每个ID旁边有一列,其中包含前5个存款的平均值.
id | AVGDEPOSIT
10 | 86 (deposit value of (id9+id8+id7+id6+id5)/5) to get the AVG
9 | 84
8 | 84
7 | 84
6 | 79
5 | 73.75
Run Code Online (Sandbox Code Playgroud)
我不是MySQL专家(在MS SQL中它可以做得更容易),你的问题对我来说有点不清楚,但看起来你正试图获得前5个项目的平均值.
如果您的Id没有间隙,那很简单:
select
p.id,
(
select avg(t.deposit)
from products as t
where t.itemid = 1 and t.id >= p.id - 5 and t.id < p.id
) as avgdeposit
from products as p
where p.itemid = 1
order by p.id desc
limit 15
Run Code Online (Sandbox Code Playgroud)
如果没有,那么我试图像这样做这个查询
select
p.id,
(
select avg(t.deposit)
from (
select tt.deposit
from products as tt
where tt.itemid = 1 and tt.id < p.id
order by tt.id desc
limit 5
) as t
) as avgdeposit
from products as p
where p.itemid = 1
order by p.id desc
limit 15
Run Code Online (Sandbox Code Playgroud)
但我有例外Unknown column 'p.id' in 'where clause'
.看起来MySQL无法处理2级子查询嵌套.但你可以获得5个以前的项目offset
,如下所示:
select
p.id,
(
select avg(t.deposit)
from products as t
where t.itemid = 1 and t.id > coalesce(p.prev_id, -1) and t.id < p.id
) as avgdeposit
from
(
select
p.id,
(
select tt.id
from products as tt
where tt.itemid = 1 and tt.id <= p.id
order by tt.id desc
limit 1 offset 6
) as prev_id
from products as p
where p.itemid = 1
order by p.id desc
limit 15
) as p
Run Code Online (Sandbox Code Playgroud)
这是我的解决方案.很容易理解它是如何工作的,但同时由于我使用的是一些字符串函数,因此它无法进行优化,而且它远非标准SQL.如果你只需要返回一些记录,它仍然可以.
此查询将为每个ID返回以逗号分隔的先前ID列表,按升序排序:
SELECT p1.id, p1.itemid, GROUP_CONCAT(p2.id ORDER BY p2.id DESC) previous_ids
FROM
products p1 LEFT JOIN products p2
ON p1.itemid=p2.itemid AND p1.id>p2.id
GROUP BY
p1.id, p1.itemid
ORDER BY
p1.itemid ASC, p1.id DESC
Run Code Online (Sandbox Code Playgroud)
它会返回这样的东西:
| ID | ITEMID | PREVIOUS_IDS |
|----|--------|-------------------|
| 10 | 1 | 9,8,7,6,5,4,3,2,1 |
| 9 | 1 | 8,7,6,5,4,3,2,1 |
| 8 | 1 | 7,6,5,4,3,2,1 |
| 7 | 1 | 6,5,4,3,2,1 |
| 6 | 1 | 5,4,3,2,1 |
| 5 | 1 | 4,3,2,1 |
| 4 | 1 | 3,2,1 |
| 3 | 1 | 2,1 |
| 2 | 1 | 1 |
| 1 | 1 | (null) |
Run Code Online (Sandbox Code Playgroud)
然后我们可以将这个查询的结果与products表本身连接起来,在连接条件下我们可以使用FIND_IN_SET(src,csvalues)返回逗号分隔值中src字符串的位置:
ON FIND_IN_SET(id, previous_ids) BETWEEN 1 AND 5
Run Code Online (Sandbox Code Playgroud)
最后的查询如下所示:
SELECT
list_previous.id,
AVG(products.deposit)
FROM (
SELECT p1.id, p1.itemid, GROUP_CONCAT(p2.id ORDER BY p2.id DESC) previous_ids
FROM
products p1 INNER JOIN products p2
ON p1.itemid=p2.itemid AND p1.id>p2.id
GROUP BY
p1.id, p1.itemid
) list_previous LEFT JOIN products
ON list_previous.itemid=products.itemid
AND FIND_IN_SET(products.id, previous_ids) BETWEEN 1 AND 5
GROUP BY
list_previous.id
ORDER BY
id DESC
Run Code Online (Sandbox Code Playgroud)
请看这里的小提琴.我不建议对大表使用这个技巧,但对于小数据集,它很好.
归档时间: |
|
查看次数: |
5335 次 |
最近记录: |