sql join包括null和non existing records

时间:2014-07-31 15:00:43

标签: sql-server join

我有以下表格。我试图获得这4个表的连接,它将列出所有问题,即使用户没有回答用户和类别的任何问题。 有什么帮助吗?

select * 
from  tbl_category  c
inner join  tbl_questions  q on q.categoryID = c.categoryID
left join  tbl_answers  a on a.questionID = q.questionID
left join  tbl_users  u on u.userID = a.userID
order by u.userID

这只会提供9条记录。我需要知道未回答的问题,以及没有回答任何问题的用户。

CREATE TABLE [dbo].[tbl_users](
    [userID] [int] IDENTITY(1,1) NOT NULL,
    [firstName] [varchar](50) NULL,
    [lastName] [varchar](50) NULL
) 
GO

CREATE TABLE [dbo].[tbl_questions](
    [questionID] [int] IDENTITY(1,1) NOT NULL,
    [categoryID] [int] NOT NULL,
    [description] [varchar](100) NULL
) 
GO

CREATE TABLE [dbo].[tbl_category](
    [categoryID] [int] IDENTITY(1,1) NOT NULL,
    [description] [varchar](50) NULL
) 
GO

CREATE TABLE [dbo].[tbl_answers](
    [answer_id] [int] IDENTITY(1,1) NOT NULL,
    [answerText] [varchar](250) NULL,
    [questionID] [int] NULL,
    [userID] [int] NULL
) 
GO

-- tbl_questions
insert into tbl_questions ( categoryID, description ) 
values ( 1, 'How do you balance life and work?') 

insert into tbl_questions ( categoryID, description ) 
values ( 1, 'Do you check voicemail and email when on vacation?') 

insert into tbl_questions ( categoryID, description ) 
values ( 1, 'What is your favorite book?') 

insert into tbl_questions ( categoryID, description ) 
values ( 2, 'What were your responsibilities?') 

insert into tbl_questions ( categoryID, description ) 
values ( 2, 'What is your greatest strength?') 

insert into tbl_questions ( categoryID, description ) 
values ( 2, 'What is your greatest weakness?') 

insert into tbl_questions ( categoryID, description ) 
values ( 2, 'How do you evaluate success?') 

-- tbl_users
insert into tbl_users ( firstName, lastName ) 
values ( 'Alessandra', 'Ambrosio' )

insert into tbl_users ( firstName, lastName ) 
values ( 'Adriana', 'Lima' )

insert into tbl_users ( firstName, lastName ) 
values ( 'Daniela', 'Pestova' )


-- tbl_answers
insert into tbl_answers ( answerText, questionID, userID ) 
values ( 'answer for q1', 1, 1) 

insert into tbl_answers ( answerText, questionID, userID ) 
values ( 'answer for q2', 2, 1) 

insert into tbl_answers ( answerText, questionID, userID ) 
values ( 'answer for q3', 3, 1) 

insert into tbl_answers ( answerText, questionID, userID ) 
values ( 'answer for q4', 4, 1) 

insert into tbl_answers ( answerText, questionID, userID ) 
values ( 'answer for q5', 5, 1) 

insert into tbl_answers ( answerText, questionID, userID ) 
values ( 'answer for q6', 6, 1) 

insert into tbl_answers ( answerText, questionID, userID ) 
values ( 'answer for q7', 7, 1) 

insert into tbl_answers ( answerText, questionID, userID ) 
values ( 'other answer for q5', 5, 2) 

insert into tbl_answers ( answerText, questionID, userID ) 
values ( 'other answer for q2', 2, 2) 

-- tbl_category
INSERT tbl_category (categoryID, description) VALUES (1, 'About You')
INSERT tbl_category (categoryID, description) VALUES (2, 'Job') 

3 个答案:

答案 0 :(得分:7)

您需要usersquestions的所有组合,即使对于用户未回答的问题也是如此。这种问题有点复杂,但并不罕见。

解决此问题的方法是首先在CROSS JOINquestions之间创建笛卡尔积(users),然后才LEFT JOIN创建answers

所以查询将是:

SELECT                           -- choose only the columns you want, not all (*)
    u.*, c.*, q.*, a.*     
FROM

问题与类别有关。我们希望如此:

    tbl_category AS c
  JOIN 
    tbl_questions AS q  ON  q.categoryID = c.categoryID

然后将上述(问题)的所有组合与(用户)

联系起来
  CROSS JOIN
    tbl_users AS u 

然后加入(答案)。请注意答案如何具有2个连接条件,上述每个表(问题和用户)之一:

  LEFT JOIN
    tbl_answers AS a  ON  a.questionID = q.questionID
                      AND a.userID = u.userID

然后完整查询变为:

SELECT  
    u.*, c.*, q.*, a.*     
FROM
    tbl_category AS c
  JOIN 
    tbl_questions AS q  ON  q.categoryID = c.categoryID
  CROSS JOIN
    tbl_users AS u 
  LEFT JOIN
    tbl_answers AS a  ON  a.questionID = q.questionID
                      AND a.userID = u.userID
ORDER BY
    u.userID ;

答案 1 :(得分:2)

  

我需要知道未回复的问题,以及用户,他们没有回答任何问题。

你正在寻找两个截然不同的东西。这意味着我需要两个不同的查询。

未回答的问题是tbl_answers中没有匹配项的问题。这意味着tbl_answers反加入tbl_questions

SELECT
  Category = c.description,
  Question = q.description
FROM
  tbl_questions AS q
INNER JOIN
  tbl_category AS c ON q.categoryID = c.categoryID
WHERE NOT EXISTS (
  SELECT *
  FROM tbl_answers AS a
  WHERE q.questionID = a.questionID
);

没有回答任何问题的用户再次是tbl_answers中没有匹配的用户。所以,这个也是一个反连接:

SELECT
  u.firstName,
  u.lastName
FROM
  tbl_users AS u
WHERE NOT EXISTS (
  SELECT *
  FROM tbl_answers AS a
  WHERE u.userID = a.userID
);

答案 2 :(得分:-2)

用户表必须是当前定义的“左”表。你可以进入一个关于左右连接的争论,但是从可读性和个人偏好来看,左连接是可行的方法。

select * 
from tbl_users u 
left join (select q.questionID,q.categoryID,q.description qdesc,
                c.description catdesc,a.answer_id,a.answerText,a.userID
            from tbl_category  c
            inner join  tbl_questions  q on q.categoryID = c.categoryID
            left join  tbl_answers  a on a.questionID = q.questionID
            )qa on u.userid=qa.userid

如果您需要为每个用户显示每个问题,我认为您需要另一个将用户与问题相关联的表格。像

一样
CREATE TABLE [dbo].[Survey](
    [surveyID] [int] IDENTITY(1,1) NOT NULL,
    [questionID] [int] IDENTITY(1,1) NOT NULL,
     [userID] [int] NULL