How to use MAX() on a subquery result?

放肆的年华 提交于 2020-08-21 08:58:54

问题


I am new to Oracle and the SQL world. I have a slight issue with a query that I cannot figure out for the life of me, I have spent a few hours trying different approaches and I cannot get the result I expect. So heres my query:

SELECT *
from(Select membership.mem_desc,membership.mem_max_rentals,membership_history.mem_type,      
    count(membership_history.MEM_TYPE) as membership_count
    from membership_history
    JOIN membership ON membership.mem_type = membership_history.mem_type
    group by (membership_history.mem_type,membership.mem_desc,membership.mem_max_rentals)
    ) g
WHERE g.membership_count = (select MAX(membership_count) from g); 

So the inner query works perfectly and returns two results. Now that I have these two values I am trying to figure out how to return the row with the maximum value of membership_count which Is where I keep getting stuck. In the above query I tried using the MAX() in the where clause but inside that select I keep getting the error 'table not found'(meaning 'g'). So my question is how do I use the MAX() function on the results of my subquery? Any thoughts or suggestions would be greatly appreciated!!!!!


回答1:


You don't need the subquery that finds the maximum value.
Instead, ; you just need the first row after having ordered the rows:

select * from (
  select 
    membership.mem_desc,
    membership.mem_max_rentals,
    membership_history.mem_type,      
    count(membership_history.MEM_TYPE) as membership_count
  from membership_history
  JOIN membership ON membership.mem_type = membership_history.mem_type
  group by (membership_history.mem_type,membership.mem_desc,membership.mem_max_rentals)
  ORDER BY 4 DESC  -- Added this line
) g
WHERE ROWNUM = 1. -- Added this line



回答2:


This is all good SQL.

The best way to find a column value using the max primary key column value is:

SELECT .... from tablename
WHERE ... AND
  (SELECT max(primary key name) FROM tablename WHERE .... ) = primary_key_name

this example will return a scalar value.




回答3:


I have had a similar issue within an Access Query ... based on some of the comments in this thread, are we to understand that the ACCESS MAX function should only be used on/with Primary Key Fields? ... basically, I have a table that defines Addresses relating to an Entity, BUT, with a slight twist; 1) once saved, no record is allowed to be deleted or changed (meaning an Entity could have multiple address Records), 2) any current Entity Address can either have; HOME (1 Record) or HOME and MAIL (2 records) ... each Address record has an (ID) (autonumber Primary KEY) a HOME ID (HID) matching the HOME record's (ID) (HID is NOT a Primary KEY and is NOT unique) and an Entity ID (EID) ... so ... when I attempt to use a sub-query to get the max(HID) value for a given Entity, I only want the current Address returned ... what I found by using MAX in a sub-query is it either fails to run because ACCESS incorrectly thinks it has too many matching records for the sub-query ... or ... it incorrectly returns rows it shouldn't be returning.

The only way I found to get around this issue was to replace the max sub-query with a Max Function which returns the MAX HID Value for an Entity (the function uses the sub-query statement with DAO logic within VBA)

Here is the HOME sub-query which is part of the main Query (the main query needs to return one row per entity as; EID, Home.Address, Mail.Address)

Select *
From tbAddresses As tba1
Where tba1.aType = "Home"
  And tba1.HID = (Select MAX(tba2.HID) 
                      From tbAddresses As tba2 
                     Where tba1.EID = tba2.EID)

The main query only works properly when the Where clauses both Home and Mail (not shown) are replaced with the function below. If the MAX sub-query is included as above, it doesn't work.

So if the MAX function requires a PRIMARY KEY field to work, this might explain why my queries are failing, although, that would sound like a major limitation.

Where tba1.HID = fnGetMaxHID(tba1.EID) 

Here is some test data which should only return 3 rows

ID    HID    EID   aType  Address
 1      1    100   Home   Blah 1
 2      2    101   Home   Blah 2
 3      2    101   Mail   PO Box Blah 0
 4      4    102   Home   Blah 3
 5      5    101   Home   Blah 4

One last note, several versions of Access Pro; 2002, 2003, 2016 were tested and all produce the same results. So this issue is either an inherent quirk of the max function or some kind of bug which has possibly been ignored or gone unnoticed? ... the function works as a workaround for me but may not work for others so would be nice if the MAX function was clarified.




