使用 4 个表的 JOIN 查询的结果不正确

Shi*_*r K 4 sql-server relational-division

如果有人可以帮助我进行下面的查询,那就太好了!这个查询很有挑战性,我尝试自己做,但无法显示正确的结果......

我使用类似于“Facebook”的系统的数据库。

查询应显示去年为每个帖子发表评论的用户的电子邮件和姓名,这些帖子由他们的每个朋友发布。

意思是,我只想显示对所有朋友的所有帖子发表评论的人。


这是我的试验,但我收到了部分结果。我无法理解我做错了什么。

select distinct U.Mail, U.FirstName + ' ' + U.LastName as FullName 
from Users U
inner join FriendsList FL on U.Mail = FL.Mail1
inner join Post P on FL.Mail2 = P.UserMail
left outer join Comment C on P.ID = C.IDPost and P.UserMail <> C.Mail
where datediff(year, P.DatePosted, getdate()) <= 1
group by U.Mail, U.FirstName, U.LastName
having count(distinct P.ID) = count(distinct C.IDPost)
Run Code Online (Sandbox Code Playgroud)

BAK文件链接(包括测试数据):https : //file.io/SagvM3cx

表格图: 在此处输入图片说明


例子:

让我们假设 I & Adam & Ben 是朋友。

?? 第一种情况:

  • 亚当写了 1 个帖子,我发表了评论。
  • Ben 写了 1 个帖子,我没有发表评论。

然后,我的名字应该不会在查询中显示。

  • 亚当写了 1 个帖子,我发表了评论。
  • Ben 写了 1 个帖子,我发表了评论。

然后,我的名字应该显示在查询中。

?? 第二种情况:

  • Adam 写了 2 个帖子,我评论了第一个,但没有评论第二个。
  • Ben 写了 1 个帖子,我发表了评论。

然后,我的名字应该不会在查询中显示。

  • 亚当写了 2 个帖子,我都评论了。
  • Ben 写了 1 个帖子,我发表了评论。

然后,我的名字应该显示在查询中。

?? 第三种情况:

  • 亚当写了 2 个帖子,我都评论了。
  • Ben 写了 1 个帖子,我发表了评论。
  • 马克(不是我的朋友)写了 1 篇文章,我没有发表评论。

然后,我的名字应该显示在查询中。


编辑:我添加了 8 个查询 - 4create table和 4 insert。根据这个例子,上面的查询应该只显示Kelly

create table Users
(
Mail nvarchar (20) primary key check(Mail like '_%@_%._%' and (Mail like '%[0-9]%' Or Mail like '%[a-z]%'Or Mail like '%[A-Z]%')),
Password nvarchar (8) check (Password like '%[0-9]%' and Password like '%[az]%' and len(password) <= 8) not null,
FirstName nvarchar (20) not null,
LastName nvarchar (20) not null,
BirthDate date check (datediff(year,BirthDate,getdate())>=18) not null,
JoinDate date check (JoinDate<=getdate()) not null,
Gender nchar(1) check(Gender = 'F' or Gender = 'M' or Gender = 'O'),
NickName nvarchar(20),
Photo nvarchar(20),
Phone bigint check (Phone like '%[0-9]%' and len(Phone) <= 10) not null
)

INSERT INTO Users
VALUES
('Kelly@gmail.com','k1000000','Kelly','Ka','1992-05-15','2016-09-04','F','Kelly','Kelly.jpg','546296100'),
('Lilly@gmail.com','l1101111','Lilly','La','1999-04-03','2012-04-04','F','Lilly','Lilly.jpg','542448300'),
('Moshe@gmail.com','m120121','Moshe','Ma','1995-06-03','2011-04-02','M','Moshe','MosheMa.jpg','542840111'),
('Nelly@gmail.com','n130131','Nelly','Na','1994-03-07','2020-04-13','F','Nelly','NellyNa.jpg','541234567');
('Owen@gmail.com','o140141','Owen','Oa','1992-02-02','2020-05-13','M','Owen','OwenOa.jpg','541234567');

create table FriendsList
(
Mail1 nvarchar (20) references Users(Mail) not null,
Mail2 nvarchar (20) references Users(Mail) not null,
DateAdding date check (DateAdding<=getDate()) not null,
primary key (Mail1,Mail2)
)

INSERT INTO FriendsList
VALUES
('Kelly@gmail.com','Nelly@gmail.com','2018-04-18'),
('Lilly@gmail.com','Moshe@gmail.com','2020-04-22'),
('Moshe@gmail.com','Lilly@gmail.com','2020-04-22'),
('Moshe@gmail.com','Nelly@gmail.com','2020-04-22'),
('Nelly@gmail.com','Kelly@gmail.com','2018-04-18');
('Nelly@gmail.com','Moshe@gmail.com','2020-04-22'),

create table Post
(
ID int identity(1,1) primary key,
Photo nvarchar(20),
Text nvarchar(200),
Location nvarchar(50),
Video int,
DatePosted date check (datediff(month,DatePosted,getdate())<=3) not null,
UserMail nvarchar (20) references Users(Mail) on delete cascade on update
cascade not null
)

INSERT INTO Post
VALUES
('','my name is nellu','','','2020-04-18','Nelly@gmail.com'),
('','hii','','','2020-05-19','Lilly@gmail.com');

create table Comment
(
IDPost int references Post(ID) on delete cascade on update cascade not null,
SerialNumComment int check(SerialNumComment > 0) not null,
DateAndTimeComment Datetime check (DateAndTimeComment<=getDate()) not null,
Text nvarchar(200) not null,
Mail nvarchar (20) references Users(Mail) not null,
primary key (IDPost,SerialNumComment)
)

INSERT INTO Comment
VALUES
('1','1','2020-04-18','blabla','Kelly@gmail.com'),
('2','1','2020-05-05','bhfk','Moshe@gmail.com');
Run Code Online (Sandbox Code Playgroud)

Mar*_*ith 5

您原始查询中的问题是

left outer join Comment C on P.ID = C.IDPost and P.UserMail <> C.Mail
Run Code Online (Sandbox Code Playgroud)

应该

left outer join Comment C on P.ID = C.IDPost and  U.Mail = C.Mail
Run Code Online (Sandbox Code Playgroud)

您正在尝试获取原始用户发布的评论

就我个人而言,我发现双重NOT EXISTS方法更容易遵循(尽管如何对待没有符合条件的帖子发表评论的用户的语义有所不同)。

您正在寻找其中一位朋友最近没有发表评论的用户。

这实现了该逻辑

SELECT U.Mail,
       U.FirstName + ' ' + U.LastName AS FullName
FROM   Users U
WHERE  NOT EXISTS (
                  --A post by one of their friends in the last year
                  SELECT *
                   FROM   FriendsList FL
                          INNER JOIN Post P
                                  ON FL.Mail2 = P.UserMail
                   WHERE  U.Mail = FL.Mail1
                          AND P.DatePosted >= DATEADD(YEAR, -1, GETDATE())
                          AND NOT EXISTS (
                                         --A comment by the user on that post
                                         SELECT *
                                          FROM   Comment C
                                          WHERE  P.ID = C.IDPost
                                                 AND U.Mail = C.Mail))
Run Code Online (Sandbox Code Playgroud)