【问题标题】:How can I make this query better?我怎样才能使这个查询更好?
【发布时间】:2013-08-29 13:06:02
【问题描述】:

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

我在第 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 子句中使用聚合函数(例如, 亮度

当与联接结合使用时,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

突出显示轨道最多的恒星(行星和卫星组合)。 (请注意,验证查询有些繁重,请耐心等待 按“好的,我完成了..”)。


这是我的答案

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 个轨道进行硬编码,也不想创建第二个查询来插入数据。

【问题讨论】:

  • 奇怪的是,回答问题的最佳方式不是使用having子句。 SQLite 是否支持派生表,即带有别名的子查询?
  • @DanBracuk 是的,支持SELECT ... FROM (SELECT ...) AS alias ...
  • 感谢您的回复,该睡觉了,现在正在工作,所以稍后会检查他们

标签: sql sqlite group-by having-clause


【解决方案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))

【讨论】:

  • 这个解决方案错误地计算了行星的数量。简而言之,COUNT(planets.planetid) 计算类似于(卫星数 + 没有卫星的行星数)。请参阅stackoverflow.com/a/34543612/532954 以获得正确的解决方案。
【解决方案2】:

只需使用您的第一个查询,并添加子句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

【讨论】:

    【解决方案3】:

    恒星 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
    

    【讨论】:

    • 此解决方案正确计算了轨道数。
    【解决方案4】:

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

    【讨论】:

    • 我在 SQL lite 中尝试了 top 并得到一个错误,即没有 TOP 函数。但是,想象一下这确实有效,hilights 表中只有一列,而我在第一个查询中选择(ing)两列。那么如何让starid 进入hilights 表呢?
    • 您应该更新/编辑这个答案,而不是添加另一个答案。
    【解决方案5】:

    到 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;
    

    【讨论】:

    • 这些解决方案也错误地将轨道计数计算为 2n_moons + n_planets_without_moons。请参阅此处以获取正确的解决方案:stackoverflow.com/a/34543612/532954
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-04
    • 1970-01-01
    • 1970-01-01
    • 2021-08-01
    • 1970-01-01
    相关资源
    最近更新 更多