回答4:


You could try something like

 SELECT membership.mem_desc,membership.mem_max_rentals,membership_history.mem_type, membership_count, rank() over ORDER BY membership_count DESC as ranky
from
(Select membership.mem_desc,membership.mem_max_rentals,membership_history.mem_type,      
count(membership_history.MEM_TYPE) as membership_count
from membership_history
JOIN membership ON membership.mem_type = membership_history.mem_type
group by (membership_history.mem_type,membership.mem_desc,membership.mem_max_rentals)
) 
WHERE ranky =1;



回答5:


You cannot use a derived table directly in where clause it will give table or view does not exist error so to get the max count value you can use HAVING clause or Analytical Functions or Rownum like

select * from
      (Select membership.mem_desc,membership.mem_max_rentals,membership_history.mem_type,      
      count(membership_history.MEM_TYPE) as membership_count
      from membership_history a
      JOIN membership b ON b.mem_type = a.mem_type
      group by (membership_history.mem_type,membership.mem_desc,membership.mem_max_rentals)
      having count(a.MEM_TYPE) = (Select      
      MAX(count(a.MEM_TYPE)) from membership_history a
      JOIN membership b ON b.mem_type = a.mem_type
      group by (a.mem_type,b.mem_desc,b.mem_max_rentals)));

(OR)

select * from
(SELECT g.*,rank() over (order by membership_count desc) rnk from
      (Select membership.mem_desc,membership.mem_max_rentals,membership_history.mem_type,      
      count(membership_history.MEM_TYPE) as membership_count
      from membership_history
      JOIN membership ON membership.mem_type = membership_history.mem_type
      group by (membership_history.mem_type,membership.mem_desc,membership.mem_max_rentals)) g)
WHERE rnk=1;

(OR)

select * from
(SELECT g.*,rownum rn from
      (Select membership.mem_desc,membership.mem_max_rentals,membership_history.mem_type,      
      count(membership_history.MEM_TYPE) as membership_count
      from membership_history
      JOIN membership ON membership.mem_type = membership_history.mem_type
      group by (membership_history.mem_type,membership.mem_desc,membership.mem_max_rentals)
      order by membership_count desc) g)
WHERE rn=1;



回答6:


I think the cleanest solution is to use the ALL comparison condition. It is used to compare a value to a list or subquery.

SELECT 
  m.mem_desc,
  m.mem_max_rentals,
  mh.mem_type,      
  COUNT(mh.mem_type) as membership_count
FROM membership_history mh
JOIN membership m ON m.mem_type = mh.mem_type
GROUP BY mh.mem_type,m.mem_desc,m.mem_max_rentals
HAVING membership_count >= ALL (
  SELECT count(*)
  FROM membership_history
  GROUP BY mem_type
)   



回答7:


Here, an aggregate may not appear in the WHERE clause unless it is in a subquery contained in a HAVING clause or a select list, and the column being aggregated is an outer reference in SQL Server.

For the demonstration, we have a table named ‘Info’ with some records.

--Select records from info
SELECT * FROM INFO

ScreenShot

enter image description here

Problem Statement: Find all the details of INFO for the max id.

SELECT * FROM INFO WHERE ID = MAX(ID)

When he executed the above script it gave him the following error:

Message 147, Level 15, State 1, Line 3
The aggregate may not appear in the WHERE clause unless it is in a subquery contained in a HAVING clause or a select list, and the column being aggregated is an outer reference.

He was not able to resolve this problem, even though the solution was given in the query description itself.

Due to a lack of experience, he came up with another version of the above query based on the error message.

SELECT * FROM INFO HAVING ID = MAX(ID)

Message 8121, Level 16, State 1, Line 1
Column 'INFO.id' is invalid in the HAVING clause because it is not contained in either an aggregate function or the GROUP BY clause.

What he wanted actually was the table INFO max value of ID. Based on the problem statement what the right solution is as following, which does not generate an error.

SELECT * FROM INFO WHERE ID = (SELECT MAX(ID) FROM INFO)

ScreenShot

enter image description here



来源:https://stackoverflow.com/questions/16182700/how-to-use-max-on-a-subquery-result

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!