【问题标题】:SQL query with count and left join带有计数和左连接的 SQL 查询
【发布时间】:2017-05-23 16:03:53
【问题描述】:

我有一个查询,我需要从 2 个表中计算“用户 ID”。

SQL 查询:

    SELECT DISTINCT TOP 1000 u.id as userID, u.firstName as userFirstName, u.email as userEmail, u.phone as userPhone, 
count(ueo.userID) as opensEmailCounter, count(ush.userID) as opensSmsCounter
    FROM dbo.Users u
    LEFT JOIN dbo.UserEmailsOpens ueo ON u.id = ueo.userID AND ueo.targetID = 4
    LEFT JOIN dbo.UserSmsHistory ush ON u.id = ush.userID AND ush.targetID = 4 AND ush.opened = 1
    WHERE u.deleted = 0
    AND IsNull(u.firstName, '') != '' 
    AND IsNull(u.email, '') != '' 
    AND IsNull(u.phone, '') != ''
GROUP BY u.id, u.firstName, u.email, u.phone

但是,结果不是我所期望的。在我进行第二次左加入后,它给了我错误的数字。在某些情况下,它是我结果的两倍,并显示相同的计数结果(附截图)。

【问题讨论】:

  • 你能显示表格 dbo.UserEmailsOpens 的定义吗?
  • 您要么必须在连接之前使用子查询进行计数,要么使用由值分区的窗口函数进行计数,使其在表连接之前具有唯一性。
  • 我不确定,但它可能会计算空值。你想让它这样做吗?
  • 您也可以考虑更改 where 谓词。而不是使用 ISNULL ...只需使用 u.firstName > '' 等。这将排除 NULL 并保持您的谓词 SARGable。
  • 如果在 JOINing UserSmsHistory 后您的数量翻了一番,则该表中可能有多个 userID 行。

标签: sql sql-server count


【解决方案1】:

在连接之前进行聚合,如下所示:

select distinct top 1000 
    u.id as userID
  , u.firstName as userFirstName
  , u.email as userEmail
  , u.phone as userPhone
  , ueo.opensEmailCounter
  , ush.opensSmsCounter
from dbo.Users u
  left join (
    select 
        userID
      , count(*) as opensEmailCounter
    from dbo.UserEmailsOpens 
    where targetID = 4
    group by userID
    ) ueo
     on u.id = ueo.userID
  left join (
    select 
        userID
      , count(*) as opensSmsCounter
    from dbo.UserSmsHistory 
    where targetID = 4
      and opened = 1
    group by userID
    ) ush
     on u.id = ush.userID
where u.deleted = 0
  and IsNull(u.firstName, '') != ''
  and IsNull(u.email, '')     != ''
  and IsNull(u.phone, '')     != ''

【讨论】:

    【解决方案2】:

    稍微修改了您的查询。使用Case When消除结果中的空白计数。

    Select userID, userFirstName, userEmail, userPhone, 
    sum(case when ueo_userID <> '' then 1 else 0 end) as opensEmailCounter,
    sum(case when ush_userID <> '' then 1 else 0 end) as opensSmsCounter
    from
     (
        SELECT DISTINCT u.id as userID, u.firstName as userFirstName, u.email as userEmail, u.phone as userPhone, 
        ueo.userID as ueo_userID, ush.userID as ush_userID
        FROM dbo.Users u
        LEFT JOIN dbo.UserEmailsOpens ueo ON u.id = ueo.userID AND ueo.targetID = 4
        LEFT JOIN dbo.UserSmsHistory ush ON u.id = ush.userID AND ush.targetID = 4 AND ush.opened = 1
        WHERE u.deleted = 0user
        AND IsNull(u.firstName, '') != '' 
        AND IsNull(u.email, '') != '' 
        AND IsNull(u.phone, '') != ''
     ) a
    GROUP BY userID, userFirstName, userEmail, userPhone;
    

    如果您有任何问题,请告诉我

    【讨论】:

      猜你喜欢
      • 2021-12-28
      • 2018-11-14
      • 2017-08-17
      • 2016-05-16
      • 1970-01-01
      • 2012-04-10
      • 2020-12-15
      • 1970-01-01
      • 2019-05-24
      相关资源
      最近更新 更多