【问题标题】:How to select a row based on a max count? (using standard sql)如何根据最大计数选择行? (使用标准 sql)
【发布时间】:2009-12-11 17:38:05
【问题描述】:

我有一张桌子:

计算机 ID、用户 ID、登录日期

我需要一个返回的 select 语句:
ComputerID、UserID、LoginCount

对于所有台计算机,但对于每台计算机,只显示最常登录该计算机的一个用户。 (如果有平局,我想我只想随意选择一个用户....所以这似乎表明我在某个地方需要一个 TOP 1。)

(这是在 ms-access 中,因此不能使用供应商特定的功能)。

解决方案(JBrooks 回答的轻微修复)

select main.*
from (select ComputerID, UserID, count(1) as cnt
    from ComputerLoginHistory
    group by ComputerID, UserID) as main
           inner join (select ComputerID, max(cnt) As  maxCnt
                            from 
                                    (select ComputerID, UserID, count(1) as cnt
                                     from ComputerLoginHistory
                                     group by ComputerID, UserID) as Counts
                            group by ComputerID)
                          as maxes
on main.ComputerID = maxes.ComputerID
and main.cnt = maxes.maxCnt

为了处理 >1 用户可能对给定计算机具有相同 loginCount 的情况,我能想到的所有方法都是围绕这个选择另一个选择,选择 Max(UserID).....所以你基本上只是随意挑选其中之一。这就是我在本示例中所做的,我将拉回最近的用户,而不是最活跃的用户:

Select ComputerID, Max(xUserID) As UserID, MaxLoginDate
FROM
(
SELECT main.ComputerID, main.UserID as xUserID, main.MaxLoginDate
FROM [select ComputerID, UserID, Max(LoginDate) as MaxLoginDate
    from ComputerLoginHistory
    group by ComputerID, UserID]. AS main 
     INNER JOIN [select ComputerID, Max(MaxLoginDate) As MaxLogin
                            from 
                                    (select ComputerID, UserID, Max(LoginDate) as MaxLoginDate
                                     from ComputerLoginHistory
                                     group by ComputerID, UserID) as Counts
                            group by ComputerID]. AS maxes ON (main.MaxLoginDate = maxes.MaxLogin) AND (main.ComputerID = maxes.ComputerID)
)
GROUP BY ComputerID, MaxLoginDate
ORDER BY ComputerID

【问题讨论】:

  • 以及LoginCount数相同的用户数少时怎么办
  • 我用一个例子编辑了我的答案。我用访问数据库中的一些示例数据对其进行了测试,它对我有用。

标签: sql ms-access


【解决方案1】:

如果您想要列出每台计算机 ID 及其最高用户,则类似于:

select main.*
from (select ComputerID, UserID, count(1) as cnt
    from logTable
    group by ComputerID, UserID) as main
    inner join (select ComputerID, max(cnt) maxCnt
                from (select ComputerID, UserID, count(1) as cnt
                    from logTable
                    group by ComputerID, UserID) as Counts) 
                as maxes
on main.ComputerID = maxes.ComputerID
and main.cnt = maxes.maxCnt

【讨论】:

  • 如果两个用户登录计算机的次数相同会怎样?
  • 我在原始问题中发布了对此 sql 的轻微修复。
【解决方案2】:

在 MS Access 中,我会编写 two 三个查询并从第一个查询调用第二个查询。第一个查询应该简单地进行计数,下一个查询将找到第一个查询的最大值。在将前两个查询连接在一起后,第三个查询将引用第一个查询中的用户 ID。

例如:

qryCountQuery

SELECT 
LoginCount.ComputerID, 
LoginCount.UserID, 
Count(LoginCount.ComputerID) AS CountOfComputerID
FROM 
LoginCount
GROUP BY 
LoginCount.ComputerID, LoginCount.UserID;

qryMaxQuery

SELECT 
qryCountQuery.ComputerID, 
Max(qryCountQuery.CountOfComputerID) AS MaxOfCountOfComputerID
FROM 
qryCountQuery
GROUP BY 
qryCountQuery.ComputerID;

qryCountMaxQueryCombined

SELECT 
qryMaxQuery.ComputerID, 
qryMaxQuery.MaxOfCountOfComputerID, 
qryCountQuery.UserID
FROM 
qryCountQuery 
INNER JOIN qryMaxQuery 
    ON (qryCountQuery.CountOfComputerID = qryMaxQuery.MaxOfCountOfComputerID) AND 
       (qryCountQuery.ComputerID = qryMaxQuery.ComputerID);

