帮助这个SQL查询

问题描述:

后续的查询在143列返回一个错误:“ORA-00934:组功能在这里不允许使用”帮助这个SQL查询

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'的每个实例,而不是最新的。有人能帮我吗?

您不能在非聚合查询中使用聚合函数(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') 

的基本规则是,如果你使用的聚合函数(即最小,最大,平均等),那么所有在select语句中的列必须位于聚合函数或GROUP BY子句的一部分中。即使你有GROUP BY(在这种情况下你不需要做你所需要的),你原来的查询仍然是无效的,因为你不能在WHERE子句中引用聚合函数。要通过聚合函数进行过滤,您需要使用HAVING子句,该子句在聚合结果之后应用(与以前评估的WHERE相反)。


或者,你可以使用ROWNUM和ORDER BY子句来达到同样的效果(主要是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之前,所以你会得到一个半随机的行。

我相信第一个版本会更高效,因为它不需要对结果进行排序。

+0

工作就像一个魅力,谢谢! – Dan 2010-07-13 17:56:48

+0

+1:最佳答案 – 2010-07-13 18:34:58

你可以尝试:

SELECT Top(1) * FROM 
TBLENTITYLOCATION TL INNER JOIN TBLENTITY TE ON TE.ENTITYID = TL.ENTITYID 
WHERE TE.ENTITYNAME = 'foobar' 
ORDER BY LOCATIONDATETIME DESC 
+2

我试过这个,但是它在“TOP”处表示无效标识符。是因为我在使用Oracle吗? – Dan 2010-07-13 17:41:18

+1

TOP只适用于SQL。查看http://windev.wordpress.com/2007/01/17/tip-of-the-day-t-sql-top-n-equivalent-for-oracle-and-mysql/ – Gage 2010-07-13 17:57:00

+1

Oracle不支持TOP语法。最接近这个的是使用ROWNUM,但是你需要将ORDER BY的主要选择嵌套在子查询中,然后在其上应用ROWNUM过滤器,以确保实际上获得最高值。 – Allan 2010-07-13 17:57:53

从where子句中取出MAX(LOCATIONDATETIME),并把它放在你的SELECT子句:

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

而且在SELECT子句添加其他字段选择*是不好的做法

+0

我想到了这一点,但那只会返回DATETIME,而不是foobar的每一列(属性) – Dan 2010-07-13 17:40:58

另外,您可以在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) 
+0

+1 - 击败我; o) – Andrew 2010-07-13 17:38:44

+0

如果来自TBLENTITYLOCATION的最大LOCATIONDATETIME不属于“foobar”实体,该查询将不返回任何行。 – Allan 2010-07-13 17:54:07

+0

好点艾伦 - 你的答案绝对是最好的一个:-) – 2010-07-13 19:00:24

使用MAX在Select语句

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

+0

这是无效的SQL:1)你不能在聚合中使用通配符列; 2)您不能在没有GROUP BY的非聚合列中使用聚合函数; 3)如果不指定表格(即TBLENTITYLOCATION。*),则不能使用带有附加列的通配符列。 – Allan 2010-07-13 17:52:35

您可以按降序对Query进行排序,然后使用第一行。