【问题标题】:Getting count depending on subquery根据子查询获取计数
【发布时间】:2019-05-16 07:11:24
【问题描述】:

在下面的 SELECT 语句中,我希望从表中获取 COUNT 个连接,其中连接定义为每个唯一 transactionID 1 个连接。
因此,在我的 COUNT 中,我想检查以确保尚未建立连接(即相同的 transactionID 但较低的主键 ID)。

我尝试使用 COUNT(DISTINCT pc.TransactionID),但问题是每个分组(ThisDate、SiteName、UserName、Command)中可能出现相同的 transactionID,因此它不止一次地计算了一些连接。

然后我尝试加入同一个表并使用 SUM 而不是 COUNT,这似乎可行,但由于拉入了额外的记录,这增加了 BytesTransferred 值。

关于处理此问题的最佳方法的想法?

ProtocolCommands 表

ProtocolCommandID, int, not null, primary key
Time_Stamp Datetime
SiteName nvarchar(50) null
UserName nvarchar(50) null
Command nvarchar(50) null
BytesTransferred numeric(18,0) null
TransactionID int not null

选择语句

SELECT
    CONVERT(date,pc.Time_stamp) As ThisDate,
    pc.SiteName,
    pc.UserName,
    pc.Command,
    SUM(CASE WHEN p.TransactionID IS NULL THEN 1 ELSE 0 END) As Connections,    
    -- COUNT(DISTINCT pc.TransactionID) AS Connections,
    SUM(pc.BytesTransferred) AS DataTransferred 
FROM ProtocolCommands pc
    LEFT OUTER JOIN ProtocolCommands p ON p.TransactionID = pc.TransactionID AND p.ProtocolCommandID < pc.ProtocolCommandID
WHERE pc.Time_Stamp >= '01/01/2019'
GROUP BY CONVERT(date,pc.Time_stamp),pc.SiteName, pc.UserName, pc.Command

举个例子,这里有一些记录:

Time_stamp  SiteName    UserName    Command BytesTransferred    TransactionID
2019-04-20  MySite  Joe connect 2000    12345
2019-04-20  MySite  Joe send    20000   12345
2019-04-21  MySite  Joe retrieve    25952   12345
2019-04-21  MySite  Joe send    30000   12345

当使用 COUNT(DISTINCT pc.TransactionID) 执行 SELECT 并删除内部连接时,结果如下(注意最后两行的 DataTransferred 不正确):

ThisDate    SiteName    UserName    Command Connections DataTransferred
2019-04-20  MySite  Joe connect 1   2000
2019-04-20  MySite  Joe send    0   20000
2019-04-21  MySite  Joe retrieve    0   51904
2019-04-21  MySite  Joe send    0   90000

当使用 SUM 执行 SELECT 并添加内连接时,结果是这样的(注意不正确的连接 - 应该只有 1 个):

ThisDate    SiteName    UserName    Command Connections DataTransferred
2019-04-20  MySite  Joe connect 1   2000
2019-04-20  MySite  Joe send    1   20000
2019-04-21  MySite  Joe retrieve    1   25952
2019-04-21  MySite  Joe send    1   30000

预期结果:

ThisDate    SiteName    UserName    Command Connections DataTransferred
2019-04-20  MySite  Joe connect 1   2000
2019-04-20  MySite  Joe send    0   20000
2019-04-21  MySite  Joe retrieve    0   25952
2019-04-21  MySite  Joe send    0   30000

【问题讨论】:

  • 显示数据和预期结果。这将消除所有的不确定性
  • 添加了示例数据和预期结果 - 谢谢。

标签: sql tsql sql-server-2016


【解决方案1】:

不确定我是否理解正确,但您似乎想检测最早出现的连接。您可以使用以下查询来做到这一点:

SELECT ROW_NUMBER() OVER (PARTITION BY TransactionId ORDER BY ProtocolCommandID ASC) as RowNum
, ProtocolCommandId
FROM ProtocolCommands

对于第一次出现连接的记录,这将使 RowNum = 1。

将它加入到您的主表中,您可以获得正确的连接数

SELECT 
  CONVERT(date,pc.Time_stamp) As ThisDate,
    pc.SiteName,
    pc.UserName,
    pc.Command,
    CASE WHEN first_conn.RowNum = 1 THEN SUM(first_conn.RowNum) ELSE 0 END AS Connection,
    SUM(pc.BytesTransferred) AS DataTransferred 
FROM ProtocolCommands pc
    LEFT OUTER JOIN 
        (SELECT ROW_NUMBER() OVER (PARTITION BY TransactionId ORDER BY ProtocolCommandID ASC) as RowNum
            , ProtocolCommandId
        FROM ProtocolCommands) as first_conn ON pc.ProtocolCommandID = first_conn.ProtocolCommandID

GROUP BY CONVERT(date,pc.Time_stamp),pc.SiteName, pc.UserName, pc.Command, first_conn.RowNum

【讨论】:

  • 看起来很到位。让我用各种数据进行测试。
  • 请注意,我正在假设连接与用户无关。无论用户如何,子查询都在寻找第一次出现的连接。如果用户可以共享连接,则必须让用户知道子查询,即将用户名添加到“分区依据”部分。
  • 是的,您说得对,连接与用户无关。测试看起来不错。感谢您的帮助!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-10-04
  • 2019-07-05
  • 1970-01-01
  • 2015-10-31
  • 2012-06-16
  • 1970-01-01
相关资源
最近更新 更多