MySQL:如何使用GROUP BY选择每个组的第N个值

时间:2015-04-09 20:44:46

标签: mysql group-by

我想选择每个new_threads组的第二个响应列值,如果它是1行组,则为零值。

new_treads|response
------------------
 1        | 0        
 1        | 1
 2        | 0    
 2        | 0
 2        | 1
 ...      | ...
 9        | 0     
 9        | 1    
 9        | 0   
 10       | 0  

输出为:

new_treads|response
------------------
 1        | 1
 2        | 0
 ...      | ...
 9        | 1    
 10       | 0  

到目前为止,我理解如何使用MIN获得第一个,但我需要第二个

SELECT 
thread,
min(response)
FROM messages
GROUP BY thread;

我想使用GROUP BY,因为我也在使用GROUP BY来处理其他SELECT

谢谢!

3 个答案:

答案 0 :(得分:2)

由于行没有“编号”,您需要为每个组创建一个数字,然后选择它。我会用用户变量做到这一点:

select thread, response
from (
        select @n := (case 
                when m.thread = @prev_thread then @n 
                else 0 
            end) + 1 as n    -- If the current thread is the same as the
                             -- previous row, then increase the counter,
                             -- else, reset it
             , @prev_thread := m.thread as thread -- Update the value of
                                                  -- @prev_thread
             , m.response
        from 
               (select @n := 0, @prev_thread := 0) as init
                          -- The 'init' subquery initializes the 
                          -- temp variables:
                          --     @n is a counter
                          --     @prev_thread is an identifier for the
                          --     previous thread id
             , messages as m
        order by m.thread -- You need to add a second column to order 
                          -- each response (such as "response_id", or
                          -- something like that), otherwise the returned
                          -- row may be a random one
    ) as a
where n = 2;    -- Select the rows from the subquery where the counter equals 2

上面的工作非常精细,可以找到每组的第二行,但前提是只有一行。现在:如果没有第二行,如何获得NULL值?

最简单的方法是使用左连接:

select t.thread, b.response
from (select distinct thread from messages) as t
     left join (
         -- Put the above query here
     ) as b on t.thread = b.thread;

答案 1 :(得分:0)

SELECT 
thread,
min(response)
FROM messages
GROUP BY thread
HAVING response > min(response)

尝试这只是想知道它是否有效

答案 2 :(得分:0)

我想详细说明上面的答案。虽然它对我来说效果很好,但是花了一些时间将上下文拼凑在一起并进行概括,以便将其应用到我的代码中。我希望这个答案能更好地概括上面列出的内容......

SELECT *
FROM  (SELECT distinct keyField    --- keyField is the field the query is grouping by
        FROM TABLE
        --  Add keyField Constraint --
        --  Add non-keyField Constraint --     
INNER JOIN (SELECT *,
       @n:=(CASE                                -- Iterating through...
               WHEN keyField = @prev_keyField   -- When keyField value == previous keyField value
               THEN @n:=@n+1                    -- Define n as the row in the group
               ELSE 1                           -- When keyField value != previous keyField value, then n is the 1st row in the group
               END) as n,
            @prev_keyField:= keyField           -- Define previous keyField value for the next iteration
            FROM (SELECT @n:=0,@prev_keyField:=0) r,TABLE as p
            --  Add non-keyField Constraint--  
            ORDER BY keyField,sortField DESC    -- Order by keyField and the field you are sorting by
                                                --  ei. keyField could be `thread`, 
                                                --  and sort field could be `timestamp` if you are sorting by time
            ) s ON s.keyField = p.keyField
WHERE s.n = 2                                   -- Define which row in the group you want in the query