Eu criei um SQL Fiddle para essa pergunta, se isso facilitar as coisas para qualquer pessoa.
Eu tenho um tipo de banco de dados de esportes de fantasia e o que estou tentando descobrir é como criar dados de "sequência atual" (como 'W2' se a equipe venceu seus últimos 2 confrontos, ou 'L1' se eles perderam sua última luta depois de vencer a luta anterior - ou 'T1' se eles empataram a luta mais recente).
Aqui está o meu esquema básico:
CREATE TABLE FantasyTeams (
team_id BIGINT NOT NULL
)
CREATE TABLE FantasyMatches(
match_id BIGINT NOT NULL,
home_fantasy_team_id BIGINT NOT NULL,
away_fantasy_team_id BIGINT NOT NULL,
fantasy_season_id BIGINT NOT NULL,
fantasy_league_id BIGINT NOT NULL,
fantasy_week_id BIGINT NOT NULL,
winning_team_id BIGINT NULL
)
Um valor de NULL
na winning_team_id
coluna indica um empate para essa correspondência.
Aqui está um exemplo de instrução DML com alguns dados de exemplo para 6 equipes e 3 semanas de confrontos:
INSERT INTO FantasyTeams
SELECT 1
UNION
SELECT 2
UNION
SELECT 3
UNION
SELECT 4
UNION
SELECT 5
UNION
SELECT 6
INSERT INTO FantasyMatches
SELECT 1, 2, 1, 2, 4, 44, 2
UNION
SELECT 2, 5, 4, 2, 4, 44, 5
UNION
SELECT 3, 6, 3, 2, 4, 44, 3
UNION
SELECT 4, 2, 4, 2, 4, 45, 2
UNION
SELECT 5, 3, 1, 2, 4, 45, 3
UNION
SELECT 6, 6, 5, 2, 4, 45, 6
UNION
SELECT 7, 2, 6, 2, 4, 46, 2
UNION
SELECT 8, 3, 5, 2, 4, 46, 3
UNION
SELECT 9, 4, 1, 2, 4, 46, NULL
GO
Aqui está um exemplo da saída desejada (com base no DML acima) que eu estou tendo problemas para começar a descobrir como derivar:
| TEAM_ID | STEAK_TYPE | STREAK_COUNT |
|---------|------------|--------------|
| 1 | T | 1 |
| 2 | W | 3 |
| 3 | W | 3 |
| 4 | T | 1 |
| 5 | L | 2 |
| 6 | L | 1 |
Eu tentei vários métodos usando subconsultas e CTE, mas não consigo montá-lo. Gostaria de evitar o uso de um cursor, pois poderia ter um grande conjunto de dados para executar isso no futuro. Eu sinto que pode haver uma maneira de envolver variáveis de tabela que associam esses dados a si mesmos de alguma forma, mas ainda estou trabalhando nisso.
Informações adicionais: pode haver um número variável de equipes (qualquer número par entre 6 e 10) e o total de confrontos aumentará em 1 para cada equipe a cada semana. Alguma idéia de como devo fazer isso?
fonte
bigint
para tantas colunas ondeint
provavelmente faria 3) por que todos os_
s ?! 4) Eu prefiro nomes de tabela a ser singular, mas reconhecem nem todos concordam comigo // mas aqueles de lado o que você mostrou-nos aqui parece coerente, simRespostas:
Como você está no SQL Server 2012, você pode usar algumas das novas funções de janelas.
SQL Fiddle
C1
calcula ostreak_type
para cada equipe e partida.C2
encontra o anteriorstreak_type
ordenado pormatch_id desc
.C3
gera uma soma em execuçãostreak_sum
ordenada,match_id desc
mantendo um0
a enquanto ostreak_type
é o mesmo que o último valor.A consulta principal resume as faixas onde
streak_sum
está0
.fonte
LEAD()
. Não basta as pessoas sabem sobre as novas funções de janela, em 2012FantasyTeams JOIN FantasyMatches
porFantasyMatches CROSS APPLY (VALUES (home_fantasy_team_id), (away_fantasy_team_id))
e, potencialmente, melhorar o desempenho.FantasyTeams
, provavelmente será melhor ingressar na consulta principal.Uma abordagem intuitiva para resolver esse problema é:
Essa estratégia pode vencer a solução da função de janela (que executa uma varredura completa dos dados) à medida que a tabela aumenta, assumindo que a estratégia recursiva seja implementada com eficiência. A chave para o sucesso é fornecer índices eficientes para localizar linhas rapidamente (usando pesquisas) e evitar classificações. Os índices necessários são:
Para ajudar na otimização de consultas, usarei uma tabela temporária para manter as linhas identificadas como parte de uma sequência atual. Se as faixas são geralmente curtas (como é verdade para as equipes que sigo, infelizmente), esta tabela deve ser bem pequena:
Minha solução de consulta recursiva é a seguinte ( SQL Fiddle aqui ):
O texto T-SQL é bastante longo, mas cada seção da consulta corresponde ao esboço geral do processo fornecido no início desta resposta. A consulta é prolongada pela necessidade de usar certos truques para evitar classificações e produzir um
TOP
na parte recursiva da consulta (o que normalmente não é permitido).O plano de execução é relativamente pequeno e simples em comparação com a consulta. Sombrei a região da âncora em amarelo e a parte recursiva em verde na captura de tela abaixo:
Com as linhas de sequência capturadas em uma tabela temporária, é fácil obter os resultados resumidos necessários. (O uso de uma tabela temporária também evita um derramamento de classificação que pode ocorrer se a consulta abaixo for combinada com a consulta recursiva principal)
A mesma consulta pode ser usada como base para atualizar a
FantasyTeams
tabela:Ou, se você preferir
MERGE
:Qualquer uma das abordagens produz um plano de execução eficiente (com base no número conhecido de linhas na tabela temporária):
Finalmente, como o método recursivo inclui naturalmente o
match_id
processo, é fácil adicionar uma lista dosmatch_id
s que formam cada sequência à saída:Resultado:
Plano de execução:
fonte
EXISTS (... INTERSECT ...)
vez de apenasStreaks.streak_type = CASE ...
? Eu sei que o primeiro método pode ser útil quando você precisa corresponder nulos em ambos os lados, bem como os valores, mas não é como se a peça certa pode produzir quaisquer nulos, neste caso, então ...CASE
é usado, o otimizador não pode usar uma concatenação de mesclagem (que preserva a ordem das chaves de união) e usa uma concatenação mais classificações.Outra maneira de obter o resultado é por meio de uma CTE recursiva
Demonstração do SQLFiddle
fonte