子查询无法从超级查询的连接中找到列

Flo*_*lot 7 mysql join subquery

我在 SQL 方面遇到了一些麻烦:基本上,我试图获取一个结果集,其中包含向员工提出的所有问题的总和(按公司分组),并添加手动添加项目的“onetime_items”不同的表。

我目前有这个 SQL 语句(我使用的是 MySQL):

SELECT 
CONCAT_WS(
    ', ', count(DISTINCT CONCAT(emailaddress, '_', e.id)),
    (
        SELECT GROUP_CONCAT(items SEPARATOR '; ') as OneTimeItems
        FROM ( 
            SELECT CONCAT_WS(
                ': ', oi.item_name, SUM(oi.item_amount)
            ) items 
            FROM onetime_item oi 
            WHERE oi.company_id = e.company_id
            AND oi.date BETWEEN '2015-12-01'
            AND LAST_DAY('2015-12-01') 
            GROUP BY oi.item_name 
        ) resulta
    )
) as AllItems,
e.id,
LEFT(e.firstname, 1) as voorletter,
e.lastname
FROM question q 
LEFT JOIN employee e ON q.employee_id = e.id 
WHERE 1=1 
AND YEAR(created_at) = '2015'
AND MONTH(created_at) = '12' 
GROUP BY e.company_id
Run Code Online (Sandbox Code Playgroud)

现在我收到以下错误:

SQLSTATE[42S22]: Column not found: 1054 Unknown column 'e.company_id' in where clause
Run Code Online (Sandbox Code Playgroud)

使用的日期是虚拟日期,底部 where 子句中的 1=1 是因为我正在根据用户输入值生成 where 语句。

所有列都存在于表员工中,并且左连接有效(我尝试手动输入一个 id 而不是使用列引用,它有效,我得到了正确的结果)

我也很抱歉,但我不允许在线发布表架构或与数据库结构相关的任何内容。

关于为什么对 e.company_id 的引用失败的任何想法?

编辑:这是我需要的结果集:

5, Het is je verjaardag: 1; Skivakantie: 1; Telefonische leadvergoeding: 8
Run Code Online (Sandbox Code Playgroud)

构造如下: 5 = 以逗号分隔以获取其余部分。Leads 是来自 Questions 表的唯一组合,其余结果由 onetime_items 构建。

编辑 2:SQL fiddle 不断向我抛出错误,所以我只是要发布一个带有一些合成数据的小型数据库:http : //pastebin.com/cCveVtGr

ype*_*eᵀᴹ 5

@Phil 在评论中确定了问题的原因:

可能是因为嵌套太深

你有 2 层嵌套,表的引用e在 MySQL 中无法“看穿”这 2 层。

相关的内联子查询通常可以转换为派生表,然后LEFT连接到FROM子句中的其他表,但必须将它们转换为不相关的(在 MySQL 中。在其他 DBMS 中,您可以使用LATERAL连接或类似的OUTER APPLY.

第一次重写以完成工作:

SELECT 
    CONCAT_WS(
        ', ', count(DISTINCT CONCAT(q.emailaddress, '_', e.id)),
        dv.OneTimeItems
    ) as AllItems,
    e.id,
    LEFT(e.firstname, 1) as voorletter,
    e.lastname
FROM question q 
LEFT JOIN employee e ON q.employee_id = e.id 
LEFT JOIN
    (
        SELECT company_id,
               GROUP_CONCAT(items SEPARATOR '; ') AS OneTimeItems
        FROM ( 
            SELECT oi.company_id,
                   CONCAT_WS(
                ': ', oi.item_name, SUM(oi.item_amount)
            ) items 
            FROM onetime_item oi 
            WHERE oi.date BETWEEN '2015-12-01'
                              AND LAST_DAY('2015-12-01') 
            GROUP BY oi.company_id, oi.item_name 
        ) resulta
        GROUP BY company_id
    ) AS dv
    ON dv.company_id = e.company_id
WHERE 1=1 
AND YEAR(q.created_at) = '2015'
AND MONTH(q.created_at) = '12' 
GROUP BY e.company_id ;
Run Code Online (Sandbox Code Playgroud)

SQLfiddle 中测试。


与问题无关的评论:

  • GROUP BY e.company_id,而select列表中有e.id, LEFT(e.firstname, 1), e.lastname。所有这些都会从每个公司的(或多或少随机的)员工给出任意结果——甚至在极少数情况下,来自 2 或 3 个不同员工的任意结果!MySQL 允许(在 5.7 之前)这种对 group by 的不良使用可能会导致错误的结果。它已在 5.7 中修复,默认设置将拒绝此查询。
  • 条件:

    YEAR(created_at) = '2015' AND MONTH(created_at) = '12'
    
    Run Code Online (Sandbox Code Playgroud)

    不能使用索引。BETWEEN如果列的DATE类型为具有包含-不包含范围条件的类型,则最好使用其中任何一个进行重写,该条件可以与任何精度的任何日期时间类型 ( DATE, DATETIME, TIMESTAMP)完美配合:

    -- use only when the type is DATE only
    date BETWEEN '2015-12-01' AND LAST_DAY('2015-12-01')
    
    Run Code Online (Sandbox Code Playgroud)

    或者:

    -- use when the type is DATE, DATETIME or TIMESTAMP
    created_at >= '2015-12-01' AND created_at < '2016-01-01'     
    
    Run Code Online (Sandbox Code Playgroud)