SQL — использование значения во вложенном выборе

#sql #oracle #nested

#sql #Oracle #вложенный

Вопрос:

Надеюсь, название имеет какой-то смысл — в принципе, я хотел бы выполнить вложенный выбор на основе значения в исходном выборе, вот так:

 SELECT MAX(iteration) AS maxiteration,
       (SELECT column
        FROM   table
        WHERE  id = 223652
               AND iteration = maxiteration)
FROM   table
WHERE  id = 223652;  
  

Я получаю ошибку недопустимого идентификатора ORA-00904.

Был бы очень признателен за любой совет о том, как вернуть это значение, спасибо!

Комментарии:

1. Можете ли вы опубликовать полное сообщение об ошибке?

2. Так много замечательных ответов, спасибо вам, ребята!

Ответ №1:

Похоже, это должно быть переписано с помощью предложения where:

 select iteration,
       col
from tbl
where id = 223652
and iteration = (select max(iteration) from tbl where id = 223652);
  

Комментарии:

1. 1 : Моя предпочтительная версия, но я бы изменил 2-й экземпляр 223652 , чтобы ссылаться на идентификатор из внешнего запроса. (Но также потребуется, чтобы одному экземпляру tbl был присвоен псевдоним.)

Ответ №2:

Вы можете полностью обойти проблему, поместив подвыборку в INNER JOIN свою собственную.

 SELECT t.iteration
       , t.column
FROM   table t
       INNER JOIN (
         SELECT id, MAX(iteration) AS iteration
         FROM   table
         WHERE  id = 223652
       ) tm ON tm.id = t.id AND tm.iteration = t.iteration
  

Комментарии:

1. Потому что немногие СУБД допускают использование псевдонима агрегатной функции в качестве ссылки в коррелированном подзапросе. Если бы это было разрешено, был бы каскад зависимостей (коррелированный результат подзапроса мог быть использован в другом коррелированном подзапросе). И это может даже привести к циклическим ссылкам и другим сложностям. Итак, в общем, это просто не разрешается. (Ответ Дэниела Хилгарта — это обходной путь, наиболее точно соответствующий ответу OP.)

Ответ №3:

Поскольку вы используете Oracle, я бы предложил использовать для этого аналитические функции:

 SELECT * FROM (
    SELECT col,
      iteration,
      row_number() over (partition by id order by iteration desc) rn
    FROM tab
    WHERE  id = 223652
) WHERE rn = 1
  

Ответ №4:

сделайте это следующим образом:

 with maxiteration as
(
    SELECT MAX(iteration) AS maxiteration
    FROM   table
    WHERE  id = 223652
)
select
    column, 
    iteration
from
    table
where
    id = 223652
    AND iteration = maxiteration
;
  

Ответ №5:

Не уверен на 100% в синтаксисе Oracle, но разве это не что-то вроде:

 select iteration, column from table where id = 223652 order by iteration desc limit 1
  

Ответ №6:

Я бы подошел к этой проблеме немного по-другому. По сути, вы ищете строку, у которой нет других итераций, превышающих ее. Я могу придумать как минимум 3 способа сделать это:

 SELECT
    T1.iteration AS maxiteration,
    T1.column
FROM
    Table T1
WHERE
    T1.id = 223652 AND
    NOT EXISTS
    (
        SELECT *
        FROM Table T2
        WHERE
            T2.id = 223652 AND
            T2.iteration > T1.iteration
    )
  

Или…

 SELECT
    T1.iteration AS maxiteration,
    T1.column
FROM
    Table T1
LEFT OUTER JOIN Table T2 ON
    T2.id = T1.id AND
    T2.iteration > T1.iteration
WHERE
    T1.id = 223652 AND
    T2.id IS NULL
  

Или…

 SELECT
    T1.iteration AS maxiteration,
    T1.column
FROM
    Table T1
INNER JOIN (SELECT id, MAX(iteration) AS maxiteration FROM Table T2 GROUP BY id) SQ ON
    SQ.id = T1.id AND
    SQ.maxiteration = T1.iteration
WHERE
    T1.id = 223652
  

РЕДАКТИРОВАТЬ: я не увидел ошибку ORA при первом чтении вопроса, и она не была помечена как специфичная для Oracle. Я думаю, что могут быть некоторые различия в синтаксисе и использовании псевдонимов в Oracle, поэтому вам может потребоваться настроить некоторые из приведенных выше запросов.

Ошибка Oracle сообщает вам, что он не знает, что такое maxiteration, поскольку псевдоним столбца пока недоступен внутри подзапроса. Вам нужно ссылаться на него с помощью псевдонима таблицы и имени столбца вместо псевдонима столбца, который я полагаю.

Ответ №7:

Вы делаете что-то вроде

 select maxiteration,column from table a join (select max(iteration) as maxiteration from table where id=1) b using (id) where b.maxiteration=a.iteration;
  

Это, конечно, может возвращать несколько строк для одного maxiteration, если в вашей таблице нет ограничения на это.