Importante: Considere a atualização para o MySQL 8+ e use a função ROW_NUMBER () definida e documentada e evite hacks antigos vinculados a uma versão antiga limitada do MySQL com um recurso
Agora, aqui está um desses hacks:
As respostas aqui que usam variáveis na consulta principalmente / todas parecem ignorar o fato de que a documentação diz (paráfrase):
Não confie nos itens da lista SELECT que estão sendo avaliados em ordem de cima para baixo. Não atribua variáveis em um item SELECT e use-as em outro
Como tal, existe o risco de que eles apresentem a resposta errada, porque geralmente fazem uma
select
(row number variable that uses partition variable),
(assign partition variable)
Se alguma vez for avaliado de baixo para cima, o número da linha deixará de funcionar (sem partições)
Portanto, precisamos usar algo com uma ordem de execução garantida. Digite CASE QUANDO:
SELECT
t.*,
@r := CASE
WHEN col = @prevcol THEN @r + 1
WHEN (@prevcol := col) = null THEN null
ELSE 1 END AS rn
FROM
t,
(SELECT @r := 0, @prevcol := null) x
ORDER BY col
Como esboço ld, a ordem de atribuição do prevcol é importante - o prevcol deve ser comparado ao valor da linha atual antes de atribuirmos um valor a partir da linha atual (caso contrário, seria o valor da coluna da linha atual, não o valor da coluna da linha anterior) .
Veja como isso se encaixa:
O primeiro WHEN é avaliado. Se a coluna dessa linha for igual à coluna da linha anterior, @r será incrementado e retornado do CASE. Esses valores de led de retorno são armazenados em @r. É um recurso do MySQL que a atribuição retorna o novo valor do que é atribuído ao @r nas linhas de resultado.
Para a primeira linha do conjunto de resultados, @prevcol é nulo (inicializado como nulo na subconsulta), portanto, esse predicado é falso. Esse primeiro predicado também retorna false toda vez que a coluna é alterada (a linha atual é diferente da linha anterior). Isso faz com que o segundo WHEN seja avaliado.
O segundo predicado WHEN é sempre falso e existe apenas para atribuir um novo valor a @prevcol. Como o col da linha é diferente do col da linha anterior (sabemos disso porque, se fosse o mesmo, o primeiro WHEN teria sido usado), precisamos atribuir o novo valor para mantê-lo para teste na próxima vez. Como a atribuição é feita e, em seguida, o resultado da atribuição é comparado com nulo, e qualquer coisa equiparada a nulo é falsa, esse predicado é sempre falso. Mas, pelo menos, avaliar se fez o trabalho de manter o valor de col nessa linha, para que possa ser avaliado com relação ao valor de col da próxima linha
Como o segundo WHEN é falso, significa que nas situações em que a coluna pela qual particionamos (col) foi alterada, é o ELSE que fornece um novo valor para @r, reiniciando a numeração de 1
Nós chegamos a uma situação em que:
SELECT
t.*,
ROW_NUMBER() OVER(PARTITION BY pcol1, pcol2, ... pcolX ORDER BY ocol1, ocol2, ... ocolX) rn
FROM
t
Tem a forma geral:
SELECT
t.*,
@r := CASE
WHEN col1 = @pcol1 AND col2 = @pcol2 AND ... AND colX = @pcolX THEN @r + 1
WHEN (@pcol1 := pcol1) = null OR (@pcol2 := col2) = null OR ... OR (@pcolX := colX) = null THEN null
ELSE 1
END AS rn
FROM
t,
(SELECT @r := 0, @pcol1 := null, @pcol2 := null, ..., @pcolX := null) x
ORDER BY pcol1, pcol2, ..., pcolX, ocol1, ocol2, ..., ocolX
Notas de rodapé:
OP in pcol significa "partição", o o ocol significa "ordem" - na forma geral, removi o "prev" do nome da variável para reduzir a desordem visual
Os suportes ao redor (@pcolX := colX) = null
são importantes. Sem eles, você atribuirá null ao @pcolX e as coisas param de funcionar
É um compromisso que o conjunto de resultados também tenha que ser ordenado pelas colunas da partição, para que a comparação anterior funcione. Portanto, você não pode ter seu número de ordenador ordenado de acordo com uma coluna, mas seu conjunto de resultados ordenado para outro. Você pode resolver isso com subconsultas, mas acredito que os documentos também afirmam que a ordenação de subconsultas pode ser ignorada, a menos que LIMIT seja usado e isso possa afetar desempenho
Eu não investiguei além do teste de que o método funciona, mas se houver o risco de que os predicados no segundo WHEN sejam otimizados (qualquer coisa comparada a null é nula / falsa, por que se preocupar em executar a atribuição) e não executada , também para. Parece que isso não aconteceu na minha experiência, mas aceitarei com prazer comentários e proponho uma solução se isso ocorrer razoavelmente
Pode ser aconselhável converter os nulos que criam @pcolX nos tipos reais de suas colunas, na subconsulta que cria as variáveis @pcolX, a saber: select @pcol1 := CAST(null as INT), @pcol2 := CAST(null as DATE)
greatest-n-per-group
para guiá-lo para perguntas semelhantes.