【问题标题】:SQL: SELECT COUNT involving a couple of tablesSQL:SELECT COUNT 涉及几个表
【发布时间】:2012-03-07 00:35:10
【问题描述】:

我有一个包含四个表的小型 MS Access 数据库,并且正在努力处理涉及所有表的 SELECT COUNT 查询。任何帮助将不胜感激。

数据库概览:

TABLE       COLUMNS

Person         Person_ID |....
Games          Game_ID | Name |....
Played_Games   Played_Games_ID | Game_ID |....
Participation  Played_Games_ID | Person_ID |...

列出所有游戏以及每个游戏总共玩了多少次:

SELECT DISTINCT
Games.Name,
(SELECT COUNT(*) FROM Played_Games WHERE Played_Games.Game_ID = Games.Game_ID) AS TimesPlayed
FROM Games
ORDER BY Games.Name

这很好用,但我还想列出每个游戏由特定群体的成员玩了多少次

我在下面的代码(第 4 行)方面取得了一些进展,但我仍然遇到一个小问题:

在最里面的括号后面对 Games.Game_ID 的引用不再链接到当前的 Game_ID,就像在上面的代码中一样。它现在似乎是未定义的。当我在 MS Access Query Designer 中运行它进行测试时,它要求我输入 Games.Game_ID 的值。如果我然后输入一些随机 Game_ID,代码会“完美”运行,但正如您可能已经发现的那样,TimesPlayedByGroupMembers 的值对于记录集中的每一行都将是相同的,并且仅对我输入的那个特定 Game_ID 为 true

SELECT DISTINCT
Games.Name,
(SELECT COUNT(*) FROM Played_Games WHERE Played_Games.Game_ID = Games.Game_ID) AS TimesPlayed,
(SELECT COUNT(*) FROM (SELECT DISTINCT Played_Games_ID FROM Participation WHERE Played_Games_ID IN (SELECT Played_Games_ID FROM Played_Games WHERE Game_ID = Games.Game_ID) AND Person_ID IN (26, 27, 28))) AS TimesPlayedByGroupMembers
FROM Games
ORDER BY Games.Name

我将尝试从内到外解释我的代码做什么和/或应该做什么

最里面的括号列出了涉及当前游戏的 Played_Games_ID,但这不起作用,因为 Games.Game_ID 未链接到当前 Game_ID

中间的括号(包括上面的那个)列出了涉及当前游戏和一个或多个选定人员的 Played_Games_ID。此处列出的 Person_ID 只是一个示例,这部分代码正在运行

最外面的括号(包括以上所有)计算每个游戏由一个或多个选定的人玩了多少次

我真的很困惑,所以任何帮助都将不胜感激

感谢您的宝贵时间

【问题讨论】:

  • 这会有点耗时。你能发布表结构、插入和期望的结果示例吗?如果你不着急的话,我会在我回到家时尝试分解它。
  • @Bhrugesh Patel 感谢您有兴趣帮助我!也许我不太明白您的要求,因为我已经列出了表名、所涉及的列以及我想要列出的内容(?)。 GarethD 已经解决了这个任务,但我担心我可能会遇到一些问题,将他的代码整合到更大的图景中。你看到的我的真实查询中涉及更多的表和列。我只是提取了我自己无法弄清楚如何完成的部分或任务
  • 我想要插入语句,这样我就可以使用它们来注入数据并对其运行查询。有时查询可能看起来不错,但是当您运行它们并与预期结果匹配时,您会发现很少有额外或缺失的结果。在复杂查询中确认结果始终是最佳实践,而不是相信查询正在做它应该做的事情。
  • 好的,我现在明白你的意思了@Bhrugesh Patel,我看到提供创建和注入查询可以让人们更容易提供帮助。对于任何可能的进一步问题,我会牢记这一点。这是我第一次来这里;-)

标签: sql ms-access count


【解决方案1】:

我的 Access 语法有些生疏,我不能 100% 确定您的表结构,但我认为下面的方法可行。

SELECT  Games.Name, 
        TimesPlayed,
        TimesPlayedByGroupMembers
FROM    Games
        INNER JOIN 
        (   SELECT  Game_ID, 
                    COUNT(*) AS TimesPlayed,
                    SUM(IIF(ISNULL(Participation.Played_Games_ID),0,1)) AS TimesPlayedByGroupMembers
            FROM    Played_Games 
                    LEFT JOIN 
                    (   SELECT  Played_games_ID 
                        FROM    Participation 
                        WHERE   Person_ID IN (1, 2) 
                        GROUP BY Played_games_ID 
                    ) AS Participation 
                        ON Participation.Played_Games_ID = Played_Games.Played_Games_ID
            GROUP BY Game_ID
        ) AS Played_Games
            ON Played_Games.Game_ID = Games.Game_ID