注意:如果您的用户被“捆绑”了最多登录到一台 PC,则这台 PC 将与两个用户一起显示两次。您可以将UNIQUEFIRST 聚合调用放入另一个查询中。这取决于您是否绝对必须为每个 computerID.

提供一个结果

注意 2:在 MySQL 等其他系统中,我可能会使用嵌套查询,但我更喜欢在 Access 中将其分开。

注意 3:我忘记了这个问题在 Access 中很困难。我很高兴我测试了我的代码。

【讨论】:

  • 我完全明白。我有时会在 Access 中这样做,但 Access(2002/XP 版本)喜欢取消我的 SQL 格式,这让我非常难以使用。
【解决方案3】:

不确定这是否在 MS ACCESS 中可用,它肯定在 SQL Server 05 和 08 中可用,因此您必须对此进行调查。

您可以使用方便的 ROW_NUMBER() 函数,该函数允许您对数据子集进行分区和分配行号,然后您可以根据该行号限制返回的结果。

DECLARE     @MaxResultsPerComputerID    INT
SELECT      @MaxResultsPerComputerID    = 3 -- assign the maximum number of results to bring back per computer

SELECT      *
FROM        (
            SELECT      ComputerID, 
                        UserID, 
                        LoginDate,
                        NumberOfTimesLoggedIn, -- Derive this value somehow (not sure what your db schema is)
                        ROW_NUMBER() OVER (PARTITION BY ComputerID ORDER BY NumberOfTimesLoggedIn) AS RowNumber -- the magic happens here
            FROM        SomeTable
            ) a
WHERE       RowNumber <= @MaxResultsPerComputerID

【讨论】:

  • 虽然我认为这是 Oracle,不是吗??
  • 这是 sql server 05+,不确定它是否可以在 MS Access 中使用。但我不会删除,因为它可能是一个可以帮助找到这个问题的人的答案。
  • ROW_NUMBER() OVER 可能对 Oracle/SQL Server/DB2 人群有用,但在 Access、MySQL 或 PostgreSQL 中没有用(来源:SQL Cookbook,p. 330:amazon.com/Cookbook-Cookbooks-OReilly-Anthony-Molinaro/dp/…)
【解决方案4】:
SELECT TOP 1 * FROM YOURTABLE ORDER BY LoginCount DESC

(MS - SQL,不确定这在 Access 中是否有效)

试试这个例子的一些变化:

SELECT UserId, MAX(COUNT(*)) as "HighestLogin"
FROM YOURTABLE
GROUP BY ComputerId;

【讨论】:

  • TOP 关键字不是标准 SQL。
  • TOP 是标准的 Jet/ACE SQL。至少从 Jet 2.x 开始就支持它。我什至不知道术语“标准 SQL”是什么意思。我所看到的只是一堆 SQL 方言,每个数据库引擎都略有不同。有 SQL 标准,但没有一个数据库引擎可以完全实现任何曾经存在的 SQL 标准。
  • @David W. Fenton:标准 SQL 通常意味着所有 SQL 产品——甚至是 Jet 4.0 时代的 Access 数据库引擎——都高度重视的 ISO/ANSI SQL 标准。另一方面,“标准 Jet/ACE SQL”是您刚刚发明的一个短语;)
  • FWIW SQL-99 标准使用 ROW_NUMBER() OVER (ORDER BY..) 语法作为专有 TOP N 语法的替代方案。
【解决方案5】:

你能在你的 Access 数据库上检查一下吗:

select ComputerID, UserID, count(*) as LoginCount
from t2  parent_table
group by ComputerID, UserID
having count(*) = (select max(count(*) ) from t2 
       where ComputerID = parent_table.ComputerID group by ComputerID, UserID)
order by ComputerID, UserID

【讨论】:

  • 该死的。表达式 中不能有聚合函数。 (错误 3095)
【解决方案6】:
create temporary table t select ComputerID, UserID, count(*) as LoginCount
from table group by ComputerID, UserID;

create temporary table m select ComputerID, max(LoginCount) as maxLoginCount
from t group by ComputerID;

select m.ComputerID, max(UserID) from m join t
on m.ComputerID = t.ComputerID and m.maxLoginCount = t.LoginCount
group by ComputerID;

【讨论】:

猜你喜欢
  • 2015-08-12
  • 1970-01-01
  • 2022-08-10
  • 1970-01-01
  • 2021-09-12
  • 1970-01-01
  • 2014-05-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多