Как коррелированный подзапрос внутри SELECT CASE WHEN может получить доступ к псевдониму внешней таблицы? - PullRequest
0 голосов
/ 01 марта 2019

Я использую Oracle 12. Я придумал упрощенный пример, чтобы попытаться передать проблему, с которой я сталкиваюсь, поскольку фактический запрос слишком сложен, чтобы представлять его здесь.Этот упрощенный пример содержит те же условия и логику, что и сложный запрос.Я надеюсь найти способ для подзапроса, который находится в WHEN в основном SELECT, для доступа к псевдониму таблицы, который определен из внутреннего соединения, которое находится на том же уровне, что и основной 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, как показано ниже, но в реальном запросе блок 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;

Является ли эта версия СО действительно лучшим решением?Есть ли способ переписать первую версию INNER JOIN, чтобы подзапрос в CASE WHEN мог получить доступ к псевдониму объединенной таблицы?

Ответы [ 2 ]

0 голосов
/ 01 марта 2019

Вам не нужны подзапросы;если вы переместите чек 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, где это не выполняется,тогда вы можете использовать условное агрегирование с другими выражениями:

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;

Вы все еще можете захотеть, чтобы это было внешнее соединение, но если не просто изменить его обратно на внутреннее.

0 голосов
/ 01 марта 2019

Вы не можете получить доступ к внешнему подзапросу как к таблице, вы должны повторить код

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;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...