Você não escreveria um aplicativo com funções de 200 linhas. Você decomporia essas funções longas em funções menores, cada uma com uma única responsabilidade claramente definida.
Por que escrever seu SQL assim?
Decomponha suas consultas, assim como você decompõe suas funções. Isso os torna mais curtos, mais simples, mais fáceis de compreender, testar , refatorar. E permite que você adicione "shims" entre eles e "wrappers" ao redor deles, assim como você faz no código procedural.
Como você faz isso? Ao transformar cada coisa significativa que uma consulta faz em uma visualização. Então você compõe consultas mais complexas a partir dessas visualizações mais simples, da mesma forma que compõe funções mais complexas a partir de funções mais primitivas.
E o melhor de tudo é que, para a maioria das composições de visualizações, você obterá exatamente o mesmo desempenho de seu RDBMS. (Para alguns, você não vai; e daí? A otimização prematura é a raiz de todos os males. Codifique corretamente primeiro e, em seguida , otimize se necessário.)
Aqui está um exemplo do uso de várias visualizações para decompor uma consulta complicada.
No exemplo, como cada exibição adiciona apenas uma transformação, cada uma pode ser testada de forma independente para encontrar erros e os testes são simples.
Aqui está a tabela base no exemplo:
create table month_value(
eid int not null, month int, year int, value int );
Esta tabela é falha, porque usa duas colunas, mês e ano, para representar um dado, um mês absoluto. Aqui está nossa especificação para a nova coluna calculada:
Faremos isso como uma transformação linear, de forma que ela classifique da mesma forma que (ano, mês) e que, para qualquer tupla (ano, mês), haja um e somente valor, e todos os valores são consecutivos:
create view cm_absolute_month as
select *, year * 12 + month as absolute_month from month_value;
Agora, o que temos que testar é inerente à nossa especificação, ou seja, que para qualquer tupla (ano, mês), há um e apenas um (mês_determinado), e que (mês_bsoluto) são consecutivos. Vamos escrever alguns testes.
Nosso teste será uma select
consulta SQL , com a seguinte estrutura: um nome de teste e uma instrução case catenada. O nome do teste é apenas uma string arbitrária. A declaração do caso é apenas uma case when
declaração de testethen 'passed' else 'failed' end
.
As instruções de teste serão apenas seleções SQL (subconsultas) que devem ser verdadeiras para que o teste passe.
Aqui está nosso primeiro teste:
--a select statement that catenates the test name and the case statement
select concat(
-- the test name
'For every (year, month) there is one and only one (absolute_month): ',
-- the case statement
case when
-- one or more subqueries
-- in this case, an expected value and an actual value
-- that must be equal for the test to pass
( select count(distinct year, month) from month_value)
--expected value,
= ( select count(distinct absolute_month) from cm_absolute_month)
-- actual value
-- the then and else branches of the case statement
then 'passed' else 'failed' end
-- close the concat function and terminate the query
);
-- test result.
Executar essa consulta produz este resultado: For every (year, month) there is one and only one (absolute_month): passed
Desde que haja dados de teste suficientes em month_value, este teste funcionará.
Também podemos adicionar um teste para dados de teste suficientes:
select concat( 'Sufficient and sufficiently varied month_value test data: ',
case when
( select count(distinct year, month) from month_value) > 10
and ( select count(distinct year) from month_value) > 3
and ... more tests
then 'passed' else 'failed' end );
Agora vamos testar consecutivamente:
select concat( '(absolute_month)s are consecutive: ',
case when ( select count(*) from cm_absolute_month a join cm_absolute_month b
on ( (a.month + 1 = b.month and a.year = b.year)
or (a.month = 12 and b.month = 1 and a.year + 1 = b.year) )
where a.absolute_month + 1 <> b.absolute_month ) = 0
then 'passed' else 'failed' end );
Agora vamos colocar nossos testes, que são apenas consultas, em um arquivo e executar esse script no banco de dados. Na verdade, se armazenarmos nossas definições de visualização em um script (ou scripts, eu recomendo um arquivo por visualizações relacionadas) para ser executado no banco de dados, podemos adicionar nossos testes para cada visualização ao mesmo script, de modo que o ato de (re -) criar nossa visão também executa os testes da visão. Dessa forma, ambos obtemos testes de regressão quando recriamos as visualizações e, quando a criação da visualização é executada na produção, a visualização também será testada na produção.
Crie um banco de dados do sistema de teste que você pode recarregar com a freqüência que desejar. Carregue seus dados ou crie seus dados e salve-os. Produza uma maneira fácil de recarregá-lo. Anexe seu sistema de desenvolvimento a esse banco de dados e valide seu código antes de ir para a produção. Chute-se toda vez que você conseguir deixar um problema entrar em produção. Crie um conjunto de testes para verificar problemas conhecidos e aumente seu conjunto de testes com o tempo.
fonte
Você pode querer verificar DbUnit , então você pode tentar escrever testes de unidade para seus programas com um conjunto fixo de dados. Dessa forma, você deve ser capaz de escrever consultas com resultados mais ou menos previsíveis.
A outra coisa que você pode querer fazer é criar um perfil de sua pilha de execução do SQL Server e descobrir se todas as consultas são realmente as corretas, por exemplo, se você estiver usando apenas uma consulta que retorna resultados corretos e incorretos, então claramente a consulta está sendo usado está em questão, mas e se o seu aplicativo estiver enviando consultas diferentes em pontos diferentes do código?
Qualquer tentativa de corrigir sua consulta seria fútil ... as consultas fraudulentas ainda podem ser as que geram os resultados errados.
fonte
Re: tpdi
Observe que isso só verifica se os valores am para meses consecutivos serão consecutivos, não se existem dados consecutivos (que é provavelmente o que você pretendia inicialmente). Isso sempre passará se nenhum de seus dados de origem for consecutivo (por exemplo, você só tem meses pares), mesmo se seu cálculo am estiver totalmente errado.
Também estou faltando alguma coisa, ou a segunda metade dessa cláusula ON aumenta o valor do mês errado? (ou seja, verifica se 12/2011 vem após 1/2010)
O que é pior, se bem me lembro, o SQL Server permite pelo menos menos de 10 níveis de visualizações antes que o otimizador jogue suas mãos virtuais no ar e comece a fazer varreduras completas da tabela em cada solicitação, portanto, não exagere nessa abordagem.
Lembre-se de testar seus casos de teste!
Caso contrário, criar um conjunto muito amplo de dados para abranger a maioria ou todas as formas possíveis de entradas, usando SqlUnit ou DbUnit ou qualquer outra * Unidade para automatizar a verificação de resultados esperados em relação a esses dados, e revisar, manter e atualizar conforme necessário geralmente parece ser o caminho para seguir.
fonte