如何将三个SELECT语句与非常棘手的要求结合起来

时间:2010-03-26 14:23:49

标签: sql

我有一个带有三个SELECT语句的SQL查询。这三个选择语句生成的数据表的图片位于www.britestudent.com/pub/1.png。三个数据表中的每一个都具有相同的列。我想将这三个表组合成一个表,以便:

(1)始终包括顶部表格(表1)中的所有行。

(2)仅当column1(UserName)和column4(CourseName)中的值与Table1中的任何行不匹配时,才包含中间表(Table2)中的行。两列都需要匹配Table2中的行才不包括在内。

(3)只有当column4(CourseName)中的值不在组合Table1和Table2的结果的任何行中时,才包含底部表(Table3)中的行。

我使用这样的SQL查询成功实现了(1)和(2):

SELECT DISTINCT 
   UserName AS UserName, 
   MAX(AmountUsed) AS AmountUsed, 
   MAX(AnsweredCorrectly) AS AnsweredCorrectly, 
   CourseName, 
   MAX(course_code) AS course_code, 
   MAX(NoOfQuestionsInCourse) AS NoOfQuestionsInCourse, 
   MAX(NoOfQuestionSetsInCourse) AS NoOfQuestionSetsInCourse
FROM 
   ( "SELECT statement 1"  UNION  "SELECT statement 2" ) dt_derivedTable_1 
GROUP BY CourseName, UserName

其中“SELECT语句1”是生成Table1的查询,“SELECT语句2”是生成Table2的查询。此查询生成的数据表的图片位于www.britestudent.com/pub/2.png。我可以使用MAX()函数,因为Table1中AmountUsed和AnsweredCorrectly列中的值将始终大于Table2中的值(并且它们在两个表的最后三列中相同)。

我失败的是实施(3)。任何有关如何做到这一点的建议将不胜感激。这很棘手,因为Table3中的UserName值为null,并且因为Table1和Table2组合结果中的CourseName值不是唯一的(但它们在表3中是唯一的)。

