【问题标题】:simple sql query with count带计数的简单 sql 查询
【发布时间】:2012-10-25 00:26:43
【问题描述】:

我正在使用 SQLite。 我需要帮助来解决一个简单的问题。 这是我的三张桌子:

--------------
problem
--------------
id (primary key)
question_id (foreign key)

--------------
question
--------------
id (primary key)
answer_id (foreign key)

--------------
answer
--------------
id (primary key)

我想获得在每个问题中至少有 N 个答案的所有问题。我给你举个例子:

-------
problem
id 
1
2


-------
question 
id   problem_id
1    1
2    1
3    1
4    2

-------
answer
id   question_id
1    1
2    1
3    1
4    2
5    2
6    3
7    4
8    4

如果 n=2,我的结果应该是 issue_id=2。

我试过了:

   select distinct question.problem_id 
   from answer, question
   where answer.question_id = question.id
   group by answer.question_id
   having count(*) >= 2

但它不起作用,因为它会遇到至少一个问题至少有 2 个答案的问题。所有问题都必须满足该条件。

有什么问题吗?

【问题讨论】:

    标签: sql sqlite count nested


    【解决方案1】:
    select problem_id
    from
    (
        select q.problem_id, q.id, count(a.id) answercount
        from question q
        left join answer a on a.question_id = q.id
        group by q.problem_id, q.id
    ) g
    group by problem_id
    having min(answercount) >= 2
    

    备选方案(例如 4 个答案)

    select distinct q.problem_id
    from question q
    left join answer a on a.question_id = q.id
    left join answer b on b.question_id = q.id and a.id < b.id
    left join answer c on c.question_id = q.id and b.id < c.id
    left join answer d on d.question_id = q.id and c.id < d.id
    where d.id is not null
    

    您可以根据需要扩展此模式。如果你真的需要一个参数化的查询,你可以做一些疯狂的事情,比如加入 6 次,改变 WHERE 子句如下:

    where case when f.id is not null then 6
               when e.id is not null then 5
               when d.id is not null then 4
               when c.id is not null then 3
               when b.id is not null then 2
               else 1 end >= {{YourParamHere}}
    

    【讨论】:

    • 这似乎是正确的,但我的 sqlite 版本有一些问题,所以在执行“select from (select...)”时有一个错误。还有另一种方法来编写该查询吗?谢谢!
    • 我没有忘记这一点。在外部软件中(可能使用不同的 sqlite 版本)它可以工作,但在我的没有,我无法更改它,所以我必须以另一种方式编写该查询,也许使用 INTERSECT?
    • 我添加了一个替代查询
    • 感谢您的宝贵时间。您能解释一下替代查询中条件 min(answercount) >= 2 的位置吗?结果与第一个不同。
    • 也许这就是我错过DISTINCT 的地方。它可以 LEFT JOIN 两次得到两个不同的答案 a.id &lt; b.id 的事实意味着至少有两个答案。
    【解决方案2】:

    这是我在 T-SQL 中的问题:

    declare @problem table(id bigint not null primary key clustered)
    declare @question table(id bigint not null primary key clustered, problem_id bigint)
    declare @answer table(id bigint not null primary key clustered, question_id bigint)
    
    declare @n int = 2
    
    insert @problem
          select 1 
    union select 2
    
    insert @question
          select 1, 1 
    union select 2, 1
    union select 3, 1
    union select 4, 2
    
    insert @answer 
          select 1, 1 
    union select 2, 1
    union select 3, 1
    union select 4, 2
    union select 5, 2
    union select 6, 3
    union select 7, 4
    union select 8, 4
    
    select p.id --, p.name, p.description, p.etc
    from @problem p
    where @n >= ALL --http://msdn.microsoft.com/en-us/library/ms178543.aspx
    (
        select COUNT(a.id) 
        from @question q
        left outer join @answer a
            on q.id = a.question_id
        where p.id = q.problem_id
        group by q.id
    )
    

    注意:表格架构与问题略有不同,因为问题中的架构与示例数据不匹配。

    替代方案

    (基于@RichardTheKiwi 的回答,内部 SQL 已移至临时表)

    declare @tempTable table (pid bigint, qid bigint, aidCount bigint)
    
    insert @tempTable
    select q.problem_id, q.id, count(a.id) answercount
    from @question q
    left join @answer a on a.question_id = q.id
    group by q.problem_id, q.id
    
    select pid
    from @tempTable
    group by pid 
    having min(aidCount) >= @n 
    

    【讨论】:

    • 感谢您的回答。我已经复制并粘贴了,但是我的 sqlite 似乎不支持“ALL”字样,它会产生错误
    • 不用担心 - 抱歉,它在 SQLite 上表现不佳;可悲的是,我没有要测试的副本。 @RichardTheKiwi 的回答看起来不错。如果他的回答不起作用,您可以尝试调整它,以便将内部查询加载到临时表中,使用临时表而不是括号内的内部查询。
    • 我认为这可能是一个解决方案。如何改变内部查询?它找不到 p.id
    • 我将结果拆分为一个临时表,现在它可以工作了!非常感谢!
    【解决方案3】:

    重写为相关子查询。我们不是在每个问题中找到至少有 N 个答案的问题,而是找到没有少于 N 个答案的问题的问题:

    SELECT id AS problem_id
    FROM problem AS p 
    WHERE NOT EXISTS
          ( SELECT 1
            FROM question AS q
              LEFT JOIN answer AS a 
                ON a.question_id = q.id
            WHERE q.problem_id = p.id
            GROUP BY q.id
            HAVING COUNT(a.question_id) < 2
          ) ;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多