2017-02-09 57 views
1

试图从“连接”表,其具有4个字段与样本值计算每日接受比率:计算acceptance_ratio与LEFT JOIN和SELF JOIN和聚合函数

date   action   sender_id  recipient_id 
'2017-01-05', 'request_link', 'frank', 'joe' 
'2017-01-06', 'request_link', 'sally', 'ann' 
'2017-01-07', 'request_link', 'bill', 'ted' 
'2017-01-07', 'accept_link', 'joe', 'frank' 
'2017-01-06', 'accept_link', 'ann', 'sally' 
'2017-01-06', 'accept_link', 'ted', 'bill' 

因为有0接受和1个请求上01-05,其日常接受率应为0/1 = 0。同样,01-06的比例应为2/1,01-07应为1/1。

但是,每个accept_link都有一个相应的request_link,其中request_link的sender_id = accept_link的recipient_id(反之亦然)。所以在这里需要自联接,我相信可以确保Joe接受Frank的请求,无论日期如何。

如何纠正下面的查询,以便在保留所需的连接条件的情况下正确工作?如果两个WHERE条件被删除,查询是否能够正确计算?还是它们是必需的?

SELECT f1.date, 
    SUM(CASE WHEN f2.action = 'accept_link' THEN 1 ELSE 0 END)/
    SUM(CASE WHEN f2.action = 'request_link' THEN 1 ELSE 0 END) AS acceptance_ratio 
FROM connecting f1 
LEFT JOIN connecting f2 
ON f1.sender_id = f2.recipient_id 
LEFT JOIN connecting f2 
ON f1.recipient_id = f2.sender_id 
WHERE f1.action = 'request_link' 
AND f2.action = 'accept_link' 
GROUP BY f1.date 
ORDER BY f1.date ASC 

预期的输出应该是这个样子:

date   acceptance_ratio 
'2017-01-05' 0.0000 
'2017-01-06' 2.0000 
'2017-01-07' 1.0000 

在此先感谢。

+0

什么构成一个计数?它是一个人与一个请求链接,另一个与一个接受链接?在你的例子中,如果我们有四条记录会发生什么事情,两个是弗兰克乔,两个是乔弗兰克?你想在这种情况下加倍计数? –

+0

是的,只有在发件人有相应的request_link时,accept_link数才应该有效。 为了简单起见,我们假设在这个例子中,frank-joe和joe-frank只有两条记录,尽管现在你提到它了,但我很好奇你会怎么解释查询中的多条记录。 –

+1

请参阅http://meta.stackoverflow.com/questions/333952/why-should-i-provide-an-mcve-for-what-seems-to-me-to-be-a-very-simple-sql-查询 – Strawberry

回答

1

再次,我不认为你需要在这里使用自我加入。所以,应该使用条件聚集在整个表格,并计算请求的数量,并接受其发生在每一天:

SELECT t.date, 
     CASE WHEN t.num_requests = 0 
      THEN 'No requests available' 
      ELSE CAST(t.num_accepts/t.num_requests AS CHAR(50)) 
     END AS acceptance_ratio 
FROM 
(
    SELECT c1.date, 
      SUM(CASE WHEN c1.action = 'accept_link' AND c2.action IS NOT NULL 
        THEN 1 ELSE 0 END) AS num_accepts, 
      SUM(CASE WHEN c1.action = 'request_link' THEN 1 ELSE 0 END) AS num_requests 
    FROM connecting c1 
    LEFT JOIN connecting c2 
     ON c1.action  = 'accept_link' AND 
      c2.action  = 'request_link' AND 
      c1.sender_id = c2.recipient_id AND 
      c2.recipient_id = c1.sender_id 
    GROUP BY c1.date 
) t 
ORDER BY t.date 

注意这里我用一个CASE表达零来处理鸿沟,可能发生应某一天没有要求。我也在这里假设相同的邀请不会被发送超过一次。

+0

谢谢,蒂姆,这有助于很多。有没有办法确保满足sender_id和recipient_id要求?例如,让我们说Joe接受Frank的请求,但是也许Frank的数据库中的request_link条目被错误地记录为'Jo',在这种情况下,request_link和accept_link都不应该被计入。有没有办法在将它们包含在SUM中之前验证ID是否符合预期? –

+0

@SidneyCarton我给你一个更新,我在本地测试,它似乎工作。 –

+0

非常感谢Tim –