简体   繁体   English

SQL - 查询 - max(count())

[英]SQL - Query - max(count())

I'm studying for my Database Systems Exam (tomorrow) and I'm having trouble in exercises where I'm asked to write queries. 我正在攻读我的数据库系统考试(明天),我在练习中遇到麻烦,我被要求编写查询。 Here's an example: 这是一个例子:

在此输入图像描述

I am being asked to write a query to answer the following question: Among the authors with lowest Age, who has most books written? 我被要求写一个查询来回答以下问题:年龄最低的作者中,谁写的书最多?

The problem is my teacher forbids me to use sub-queries inside FROM clause, and to use TOP . 问题是我的老师禁止我在FROM子句中使用子查询,并使用TOP

I have written an answer, but one I know is incorrect: 我写了一个答案,但我知道的是不正确的:

SELECT W.AName, COUNT(W.ID_B) AS NBooks
FROM Write W, Author A1
WHERE (A1.AName = W.AName) AND
      (A1.AAge = (SELECT MIN(A2.Age)
                  FROM Author A2))
GROUP BY W.AName
ORDER BY NBooks DESC

This one gives all the authors with the lower age, and their respective number of books written (I hope..). 这个给所有作者提供较低的年龄,以及他们各自的书籍数量(我希望......)。 The correct answer should be only the first line of this one. 正确的答案应该只是这一行的第一行。

Let me be clear: 让我说清楚一下:

Table Author
AName    | AAge
---------------
John     | 25
Rick     | 30
Sean     | 26
Lena     | 25

Table Writes
AName    | ID_B
---------------
John     | 2
Lena     | 1
John     | 3
Lena     | 4
Rick     | 5
Rick     | 6
Lena     | 6
Rick     | 7
Rick     | 8

