Como o título sugere, preciso de ajuda para obter um total em execução no T-SQL. O problema é que a soma que preciso fazer é a soma de uma contagem:
sum(count (distinct (customers)))
Digamos que, se eu fizesse a contagem sozinho, o resultado seria:
Day | CountCustomers
----------------------
5/1 | 1
5/2 | 0
5/3 | 5
Eu preciso de saída com a soma para ser:
Day | RunningTotalCustomers
----------------------
5/1 | 1
5/2 | 1
5/3 | 6
Eu já executei totais antes de usar o coalesce
método, mas nunca com uma contagem. Não sei como fazê-lo agora que tenho a contagem.
sql-server
t-sql
Aaron Bertrand
fonte
fonte
Day
uma chave e os valores são contíguos?Respostas:
Aqui estão alguns métodos que você pode comparar. Primeiro vamos configurar uma tabela com alguns dados fictícios. Estou preenchendo isso com um monte de dados aleatórios de sys.all_columns. Bem, é meio aleatório - estou garantindo que as datas sejam contíguas (o que é realmente importante apenas para uma das respostas).
Resultados:
Os dados são assim (5000 linhas) - mas parecerão um pouco diferentes no seu sistema, dependendo da versão e número da compilação:
E os resultados dos totais em execução devem ficar assim (501 linhas):
Portanto, os métodos que vou comparar são:
auto-junção
É assim que as pessoas o instruem a fazê-lo quando o alertam para ficar longe dos cursores, porque "baseado em conjuntos é sempre mais rápido". Em algumas experiências recentes, descobri que o cursor ultrapassa essa solução.
cte recursivo com datas
Lembrete - isso depende de datas contíguas (sem intervalos), até 10000 níveis de recursão e que você saiba a data de início do intervalo em que está interessado (para definir a âncora). Você pode definir a âncora dinamicamente usando uma subconsulta, é claro, mas eu queria manter as coisas simples.
cte recursivo com row_number
O cálculo do número da linha é um pouco caro aqui. Novamente, isso suporta o nível máximo de recursão de 10000, mas você não precisa atribuir a âncora.
cte recursivo com tabela temporária
Roubo da resposta de Mikael, como sugerido, para incluí-lo nos testes.
atualização peculiar
Mais uma vez, estou incluindo isso apenas por completude; Pessoalmente, eu não confiaria nessa solução, pois, como mencionei em outra resposta, não é garantido que este método funcione e pode ser completamente interrompido em uma versão futura do SQL Server. (Estou fazendo o possível para forçar o SQL Server a obedecer a ordem que desejo, usando uma dica para a escolha do índice.)
cursor
"Cuidado, existem cursores aqui! Cursores são maus! Você deve evitar cursores a todo custo!" Não, isso não sou eu falando, são coisas que eu ouço muito. Ao contrário da opinião popular, existem alguns casos em que os cursores são apropriados.
SQL Server 2012
Se você está na versão mais recente do SQL Server, os aprimoramentos na funcionalidade de janelas permitem calcular facilmente os totais em execução sem o custo exponencial da auto-associação (o SUM é calculado em uma passagem), a complexidade dos CTEs (incluindo o requisito de linhas contíguas para o melhor desempenho da CTE), a atualização peculiar não suportada e o cursor proibido. Apenas tenha cuidado com a diferença entre usar
RANGE
eROWS
, ou não especificar, apenasROWS
evita um spool no disco, o que dificultará significativamente o desempenho.comparações de desempenho
Peguei cada abordagem e agrupei um lote usando o seguinte:
Aqui estão os resultados da duração total, em milissegundos (lembre-se de incluir também os comandos DBCC sempre):
E fiz de novo sem os comandos DBCC:
Removendo o DBCC e os loops, apenas medindo uma iteração bruta:
Finalmente, multipliquei a contagem de linhas na tabela de origem por 10 (alterando o topo para 50000 e adicionando outra tabela como uma junção cruzada). Os resultados disso, uma única iteração sem comandos DBCC (simplesmente no interesse do tempo):
Apenas medi a duração - deixarei como um exercício para o leitor comparar essas abordagens em seus dados, comparando outras métricas que podem ser importantes (ou podem variar de acordo com o esquema / dados). Antes de tirar conclusões dessa resposta, você deve testá-lo com base em seus dados e seu esquema ... esses resultados quase certamente mudarão à medida que a contagem de linhas aumentar.
demonstração
Eu adicionei um sqlfiddle . Resultados:
conclusão
Nos meus testes, a escolha seria:
Mas, novamente, você deve testá-los no seu esquema e dados. Como este foi um teste artificial com contagens de linha relativamente baixas, também pode ser um peido ao vento. Fiz outros testes com contagens diferentes de esquema e linha, e as heurísticas de desempenho eram bem diferentes ... e foi por isso que fiz tantas perguntas de acompanhamento à sua pergunta original.
ATUALIZAR
Eu escrevi mais sobre isso aqui:
Melhores abordagens para execução de totais - atualizado para o SQL Server 2012
fonte
Aparentemente, esta é a solução ideal
fonte
day
por exemplo.Apenas outra maneira, cara, mas independente de versão. Ele não usa tabelas ou variáveis temporárias.
fonte