在实现(3)之后,最终表应该看起来像图2.png中的表,添加了表3中的最后一行(CourseName值以“4.Klasse ...”开头的行

我尝试使用SELECT,MAX()和UNION使用另一个派生表来实现(3),但我无法使其工作。下面是我的完整SQL查询,其中包含来自此失败尝试的行(3)已注释掉。

干杯, 弗雷德里克

PS - 我是这个论坛的新手(也是SQL的新手),但是通过阅读本论坛上其他人的帖子而不是阅读任何其他论坛或网站,我已经解决了以前更多的问题。这个论坛是一个很好的资源。

--  SELECT DISTINCT MAX(UserName), MAX(AmountUsed) AS AmountUsed, MAX(AnsweredCorrectly) AS AnsweredCorrectly, CourseName, MAX(course_code) AS course_code, MAX(NoOfQuestionsInCourse) AS NoOfQuestionsInCourse, MAX(NoOfQuestionSetsInCourse) AS NoOfQuestionSetsInCourse
--  FROM (

                SELECT DISTINCT UserName AS UserName, MAX(AmountUsed) AS AmountUsed, MAX(AnsweredCorrectly) AS AnsweredCorrectly, CourseName, MAX(course_code) AS course_code, MAX(NoOfQuestionsInCourse) AS NoOfQuestionsInCourse, MAX(NoOfQuestionSetsInCourse) AS NoOfQuestionSetsInCourse
                FROM (

                        -- Table 1 - All UserAccount/Course combinations that have had quizzez.
                        SELECT DISTINCT dbo.win_user.user_name AS UserName, 
                                        cast(dbo.GetAmountUsed(dbo.session_header.win_user_id, dbo.course.course_id, dbo.course.no_of_questionsets_in_course) as nvarchar(10)) AS AmountUsed, 
                                        Isnull(cast(dbo.GetAnswerCorrectly(dbo.session_header.win_user_id, dbo.course.course_id, dbo.question_set.no_of_questions) as nvarchar(10)),0) AS AnsweredCorrectly, 
                                        dbo.course.course_name AS CourseName, 
                                        dbo.course.course_code,
                                        dbo.course.no_of_questions_in_course AS NoOfQuestionsInCourse, 
                                        dbo.course.no_of_questionsets_in_course AS NoOfQuestionSetsInCourse
                        FROM            dbo.session_detail 
                                        INNER JOIN dbo.session_header ON dbo.session_detail.session_header_id = dbo.session_header.session_header_id
                                        INNER JOIN dbo.win_user ON dbo.session_header.win_user_id = dbo.win_user.win_user_id
                                        INNER JOIN dbo.win_user_course ON dbo.win_user_course.win_user_id = dbo.win_user.win_user_id
                                        INNER JOIN dbo.question_set ON dbo.session_header.question_set_id = dbo.question_set.question_set_id
                                        RIGHT OUTER JOIN dbo.course ON dbo.win_user_course.course_id = dbo.course.course_id
                        WHERE           (dbo.session_detail.no_of_attempts = 1 OR dbo.session_detail.no_of_attempts IS NULL)
                                        AND (dbo.session_detail.is_correct = 1 OR dbo.session_detail.is_correct IS NULL)
                                        AND (dbo.win_user_course.is_active = 'True')
                        GROUP BY        dbo.win_user.user_name, dbo.course.course_name, dbo.question_set.no_of_questions, dbo.course.no_of_questions_in_course, 
                                        dbo.course.no_of_questionsets_in_course, dbo.session_header.win_user_id, dbo.course.course_id, dbo.course.course_code

                    UNION ALL

                        -- Table 2 - All UserAccount/Course combinations that do or do not have quizzes but where the Course is selected for quizzes for that User Account.
                        SELECT          dbo.win_user.user_name AS UserName, 
                                        -1 AS AmountUsed, 
                                        -1 AS AnsweredCorrectly, 
                                        dbo.course.course_name AS CourseName, 
                                        dbo.course.course_code,
                                        dbo.course.no_of_questions_in_course AS NoOfQuestionsInCourse, 
                                        dbo.course.no_of_questionsets_in_course AS NoOfQuestionSetsInCourse
                        FROM            dbo.win_user_course
                                        INNER JOIN dbo.win_user ON dbo.win_user_course.win_user_id = dbo.win_user.win_user_id
                                        RIGHT OUTER JOIN dbo.course ON dbo.win_user_course.course_id = dbo.course.course_id
                        WHERE           (dbo.win_user_course.is_active = 'True')
                        GROUP BY        dbo.win_user.user_name, dbo.course.course_name, dbo.course.no_of_questions_in_course, 
                                        dbo.course.no_of_questionsets_in_course, dbo.course.course_id, dbo.course.course_code

                ) dt_derivedTable_1 

                GROUP BY CourseName, UserName

--      UNION ALL

            -- Table 3 - All Courses.
--          SELECT DISTINCT null AS UserName,
--                          -2 AS AmountUsed, 
--                          -2 AS AnsweredCorrectly, 
--                          dbo.course.course_name AS CourseName,
--                          dbo.course.course_code,
--                          dbo.course.no_of_questions_in_course AS NoOfQuestionsInCourse, 
--                          dbo.course.no_of_questionsets_in_course AS NoOfQuestionSetsInCourse
--          FROM            dbo.course
--          WHERE           is_active = 'True'


--  ) dt_derivedTable_2 

--  GROUP BY CourseName
--  ORDER BY CourseName

2 个答案:

答案 0 :(得分:1)

有了这样的过滤要求(取决于先前查询的行),我建议使用表变量。

DECLARE @MyTable TABLE
(
  ID int PRIMARY KEY,
  Name varchar(50),
  QueryNumber int
)

INSERT INTO @MyTable (ID, Name, QueryNumber)
SELECT CustomerID, CustomerName, 1
FROM Customer
WHERE Name = "Bob"

INSERT INTO @MyTable (ID, Name, QueryNumber)
SELECT CustomerID, CustomerName, 2
FROM Customer
WHERE Name = "Joe" and CustomerID not in (SELECT ID FROM @MyTable)

INSERT INTO @MyTable (ID, Name, QueryNumber)
SELECT CustomerID, CustomerName, 3
FROM Customer
WHERE CustomerID not in (SELECT ID FROM @MyTable)

SELECT *
FROM @MyTable

答案 1 :(得分:0)

这是一个Oracle风格的解决方案:

    Select 
        *
    from table1

    UNION

    select 
        *
    from table2
    where not exists(
        select 'x' 
        from table1
        where 
            table2.username = table1.username
            and table2.coursename = table1.coursename
    )

    UNION

    select 
        *
    from table3
    where
        coursename not in (
            Select 
                coursename                                                  
            from table1

            UNION /* the union operator implies distinct, so 
                    there will be no duplicates */

            select 
                coursename
            from table2
            where not exists(
                select 'x' 
                from table1
                where 
                    table2.username = table1.username
                    and table2.coursename = table1.coursename
            )
        )