如果表包含具有特定值的另一行,如何从查询中过滤掉一行

时间:2014-08-21 09:54:00

标签: sql tsql stored-procedures where-clause

我们有一个问答表。表格和内容如下,每位用户保留答案。

Answer table:
FKQID       Answ        UserID
1           Y           1
2           Y           2

Question table:
ID      Question
1       Do you agree to x and y?
2       Do you agree to x, y and z?

我们想要更改问题但我们无法更改现有行的问题,因为我们无法保留有关哪些用户在此问题之前回答问题的历史数据#39;改变了。我们有一个存储过程,用于返回用户提供的问题及其答案:

CREATE PROCEDURE spGetUserQuestionAndAnswers
    @UserID int 
AS
BEGIN
    DECLARE @temp Table
    (
        QID int,
        Question nvarchar(200),
        Answer nvarchar(200)
    )

    INSERT INTO @temp 
        SELECT * FROM
        (
            Select q.ID as QID,
            Ques,
            (
                SELECT Answ FROM Answer
                WHERE Answer.UserID = @UserID
                AND q.ID = FKQID
            ) As Ans
            FROM Question q
        ) qq
        --WHERE 1 = CASE WHEN QID = 1 AND Ans IS NULL THEN 0 ELSE 1 END --Can't use this 'cos too slow 

    --If I filter @temp with the where clause above then I can do something like
    --this below but it slows down the above query too much
    --DECLARE @1WasAnsweredBefore
    --SET @1WasAnsweredBefore = CAST(SELECT COUNT(*) FROM @temp WHERE QID = 1 AS bit)
    --SELECT * FROM @temp t
    --WHERE 1 = CASE WHEN QID = 2 AND @1WasAnsweredBefore THEN 0 ELSE 1 END

    SELECT * FROM @temp t
    WHERE 1 = CASE WHEN QID = 1 AND t.Answer IS NULL THEN 0 ELSE 1 END
    --AND IF @temp has QID = 1, THEN Exclude QID = 2 ????
END

这将返回用户的问题和答案。如果用户第一次回答问题,则答案为NULL,这很好。

我需要做的是如果用户之前没有回答QID = 1(Ans IS NULL)然后向用户显示Q 2,我在最后一个WHERE中过滤掉了。我不能做的是,如果结果集包含Q 1,意味着它之前被用户回答,然后过滤掉Q 2. SP中的注释掉的行就是我尝试但是如果我把WHERE过滤器放在执行插入的SELECT,然后查询太慢。我能想到的另一个解决方案是在@temp上运行过滤器,从@temp执行另一次插入到@ temp2并在@temp中存在Q 1时排除Q 2但是感觉有点太多了,那可能是一个没有使用2个临时表的解决方案。

那么如果结果集包含Q 1,如何从结果集中排除Q 2?

编辑:我在上面提供了示例数据,这些数据足以说明问题。

致电

exec spGetUserQuestionAndAnswers 2

返回

QID Question                          Answer
2   Do you agree to x, y and z?       Y

这很好。用户2之前未回答Q 1,因此SP过滤掉Q1并返回Q2

致电

exec spGetUserQuestionAndAnswers 1

返回

QID Question                     Answer
1   Do you agree to x and y?     Y 
2   Do you agree to x, y and z?  NULL

这不好,它不应该包括Q2,因为用户之前已经回答了问题1。

2 个答案:

答案 0 :(得分:0)

这就是我解决这个问题的方法,但是如果你有一个不使用@ temp2的解决方案,或者更简单的解决方案,请告诉我。

ALTER PROCEDURE spGetUserQuestionAndAnswers
    @UserID int 
AS
BEGIN
    DECLARE @temp Table
    (
        QID int,
        Question nvarchar(200),
        Answer nvarchar(200)
    )

    INSERT INTO @temp 
        SELECT * FROM
        (
            Select q.ID as QID,
            Ques,
            (
                SELECT Answ FROM Answer
                WHERE Answer.UserID = @UserID
                AND q.ID = FKQID
            ) As Ans
            FROM Question q
        ) qq

    DECLARE @temp2 Table
    (
        QID int,
        Question nvarchar(200),
        Answer nvarchar(200)
    )

    Declare @Q1Exists bit
    SELECT @Q1Exists = CAST((SELECT Count(*) 
                                FROM @temp 
                                WHERE QID = 1 AND Answer IS NOT NULL) as bit)

    insert into @temp2      
    SELECT * FROM @temp t
    WHERE 1 = CASE WHEN QID = 1 AND t.Answer IS NULL THEN 0 
                    ELSE 1 END

    SELECT * FROM @temp2
    WHERE 1 = CASE WHEN QID = 2 THEN ~@Q1Exists 
    ELSE 1 END
END

答案 1 :(得分:0)

select max(ID) 
  from question  
  left join answer 
    on answer.FKQID = question.ID 
   and answer.Answ <> null
   and answer.UserID = @UserID
 where answer.FKQID is null