Помогите с этим запросом SQL - PullRequest
1 голос
/ 13 июля 2010

Следующий запрос возвращает ошибку в столбце 143: «ORA-00934: групповая функция здесь не разрешена»

SELECT * FROM 
TBLENTITYLOCATION TL INNER JOIN TBLENTITY TE ON TE.ENTITYID = TL.ENTITYID 
WHERE TE.ENTITYNAME = 'foobar' 
AND LOCATIONDATETIME = MAX(LOCATIONDATETIME)

Работает нормально, если я уберу последнюю строку - AND LOCATIONDATETIME = MAX(LOCATIONDATETIME), но затем возвращает каждый экземпляр 'foobar' вместо только самого последнего. Кто-нибудь может мне помочь?

Ответы [ 6 ]

7 голосов
/ 13 июля 2010

Вы не можете использовать агрегатную функцию (max) в неагрегированном запросе. То, что вы хотите, это что-то вроде этого:

SELECT * 
FROM TBLENTITYLOCATION TL 
INNER JOIN TBLENTITY TE 
ON TE.ENTITYID = TL.ENTITYID 
WHERE TE.ENTITYNAME = 'foobar' 
AND LOCATIONDATETIME = (select MAX(LOCATIONDATETIME)
                        FROM TBLENTITYLOCATION TL 
                        INNER JOIN TBLENTITY TE 
                        ON TE.ENTITYID = TL.ENTITYID 
                        WHERE TE.ENTITYNAME = 'foobar')

Основное правило заключается в том, что если вы используете агрегатные функции (т. Е. Min, max, avg и т. Д.), То все столбцы в операторе select должны быть в агрегатной функции или части GROUP BY. пункт. Даже если бы у вас была функция GROUP BY (которая в данном случае не делала бы то, что вам нужно), ваш исходный запрос все равно был бы недействительным, потому что вы не можете ссылаться на агрегатные функции в предложении WHERE. Для фильтрации по статистической функции необходимо использовать предложение HAVING, которое применяется после агрегирования результатов (в отличие от WHERE, который оценивался ранее).


С другой стороны, вы можете использовать ROWNUM и предложение ORDER BY для достижения того же результата (по сути, версия TOP для Oracle):

select *
from (SELECT tl.*, te.*, rownum as rn 
      FROM TBLENTITYLOCATION TL 
      INNER JOIN TBLENTITY TE 
      ON TE.ENTITYID = TL.ENTITYID 
      WHERE TE.ENTITYNAME = 'foobar'
      ORDER BY LOCATIONDATETIME DESC)
where rn = 1

Может показаться, что вы можете свернуть это в один выбор, но это иллюзия. Если вы сделаете это, критерии ROWNUM будут применены до ORDER BY, поэтому вы получите полуслучайную строку.

Я считаю, что первая версия будет более эффективной, так как не требует сортировки результатов.

4 голосов
/ 13 июля 2010

В качестве альтернативы вы можете использовать подзапрос в предложении WHERE, например:

SELECT * FROM 
TBLENTITYLOCATION TL INNER JOIN TBLENTITY TE ON TE.ENTITYID = TL.ENTITYID 
WHERE TE.ENTITYNAME = 'foobar' 
AND LOCATIONDATETIME = (SELECT MAX(LOCATIONDATETIME) FROM TBLENTITYLOCATION)
3 голосов
/ 13 июля 2010

Вы можете попробовать:

SELECT Top(1) * FROM  
TBLENTITYLOCATION TL INNER JOIN TBLENTITY TE ON TE.ENTITYID = TL.ENTITYID  
WHERE TE.ENTITYNAME = 'foobar'  
ORDER BY LOCATIONDATETIME DESC
0 голосов
/ 13 июля 2010

Вы можете отсортировать запрос по убыванию, а затем просто использовать первую строку.

0 голосов
/ 13 июля 2010

Используйте МАКС в операторе выбора

SELECT *, MAX (LOCATIONDATETIME) ОТ TBLENTITYLOCATION TL INNER ПРИСОЕДИНЯЙТЕСЬ К TBLENTITY TE НА TE.ENTITYID = TL.ENTITYID ГДЕ TE.ENTITYNAME = 'foobar'

0 голосов
/ 13 июля 2010

Извлеките MAX (LOCATIONDATETIME) из предложения where и поместите его в предложение select:

SELECT MAX (LOCATIONDATETIME) ИЗ TBLENTITYLOCATION TL INNER Присоединитесь к TBLENTITY TE на TE.ENTITYID = TL.ENTITYID WHERE TE.ENTITYNAME = 'foobar'

Также добавьте другие поля в предложение select, так как выбор * является плохой практикой

...