如何在具有内部联接作为子查询的 sql 中查找组内的百分比?

问题描述

我有 3 张这样的桌子

create table Users (id serial primary key,country varchar(100) not null);

create table tweets(id serial primary key,user_id int,text varchar(100) not null,CONSTRAINT FK_TWEETSUSERS FOREIGN KEY (user_id)
    REFERENCES Users(id));

create table Logins(user_id int,client varchar(100),CONSTRAINT FK_LOGIN_USERS FOREIGN KEY (user_id)
    REFERENCES Users(id));
                                                                                 
insert into Users
values
(1,'Japan'),(2,'Moroco'),(3,(4,'India'),(5,(6,(7,(8,'China');
                     
insert into tweets
values
(733,1,'I love #food'),(734,'I love food'),(735,2,(736,5,(737,6,(738,3,(739,8,'I love #food');      
                     
insert into Logins
values
(1,'mobile-ios'),'web'),'mobile-ios');

我需要找到用户在推文中使用“#food”的每个国家/地区的用户百分比,另一个条件是用户应该使用“移动”设备登录

到目前为止,我已经编写了以下查询 -

select t.country,count(t.country) as tweet_users
from 
(select Mobile_User_Tweets.user_id,U.country from Users as U
inner join
(select distinct user_id from tweets 
where text like '%#food%' 
and user_id in (select distinct user_id 
                                from Logins 
                               where client like '%mobile-%')) as Mobile_User_Tweets
on U.id = Mobile_User_Tweets.user_id) as t
group by t.country ;

这给出了在推文中包含用户 #food 的国家/地区的用户数量

结果如下 -

country tweet_users
Japan   2
Moroco  1
China   1

我想要以下结果 -

 country    tweet_users

Japan   66.67      -------------> (2 out of 3 users from Japan) 

Moroco  50         -------------> (1 out of 2 users from Moroco)

China   100        -------------> (1 out of 1 user from China)

我尝试了许多不同的查询来找到百分比,但没有得到结果?

有人可以帮我解决这个问题吗?

解决方法

实现您想要的结果的一种方法是在派生表中检查用户是否发布了关于 #food 的任何推文;那么您可以LEFT JOIN将该表UsersLogins确定从每个国家/地区通过手机登录并发布有关食物的推文的平均用户数:

SELECT u.country,AVG(COALESCE(t.tfood,0) AND COALESCE(l.client,'') LIKE '%mobile-%') * 100 AS tweet_users
FROM Users u
LEFT JOIN Logins l ON l.user_id = u.id
LEFT JOIN (
  SELECT user_id,MAX(text LIKE '%#food%') AS tfood
  FROM tweets
  GROUP BY user_id
) t ON t.user_id = u.id
GROUP BY u.country

输出:

country     tweet_users
China       100.0000
India       0.0000
Japan       66.6667
Moroco      50.0000

如果您不想要没有符合条件的用户的国家/地区,只需在末尾添加 HAVING tweet_users > 0

SELECT u.country,MAX(text LIKE '%#food%') AS tfood
  FROM tweets
  GROUP BY user_id
) t ON t.user_id = u.id
GROUP BY u.country
HAVING tweet_users > 0

Demo on dbfiddle

请注意,这段代码利用了这样一个事实,即在数字上下文中,MySQL 将布尔表达式视为 1(真)或 0(假)。

请注意,如果用户在 Logins 表中可能有多个条目,您也需要从中创建一个派生表:

SELECT u.country,0) AND COALESCE(l.mclient,0)) * 100 AS tweet_users
FROM Users u
LEFT JOIN (
  SELECT user_id,MAX(client LIKE '%mobile-%') AS mclient
  FROM Logins
  GROUP BY user_id
) l ON l.user_id = u.id
LEFT JOIN (
  SELECT user_id,MAX(text LIKE '%#food%') AS tfood
  FROM tweets
  GROUP BY user_id
) t ON t.user_id = u.id
GROUP BY u.country

Demo on dbfiddle