2

我正在通过 GALAXQL http://sol.gfxile.net/galaxql.html学习 SQL

我在第 17 课 - GROUP BY/HAVING

这是场景:

让我们看一下我们尚未涉及的几个 SELECT 操作,即 GROUP BY 和 HAVING。

这些操作的语法如下所示:

SELECT columns FROM table GROUP BY column HAVING expression

SELECT 中的 GROUP BY 命令将多个输出行合并为一行。例如,如果我们希望将新的统计数据生成为表格,这将非常有用。

例如,要找出每个类别的恒星的最高强度,我们会这样做:

Select Class, Max(Intensity) As Brightness From Stars Group By Class Order By Brightness Desc

HAVING 运算符的工作方式与 WHERE 几乎相同,只是它是在分组完成后应用的。因此,我们可以计算每个类别的亮度总和,并裁剪出总和高于 150 的类别。

SELECT class, SUM(intensity) AS brightness FROM stars GROUP BY class HAVING brightness < 150 ORDER BY brightness DESC

我们可以引用 HAVING 子句中未选择的列,但结果可能难以理解。您应该能够在 HAVING 子句中使用聚合函数(例如,brightness < MAX(brightness)*0.5,但这似乎会使当前版本的 SQLite 崩溃。

当与联接结合使用时,GROUP BY 变得相当方便。要找出每颗恒星的行星数量,我们可以这样做:

SELECT stars.starid AS starid, COUNT(planets.planetid) AS planet_count FROM planets, stars WHERE stars.starid=planets.starid GROUP BY stars.starid

突出显示轨道最多的恒星(行星和卫星组合)。(请注意,验证查询有些繁重,因此请在按下“Ok, I'm done..”后耐心等待)。


这是我的答案

SELECT stars.starid AS HighStar, 
(COUNT(planets.planetid) + COUNT(moons.moonid)) AS OrbitalsTotal 
FROM stars
LEFT OUTER JOIN planets
ON stars.starid = planets.starid
LEFT OUTER JOIN moons
ON planets.planetid = moons.planetid
GROUP BY stars.starid
ORDER BY OrbitalsTotal DESC;

这个查询告诉我,拥有最多轨道的恒星有 170 个轨道

那么:

INSERT INTO hilight SELECT result.HighStar
FROM result
INNER JOIN stars
ON result.HighStar = stars.starid
WHERE result.OrbitalsTotal = 170

我的问题是我怎样才能使这个查询更好?我不想对 170 个轨道进行硬编码,也不想创建第二个查询来插入数据。

4

5 回答 5

1
SELECT stars.starid AS HighStar, 
       (COUNT(planets.planetid) + COUNT(moons.moonid)) AS OrbitalsTotal 
FROM stars
     LEFT OUTER JOIN
     planets ON stars.starid = planets.starid
     LEFT OUTER JOIN
     moons ON planets.planetid = moons.planetid
GROUP BY stars.starid
HAVING OrbitalsTotal = (SELECT MAX(Orbitals)
                        FROM (SELECT (COUNT(planets.planetid) + COUNT(moons.moonid)) Orbitals
                              FROM stars
                                   LEFT OUTER JOIN
                                   planets ON stars.starid = planets.starid
                                   LEFT OUTER JOIN
                                   moons ON planets.planetid = moons.planetid
                              GROUP BY stars.starid))
于 2013-08-27T00:20:50.900 回答
1

只需使用您的第一个查询,并添加子句LIMIT 1以仅返回第一条记录:

INSERT INTO hilight
SELECT stars.starid AS HighStar
FROM stars
LEFT OUTER JOIN planets
ON stars.starid = planets.starid
LEFT OUTER JOIN moons
ON planets.planetid = moons.planetid
GROUP BY stars.starid
ORDER BY COUNT(planets.planetid) + COUNT(moons.moonid) DESC
LIMIT 1
于 2013-08-27T07:45:53.800 回答
1

恒星 22336 没有 170 个轨道。

它有 97 个轨道。

检查月亮的数量。

SELECT COUNT(moons.moonid) as moon_count
FROM stars JOIN planets
ON stars.starid=planets.starid
JOIN moons
ON planets.planetid=moons.planetid
WHERE stars.starid=22336

这给出了 79 个卫星。

现在检查行星的数量。

SELECT COUNT(planets.planetid) AS planet_count
FROM stars JOIN planets
ON stars.starid=planets.starid
WHERE stars.starid=22336

这给出了 18 个行星。

下面的 SQL 正确计算轨道计数并完成任务。

INSERT INTO hilight
SELECT pc.starid FROM

(SELECT p.starid, COUNT(p.planetid) AS p_count
FROM planets AS p
GROUP BY p.starid) AS pc

JOIN

(SELECT p.starid, COUNT(m.moonid) AS m_count
FROM planets AS p JOIN moons AS m
ON p.planetid=m.planetid
GROUP BY p.starid) AS mc

ON pc.starid=mc.starid

ORDER BY p_count+m_count DESC
LIMIT 1
于 2015-12-31T08:43:47.070 回答
0

到 GalaXQL 的第 17 章,我们还没有学习 LIMIT,我认为我们可以在没有所有 LEFT OUTER JOINS 的情况下做到这一点(借用 Dale M 的(虽然它仍然有效但在“Orbitals”之前缺少“AS”?!))更接近我们在该部分的最后一个示例中看到的内容。

那么怎么样:

DELETE FROM hilight;
INSERT INTO hilight 
SELECT HighStar FROM (
    SELECT stars.starid AS HighStar, 
        (COUNT(planets.planetid) + COUNT(moons.moonid)) AS OrbitalsTotal 
    FROM stars, planets, moons 
    WHERE stars.starid = planets.starid
        AND planets.planetid = moons.planetid
    GROUP BY stars.starid
    HAVING OrbitalsTotal = (
        SELECT MAX(Orbitals) FROM (
            SELECT (COUNT(planets.planetid) + COUNT(moons.moonid)) AS Orbitals
            FROM stars, planets, moons
            WHERE stars.starid = planets.starid
                AND planets.planetid = moons.planetid
            GROUP BY stars.starid))
);
SELECT * FROM hilight;

使用 LIMIT,我们还可以避免 LEFT OUTER JOIN,而不必重复我们的选择:

DELETE FROM hilight;
INSERT INTO hilight
SELECT bodygroup FROM (
    SELECT stars.starid as bodygroup, 
        (COUNT(planets.planetid)+COUNT(moons.moonid)) AS bodycount
    FROM stars, planets, moons 
    WHERE stars.starid=planets.starid 
        AND planets.planetid=moons.planetid 
    GROUP BY stars.starid
    ORDER BY bodycount DESC) 
LIMIT 1;
SELECT * FROM hilight;

或者使用 CREATE VIEW 来避免在不使用 LIMIT 的情况下加倍努力,我们可以:

DELETE FROM hilight;    
CREATE VIEW bodyview AS
    SELECT stars.starid as bodygroup,
        (COUNT(planets.planetid)+COUNT(moons.moonid)) AS bodycount
    FROM stars, planets, moons
    WHERE stars.starid=planets.starid
       AND planets.planetid=moons.planetid
    GROUP BY stars.starid
    ORDER BY bodycount DESC;
INSERT INTO hilight SELECT bodygroup FROM bodyview  
    WHERE bodycount = (SELECT MAX(bodycount) FROM bodyview );
DROP VIEW bodyview;
SELECT * FROM hilight;
于 2014-08-12T22:43:05.257 回答
0

如果你开始你的第一个查询,SELECT TOP(1) ...那么这只会给你第一个结果。该TOP()语法可以与给出那么多行的硬数字或给出总数百分比的百分比一起使用。

于 2013-08-26T23:05:55.327 回答