ORDER BY Games.Name

附录:

要让未玩过的游戏显示为 0,请使用以下命令:

SELECT  Games.Name, 
        IIF(ISNULL(TimesPlayed),0,TimesPlayed) AS TimesPlayed,
        IIF(ISNULL(TimesPlayedByGroupMembers),0,TimesPlayedByGroupMembers) AS TimesPlayedByGroupMembers
FROM    Games
        LEFT JOIN 
        (   SELECT  Game_ID, 
                    COUNT(*) AS TimesPlayed,
                    SUM(IIF(ISNULL(Participation.Played_Games_ID),0,1)) AS TimesPlayedByGroupMembers
            FROM    Played_Games 
                    LEFT JOIN 
                    (   SELECT  Played_games_ID 
                        FROM    Participation 
                        WHERE   Person_ID IN (1, 2) 
                        GROUP BY Played_games_ID 
                    ) AS Participation 
                        ON Participation.Played_Games_ID = Played_Games.Played_Games_ID
            GROUP BY Game_ID
        ) AS Played_Games
            ON Played_Games.Game_ID = Games.Game_ID
ORDER BY Games.Name

【讨论】:

  • @Andrew 你一点也不生疏,我的朋友 :-) 我的大脑在处理这一切时遇到了一些问题,但 MS Access 没有 :-) 效果很好。这将只列出玩过的游戏,但将 INNER 更改为 LEFT 可以解决此问题。唯一缺少的是这些行的零输出。我可能没有这个,但你碰巧有什么调整吗?
  • @Morten 我添加了另一个查询来显示我认为你在追求什么。
  • 我向 GarethD 道歉。上面的评论确实是给你的,而不是安德鲁。我试着编辑它,但时间已经超过了 5 分钟的限制,所以我不能。这是我第一次使用stackoverflow,所以界面对我来说还是有点新。对不起
  • 再次感谢 GarethD :-) 我尝试了 IIF(ISNULL.. 我自己,在代码的更深处,但你的解决方案要好得多
  • 没问题。我认为您可以将其标记为正确答案(单击旁边的绿色勾号)。这至少应该有助于其他人查看该页面。作为将其合并到进一步查询中的提示,您可以将其保存为查询,然后在其他查询中引用该查询,如果将其保存为 [GamesPlayedCount],则可以只编写像 SELECT * FROM [GamesPlayedCount] 这样的查询,而不是重写整个查询并添加它到更多的 SQL 可能会很快变得混乱,尤其是使用访问查询编辑器。
【解决方案2】:

您的第一个查询通常是这样完成的:

SELECT
Games.Name, COUNT(Played_Games.Game_ID) AS TimesPlayed
FROM Games
INNER JOIN Played_Games ON Played_Games.Game_ID = Games.Game_ID
GROUP BY Games.Name
ORDER BY Games.Name

这可能与您的第二个查询所追求的相近:

SELECT
Games.Name, COUNT(Participation.Played_Games_ID) AS TimesPlayedByGroupMembers
FROM Games
INNER JOIN Played_Games ON Played_Games.Game_ID = Games.Game_ID
INNER JOIN Participation ON Participation.Played_Games_ID = Played_Games.Played_Games_ID
WHERE Participation.Person_ID IN (26, 27, 28)
GROUP BY Games.Name
ORDER BY Games.Name

【讨论】:

  • 我不相信 Access 的数据库引擎会运行这些查询中的任何一个。将JOIN 更改为INNER JOIN,或其他所需的连接类型。 Access 中没有 COUNT(DISTINCT something)
  • 如果你是按名字分组,你也是按名字排序,所以Order By是多余的。
  • @Andrew - 查询 1:INNER JOIN 导致仅列出玩过的游戏,但更改为 LEFT JOIN 此查询产生的结果与我的相同。谢谢
  • @Andrew - 查询 2:我关注您的查询,但不幸的是没有 MS Access。它说“缺少操作员”并在第一个 ON 之后显示代码,直到 WHERE。不过感谢您的宝贵时间
  • @HansUp:感谢您的额外提示
猜你喜欢
  • 1970-01-01
  • 2022-11-22
  • 2020-04-05
  • 2016-07-26
  • 2012-01-12
  • 2023-02-21
  • 1970-01-01
  • 2021-06-25
  • 1970-01-01
相关资源
最近更新 更多