mysql子查询中的未知列

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)

Rom*_*kar 6

我不是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 fiddle demo


fth*_*lla 5

这是我的解决方案.很容易理解它是如何工作的,但同时由于我使用的是一些字符串函数,因此它无法进行优化,而且它远非标准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)

请看这里的小提琴.我不建议对大表使用这个技巧,但对于小数据集,它很好.