繁体   English   中英

SQL - 查询 - max(count())

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

我正在攻读我的数据库系统考试(明天),我在练习中遇到麻烦,我被要求编写查询。 这是一个例子:

在此输入图像描述

我被要求写一个查询来回答以下问题:年龄最低的作者中,谁写的书最多?

问题是我的老师禁止我在FROM子句中使用子查询,并使用TOP

我写了一个答案,但我知道的是不正确的:

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

这个给所有作者提供较低的年龄,以及他们各自的书籍数量(我希望......)。 正确的答案应该只是这一行的第一行。

让我说清楚一下:

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

(注意肖恩没有写任何书,第6本书有2位作者,而里克是大多数书籍的作者(4))

现在,我上面写的代码给出了这个结果(我猜):

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

(最低年龄为25岁,Lena和John均为25岁)

问的是:

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

(Lena是作者,所有年龄最小的作者(25),大多数书籍都写过)

提前致谢

因为你是学生,我会回答部分问题。 这是一个答案,忽略了最年轻的部分:

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
                      )

我想你可以弄清楚如何修改它。

顺便说一句,我希望, limittop的限制只适用于这个例子。 否则,你应该得到另一位老师,因为这些是非常重要的结构。

此外,你需要学习传统的连接语法,而不是,from子句。 再一次,如果你的老师没有教授现代化的sytnax(自1988年左右起),请找一位新老师。 并且,我假设对子查询的限制也适用于CTE。

我还想指出查询的“正确”版本:

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

此查询几乎可以在任何维度上比上面的查询更好。 它做一个join ,一个group by和一个group by 我查询的完整版本做了两join小号明确,两名join小号隐含(年龄条款),两个group by秒。 前者的表现要比后者好。

从可读性的角度来看,这个版本更短更清洁。 我也认为教这是做什么要容易得多,而不是第一版中的“不寻常”结构。 大多数学生将了解toporder by正在做什么,并可以模仿这一点。 模仿,在发生的事情having条款要求一些心理体操。

如果你想得到所有作者的最大数量,首先要意识到前面的查询相当于:

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

切换这个以获得所有作者很容易:

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

这也比回答问题的查询更有效。 无法在from子句中使用top或子查询就像是在进行三条腿竞赛。 是的,你可以到达那里,但是你可以用自己的两条腿跑得更快。

这是一些限制,但它使人们利用它的创造力。

所以你想要最年轻的作家之一,写了一些高于(或等于)其他最年轻作家的书籍的书籍......

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:不得不承认,我了解ALL戈登·利诺夫

如果您只想要一个结果,请选择一个结果,然后排序应该完成剩下的工作。 我个人会做一个排名函数,使用Aggregate()Over()窗口函数显式获得排名。 但是既然你正在学习,也许他们不想提出这个问题并向你展示“顶级”是如何运作的。

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

据我所知,你只想要一行;

您可以先限制作者,然后使用内部联接,您可以从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

如果你被允许使用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小提琴

演示约翰写另一本书的地方

暂无
暂无

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

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