Existe uma maneira agradável no MySQL de replicar a função SQL Server ROW_NUMBER()
?
Por exemplo:
SELECT
col1, col2,
ROW_NUMBER() OVER (PARTITION BY col1, col2 ORDER BY col3 DESC) AS intRow
FROM Table1
Por exemplo, eu poderia adicionar uma condição para limitar intRow
a 1 para obter uma única linha com a maior col3
para cada (col1, col2)
par.
greatest-n-per-group
para guiá-lo para perguntas semelhantes.Sql-Server
Etiqueta removida, pois era o item com o maior número de votos na pesquisa combinada, mas não é realmente relevante para o SQL Server.Respostas:
Esse é o máximo de grupo , uma das perguntas mais frequentes sobre SQL (já que parece ser fácil, mas na verdade não é).
Costumo insistir em uma auto-junção nula:
"Obtenha as linhas da tabela para as quais nenhuma outra linha com col1 correspondente, col2 tem um col3 mais alto." (Você notará que essa e a maioria das outras soluções de grupo máximo retornarão várias linhas se mais de uma linha tiver a mesma col1, col2, col3. Se for um problema, talvez seja necessário algum pós-processamento.)
fonte
SELECT t1.id FROM test t1 LEFT JOIN test t2 ON t1.id>t2.id WHERE t2.id IS NULL;
Não requern*n/2 + n/2
comparações IS NULL para encontrar a única linha? Ocorre alguma otimização que não vejo? Tentei fazer a pergunta semelhante a Bill em outro tópico, mas ele parece ter ignorado.SELECT t0.col3 FROM table AS t0 WHERE NOT EXISTS (select 1 from table AS t1 ON t0.col1=t1.col1 AND t0.col2=t1.col2 AND t1.col3>t0.col3)
Não há funcionalidade de classificação no MySQL. O mais próximo que você pode chegar é usar uma variável:
Sim. Se fosse o Oracle, você poderia usar a função LEAD para atingir o pico no próximo valor. Felizmente, Quassnoi cobre a lógica do que você precisa implementar no MySQL .
fonte
SELECT @row_num:=@row_num+1 AS row_number, t.id FROM (SELECT * FROM table1 WHERE col = 264 ORDER BY id) t, (SELECT @row_num:=0) var;
Eu sempre acabo seguindo esse padrão. Dada esta tabela:
Você pode obter este resultado:
Executando esta consulta, que não precisa de nenhuma variável definida:
Espero que ajude!
fonte
<
,>
,<=
,>=
CHAR punho e tipos de dados VARCHAR em ordem alfabética; Espero, é exatamente o que você está procurando.row_numbers <= 2
E muito obrigado por essa resposta Mosty, é perfeito!fonte
Confira este artigo, ele mostra como imitar o SQL ROW_NUMBER () com uma partição no MySQL. Encontrei esse mesmo cenário em uma implementação do WordPress. Eu precisava de ROW_NUMBER () e não estava lá.
http://www.explodybits.com/2011/11/mysql-row-number/
O exemplo no artigo está usando uma única partição por campo. Para particionar por campos adicionais, você pode fazer algo assim:
O uso de concat_ws manipula nulos. Testei isso em três campos usando int, date e varchar. Espero que isto ajude. Confira o artigo, que detalha essa consulta e a explica.
fonte
limit 18446744073709551615
aorder by
cláusula for force .concat_ws
com a corda vazia''
é perigoso:concat_ws('',12,3) = concat_ws('',1,23)
. Melhor usar algum separador'_'
ou usar a solução @Kenneth Xu.De
MySQL 8.0.0
e acima, você pode usar funções nativas em janelas.1.4 O que há de novo no MySQL 8.0 :
Over_clause ROW_NUMBER () :
Demo:
DBFiddle Demo
fonte
Também votaria na solução de Mosty Mostacho com pequenas modificações em seu código de consulta:
O que dará o mesmo resultado:
para a mesa:
Com a única diferença de que a consulta não usa JOIN e GROUP BY, dependendo da seleção aninhada.
fonte
Eu definiria uma função:
então eu poderia fazer:
Agora você não tem uma subconsulta, que não pode ter em visualizações.
fonte
consulta para row_number no mysql
fonte
Não existe nenhuma função
rownum
, comorow_num()
no MySQL, mas o caminho a seguir é como abaixo:fonte
A solução que achei melhor funcionou foi usar uma subconsulta como esta:
As colunas PARTITION BY são comparadas com '=' e separadas por AND. As colunas ORDER BY seriam comparadas com '<' ou '>' e separadas por OR.
Eu achei isso muito flexível, mesmo que seja um pouco caro.
fonte
A funcionalidade de número de proprietário não pode ser imitada. Você pode obter os resultados esperados, mas provavelmente ficará decepcionado em algum momento. Aqui está o que a documentação do mysql diz:
Atenciosamente, Georgi.
fonte
O MariaDB 10.2 está implementando "Funções da Janela", incluindo RANK (), ROW_NUMBER () e várias outras coisas:
https://mariadb.com/kb/en/mariadb/window-functions/
Com base em uma palestra no Percona Live este mês, eles estão razoavelmente bem otimizados.
A sintaxe é idêntica ao código na pergunta.
fonte
Não vejo uma resposta simples que cubra a parte "PARTITION BY", então aqui está a minha:
Neste exemplo simples, coloquei apenas um, mas você pode ter várias partes "PARTITION BY"
fonte
Um pouco tarde, mas também pode ajudar alguém que procura respostas ...
Exemplo entre linhas / número da linha - consulta recursiva que pode ser usada em qualquer SQL:
fonte
Isso permite que a mesma funcionalidade que ROW_NUMBER () AND PARTITION BY fornece seja alcançada no MySQL
fonte
Também um pouco tarde, mas hoje eu tinha a mesma necessidade, então pesquisei no Google e finalmente uma abordagem geral simples encontrada aqui no artigo de Pinal Dave http://blog.sqlauthority.com/2014/03/09/mysql-reset-row -número-para-cada-grupo-partição-por-número-de-linha /
Eu queria focar na pergunta original de Paul (que também era meu problema), então resumi minha solução como um exemplo de trabalho.
Porque queremos particionar em duas colunas, eu criaria uma variável SET durante a iteração para identificar se um novo grupo foi iniciado.
O 3 significa, no primeiro parâmetro de MAKE_SET, que eu quero os dois valores no SET (3 = 1 | 2). Obviamente, se não tivermos duas ou mais colunas construindo os grupos, podemos eliminar a operação MAKE_SET. A construção é exatamente a mesma. Isso está funcionando para mim, conforme necessário. Muito obrigado a Pinal Dave por sua demonstração clara.
fonte
ORDER BY
em uma subconsulta pode ser ignorado (consulte mariadb.com/kb/en/mariadb/… ). A solução sugerida para isso é adicionarLIMIT 18446744073709551615
à subconsulta, o que força uma classificação. No entanto, isto pode causar problemas de desempenho e não é válida para realmente em pânico enormes mesas :)Isso também pode ser uma solução:
fonte
O MySQL suporta o ROW_NUMBER () desde a versão 8.0+ .
Se você usa o MySQL 8.0 ou posterior, verifique a função ROW_NUMBER (). Caso contrário, você emulará a função ROW_NUMBER ().
O número da linha () é uma função de classificação que retorna um número seqüencial de uma linha, iniciando em 1 para a primeira linha.
para versão mais antiga,
fonte
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):
Como tal, existe o risco de que eles apresentem a resposta errada, porque geralmente fazem uma
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:
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:
Tem a forma geral:
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)
fonte
Essa não é a solução mais robusta - mas se você está apenas procurando criar uma classificação particionada em um campo com apenas alguns valores diferentes, pode não ser difícil usar alguns casos quando for lógico com tantas variáveis quantas forem necessárias.
Algo assim funcionou para mim no passado:
Espero que faça sentido / ajude!
fonte
Isso funciona perfeitamente para eu criar RowNumber quando temos mais de uma coluna. Neste caso, duas colunas.
fonte
fonte
fonte