我正在使用Oracle12。我想出了一个简单的示例来尝试传达我所面临的问题,因为实际查询太复杂而无法在此处显示。这个简单的示例包含与复杂查询相同的条件和逻辑。我希望为主SELECT中的WHEN中的子查询找到一种访问表别名的方法,该别名是从与主SELECT处于同一级别的内部联接定义的。我尝试了此版本,但失败,并带有“ o”“表或视图不存在”:
SELECT emp.employeeid, emp.firstname
CASE
WHEN (SELECT count(*) FROM o WHERE o.shipperid <= 15) > 20 THEN 'Yes'
WHEN (SELECT count(*) FROM o WHERE o.shipperid <= 15) > 10 THEN 'Almost'
ELSE 'No'
END AS "Quota Met"
FROM Employee emp
INNER JOIN
(SELECT employeeid, shipperid FROM Orders
WHERE orderdate > sysdate - 30) o
ON o.employeeid = emp.id
WHERE emp.zipcode = 22151;
无法使上面的INNER JOIN版本正常工作,到目前为止,我最好的解决方法是使用如下所示的WITH功能定义SELECT,但是在实际查询中,WITH块需要几分钟才能完成,因为无法执行将其限制为与Employee.employeeid匹配,就像上面的INNER JOIN版本尝试一样。
WITH MyOrders AS
(SELECT employeeid, shipperid FROM Orders
WHERE orderdate > sysdate - 30
)
SELECT emp.id, emp.name, o
CASE
WHEN (SELECT COUNT(*) FROM MyOrders o WHERE o.shipperid <= 15) > 20 THEN 'Yes'
WHEN (SELECT COUNT(*) FROM MyOrders o WHERE o.shipperid <= 15) > 10 THEN 'Almost'
ELSE 'No'
END AS "Quota Met"
FROM Employee emp
WHERE emp.zipcode = 22151;
这个WITH版本真的是最好的解决方案吗?有什么方法可以重写第一个INNER JOIN版本,以便CASE WHEN中的子查询可以访问联接的表别名?
答案 0 :(得分:2)
您实际上并不需要子查询;如果将o.shipperid <= 15
检查移到内联视图中,则可以只计算联接中的匹配项。我已将您的内部联接更改为外部联接,因此您将看到零计数为“否”-否则将没有匹配项,并且根本不会显示该员工。
SELECT emp.employeeid, emp.firstname,
CASE
WHEN count(o.shipperid) > 20 THEN 'Yes'
WHEN count(o.shipperid) > 10 THEN 'Almost'
ELSE 'No'
END AS "Quota Met"
FROM Employee emp
LEFT JOIN (
SELECT employeeid, shipperid
FROM Orders
WHERE orderdate > sysdate - 30
AND o.shipperid <= 15
) o
ON o.employeeid = emp.id
WHERE emp.zipcode = 22151
GROUP BY emp.employeeid, emp.firstname;
由于这正在聚合,因此您也需要group by
子句;对于您实际,更复杂的查询而言,这可能会带来更多问题。
如果由于正在使用o
中其他未满足的数据而无法在更复杂的查询中移动该条件,则可以将条件聚合与更多的case表达式一起使用:
SELECT emp.employeeid, emp.firstname,
CASE
WHEN count(CASE WHEN o.shipperid <= 15 THEN o.shipperid END) > 20 THEN 'Yes'
WHEN count(CASE WHEN o.shipperid <= 15 THEN o.shipperid END) > 10 THEN 'Almost'
ELSE 'No'
END AS "Quota Met"
FROM Employee emp
LEFT JOIN (
SELECT employeeid, shipperid
FROM Orders
WHERE orderdate > sysdate - 30
) o
ON o.employeeid = emp.id
WHERE emp.zipcode = 22151
GROUP BY emp.employeeid, emp.firstname;
您可能仍然希望将其作为外部联接,但如果不只是将其更改回内部联接。
答案 1 :(得分:0)
您无法访问外部子查询,因为您必须重复代码
SELECT emp.employeeid
, emp.firstname
, CASE
WHEN (
SELECT count(*)
FROM (
SELECT employeeid, shipperid
FROM Orders
WHERE orderdate > sysdate - 30
) o
WHERE o.shipperid <= 15
) > 10 THEN 'Almost'
WHEN (
SELECT count(*)
FROM (
SELECT employeeid, shipperid
FROM Orders
WHERE orderdate > sysdate - 30
) o
WHERE o.shipperid <= 15) > 20 THEN 'Yes'
ELSE 'No' END AS "Quota Met"
FROM Em ployee emp
INNER JOIN (
SELECT employeeid, shipperid
FROM Orders
WHERE orderdate > sysdate - 30
) o ON o.employeeid = emp.id
WHERE emp.zipcode = 22151;
如果不想重复代码,则可以使用视图
create my_view as
SELECT employeeid, shipperid
FROM Orders
WHERE orderdate > sysdate - 30
SELECT emp.employeeid
, emp.firstname
, CASE
WHEN (
SELECT count(*)
FROM my_view o
WHERE o.shipperid <= 15
) > 10 THEN 'Almost'
WHEN (
SELECT count(*)
FROM my_view o
WHERE o.shipperid <= 15) > 20 THEN 'Yes'
ELSE 'No' END AS "Quota Met"
FROM Em ployee emp
INNER JOIN my_viewq o ON o.employeeid = emp.id
WHERE emp.zipcode = 22151;