子子查询在父 select 中找不到连接列
Sub sub-query can't find joined column in parent select
我 运行 在 SQL 方面遇到了一些麻烦:
基本上我试图得到一个结果集,其中包含向员工提出的所有问题的总和(按公司分组),并且还添加了 "onetime_items",这是在不同的 table 中手动添加的项目。
我目前有这个 SQL 声明(我正在使用 MySQL):
SELECT
CONCAT_WS(
', ', count(DISTINCT CONCAT(emailaddress, '_', a.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
现在我得到以下错误:
Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[42S22]: Column not found: 1054 Unknown column 'e.company_id' in 'where clause'
使用的日期是虚拟日期。
此列确实存在于 table 员工中并且左连接有效(我尝试手动输入 ID 而不是使用列引用并且它有效,我得到了正确的结果)
知道为什么引用 e.company_id 失败了吗?
感谢dba.stackexchange.com
link: https://dba.stackexchange.com/questions/126339/subquery-cant-find-column-from-superquerys-join
这是在那里发布的答案,希望其他人也能从中受益!
@Phil in the comments: 在评论中确定了问题的原因:
可能是因为嵌套太深
您有 2 层嵌套,table e 的引用不能 "see" 通过 MySQL.
中的这两层
相关内联子查询通常可以转换为派生的 tables,然后在 FROM 子句中 LEFT 连接到其他 tables 但它们必须变成不相关的(在 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 ;
测试在 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'
无法使用索引。如果列是具有 inclusive-exclusive 范围条件的 DATE 类型,最好用 BETWEEN 重写,它可以完美地处理任何精度的任何日期时间类型(DATE、DATETIME、TIMESTAMP):
-- 仅当类型为DATE时使用
date BETWEEN '2015-12-01' AND LAST_DAY('2015-12-01')
或:
-- 当类型为DATE、DATETIME或TIMESTAMP时使用
created_at >= '2015-12-01' AND created_at < '2016-01-01'
我 运行 在 SQL 方面遇到了一些麻烦: 基本上我试图得到一个结果集,其中包含向员工提出的所有问题的总和(按公司分组),并且还添加了 "onetime_items",这是在不同的 table 中手动添加的项目。
我目前有这个 SQL 声明(我正在使用 MySQL):
SELECT
CONCAT_WS(
', ', count(DISTINCT CONCAT(emailaddress, '_', a.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
现在我得到以下错误:
Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[42S22]: Column not found: 1054 Unknown column 'e.company_id' in 'where clause'
使用的日期是虚拟日期。
此列确实存在于 table 员工中并且左连接有效(我尝试手动输入 ID 而不是使用列引用并且它有效,我得到了正确的结果)
知道为什么引用 e.company_id 失败了吗?
感谢dba.stackexchange.com
link: https://dba.stackexchange.com/questions/126339/subquery-cant-find-column-from-superquerys-join
这是在那里发布的答案,希望其他人也能从中受益! @Phil in the comments: 在评论中确定了问题的原因: 可能是因为嵌套太深 您有 2 层嵌套,table e 的引用不能 "see" 通过 MySQL.
中的这两层相关内联子查询通常可以转换为派生的 tables,然后在 FROM 子句中 LEFT 连接到其他 tables 但它们必须变成不相关的(在 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 ;
测试在 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'
无法使用索引。如果列是具有 inclusive-exclusive 范围条件的 DATE 类型,最好用 BETWEEN 重写,它可以完美地处理任何精度的任何日期时间类型(DATE、DATETIME、TIMESTAMP):
-- 仅当类型为DATE时使用
date BETWEEN '2015-12-01' AND LAST_DAY('2015-12-01')
或:
-- 当类型为DATE、DATETIME或TIMESTAMP时使用
created_at >= '2015-12-01' AND created_at < '2016-01-01'