(notice that Sean did't write any book, book nº6 has 2 authors, and Rick is the author with most books (4) ) (注意肖恩没有写任何书,第6本书有2位作者,而里克是大多数书籍的作者(4))

Now, the code I wrote above gives this result (I guess): 现在,我上面写的代码给出了这个结果(我猜):

AName    | NBooks
-----------------
Lena     | 3
John     | 2

(The lowest age is 25 and both Lena and John are 25) (最低年龄为25岁,Lena和John均为25岁)

Whats asked is: 问的是:

AName    | NBooks
-----------------
Lena     | 3

(Lena is the Author, among all the authors with the lowest age (25), with most books written) (Lena是作者,所有年龄最小的作者(25),大多数书籍都写过)

Thanks in advance 提前致谢

Because you are a student, I'll answer part of the question. 因为你是学生,我会回答部分问题。 Here is an answer, ignoring the youngest part: 这是一个答案,忽略了最年轻的部分:

select a.AName, COUNT(*) as NumBooks
from Author a join
     Write w
     on a.AName = w.AName
group by a.AName
having count(*) >= all(select COUNT(*) as NumBooks
                       from write w
                       group by w.AName
                      )

I think you can figure out how to modify it. 我想你可以弄清楚如何修改它。

By the way, the restriction on limit and top is, I hope, only for this example. 顺便说一句,我希望, limittop的限制只适用于这个例子。 Otherwise, you should get another teacher, since these are very important constructs. 否则,你应该得到另一位老师,因为这些是非常重要的结构。

Also, you need to learn conventional join syntax, rather than , in the from clause. 此外,你需要学习传统的连接语法,而不是,from子句。 Once again, if you teacher is not teaching the modern sytnax (since about 1988), get a new teacher. 再一次,如果你的老师没有教授现代化的sytnax(自1988年左右起),请找一位新老师。 And, I assume the restriction on subqueries applies to CTEs as well. 并且,我假设对子查询的限制也适用于CTE。

I also want to point out the "correct" version of the query: 我还想指出查询的“正确”版本:

select top 1 a.aname, count(*) as NumBooks
from Author a join
     Write w
     on a.AName = w.AName
group by author.name, author.Aage
order by author.Age asc, count(*) desc

This query is better than the query above along almost any dimension. 此查询几乎可以在任何维度上比上面的查询更好。 It does one join , one group by and one sort. 它做一个join ,一个group by和一个group by The complete version of my query does two join s explicitly, two join s implicitly (the age clause), and two group by s. 我查询的完整版本做了两join小号明确,两名join小号隐含(年龄条款),两个group by秒。 The former is going to have better performance than the latter. 前者的表现要比后者好。

From a readability perspective, this version is shorter and cleaner. 从可读性的角度来看,这个版本更短更清洁。 I also think that it is much easier to teach what this is doing, rather than the "unusual" constructs in the first version. 我也认为教这是做什么要容易得多,而不是第一版中的“不寻常”结构。 Most students will understand what top and order by are doing and can emulate this. 大多数学生将了解toporder by正在做什么,并可以模仿这一点。 Mimicking what happens in that having clause requires some mental gymnastics. 模仿,在发生的事情having条款要求一些心理体操。

If you want to get all the authors with the maximum count, the first thing is to realize that the previous query is equivalent to: 如果你想得到所有作者的最大数量,首先要意识到前面的查询相当于:

select aname, NumBooks
from (select a.aname, count(*) as NumBooks,
             row_number() over (partition by author.Name order by a.aAge, count(*) desc) as seqnum
      from Author a join
           Write w
           on a.AName = w.AName
      group by author.name, author.Aage
     ) aw
where seqnum = 1

Switching this to get all the authors is easy: 切换这个以获得所有作者很容易:

select aname, NumBooks
from (select a.aname, count(*) as NumBooks,
             dense_rank() over (partition by author.Name order by a.aAge, count(*) desc) as seqnum
      from Author a join
           Write w
           on a.AName = w.AName
      group by author.name, author.Aage
     ) aw
where seqnum = 1

This is also more efficient than the query that answers the question. 这也比回答问题的查询更有效。 Not being able to use top or subqueries in the from clause is like running a three-legged race. 无法在from子句中使用top或子查询就像是在进行三条腿竞赛。 Yes, you can probably get there, but you'll get there much faster running on your own two legs. 是的,你可以到达那里,但是你可以用自己的两条腿跑得更快。

This is some restriction, but it makes one use it's creativity. 这是一些限制,但它使人们利用它的创造力。

So you want one of the youngest authors, that has written a number of books that is higher than (or equal to) any other number of books written by another of the youngest authors... 所以你想要最年轻的作家之一,写了一些高于(或等于)其他最年轻作家的书籍的书籍......

SELECT
  [a1].[AName],
  [a1].[AAge],
  COUNT(*) AS [NBooks]
FROM [Author] [a1], [Writes] [w1]
WHERE 
  [a1].[AName] = [w1].[AName]
  AND [a1].[AAge] = (SELECT MIN([a2].[AAge]) FROM [Author] [a2])
GROUP BY 
  [a1].[AName],
  [a1].[AAge]
HAVING COUNT(*) >= ALL
  (SELECT
    COUNT(*) AS [NBooks]
  FROM [Author] [a3], [Writes] [w2]
  WHERE 
    [a3].[AName] = [w2].[AName]
    AND [a3].[AAge] = (SELECT MIN([a4].[AAge]) FROM [Author] [a4])
    AND [a3].[AName] <> [a1].[AName]
  GROUP BY 
    [a3].[AName],
    [a3].[AAge])

PS: Got to admit, I learned about ALL from Gordon Linoff . PS:不得不承认,我了解ALL戈登·利诺夫

If you only want one result select a top one and the ordering should do the rest. 如果您只想要一个结果,请选择一个结果,然后排序应该完成剩下的工作。 I personally would do a ranking function to explicitly get rankings using the Aggregate() Over() windowed function. 我个人会做一个排名函数,使用Aggregate()Over()窗口函数显式获得排名。 But since you are learning maybe they don't want to bring that up yet and show you how the 'top' works. 但是既然你正在学习,也许他们不想提出这个问题并向你展示“顶级”是如何运作的。

declare @Person Table ( personID int identity, person varchar(8), age int);

insert into @Person values ('Brett', 34),('John', 34),('Peter', 52);

declare @Books Table ( BookID int identity, personID int);

insert into @Books values (1),(1),(1),(2),(2),(3)

Select top 1 -- TOP WILL LIMIT TO CHOICE YOU WANT BASED ON ORDER BY CLAUSE
    p.person
,   p.age
,   count(b.BookID) as cnts
from @Person p, @Books b
where p.personID = b.personID
group by p.person, p.age
order by age, cnts desc

I understand that you just want 1 row as a result; 据我所知,你只想要一行;

You could limit the Author first and then by using inner join you could retrieve his name and book count from Write table. 您可以先限制作者,然后使用内部联接,您可以从Write表中检索他的名字和书籍数量。

SELECT W.AName, COUNT(W.ID_B) AS NBooks
FROM Write W INNER JOIN Author A1 ON A1.AName = W.AName
WHERE 
A1.AName = (SELECT AName FROM Write GROUP BY AName ORDER BY COUNT(ID_B) DESC)
AND A1.AAge = (SELECT MIN(A2.Age) FROM Author A2)
GROUP BY W.AName
ORDER BY NBooks DESC

If you're allowed to use CTE's and RANK its trival. 如果你被允许使用CTE和RANK它的繁琐。

WITH cte 
     AS (SELECT a.aname, 
                A.aage, 
                Count(id_b)                             Book_Count, 
                RANK() 
                  OVER( 
                    ORDER BY a.aage, Count(id_b) DESC ) rn 
         FROM   author a 
                INNER JOIN writes w 
                        ON a.aname = w.aname 
         GROUP  BY a.aname, 
                   a.aage) 
SELECT aname, 
       Book_Count
FROM   cte 
WHERE  rn = 1 

SQL Fiddle SQL小提琴

Demo Where John writes another book 演示约翰写另一本书的地方

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM