Vous ne voudriez pas écrire une application avec des fonctions de 200 lignes de long. Vous auriez décomposer ces fonctions en plus petites fonctions, chacune avec un seul clairement définis responsabilité.
Pourquoi écrire de SQL comme ça?
Décomposer vos requêtes, tout comme vous le décomposer vos fonctions. Cela les rend plus court, plus simple, plus facile à comprendre, plus facile à tester, plus facile à refactoriser. Et il vous permet d'ajouter des "cales" entre eux, et des "wrappers" autour d'eux, comme vous le faites dans le code de procédure.
Comment faites-vous cela? En faisant de chaque chose importante, une requête n'est en vue. Ensuite à vous de composer des requêtes plus complexes de ces plus simples points de vue, tout comme vous composer des fonctions plus complexes des fonctions primitives.
Et la grande chose est, pour la plupart des compositions de vues, vous aurez exactement les mêmes performances de votre SGBDR. (Pour certains d'entre vous ne le ferez pas; et alors? L'optimisation prématurée est la racine de tous les maux. Code correctement d'abord, puis optimiser si vous en avez besoin.)
Voici un exemple d'utilisation de plusieurs vue de décomposer un complexe de requête.
Dans l'exemple, parce que chaque point de vue ajoute seulement une transformation, chacun peut être testé de façon indépendante à trouver des erreurs, et les tests sont simples.
Voici la table de base de l'exemple:
create table month_value(
eid int not null, m int, y int, v int );
Ce tableau est imparfait, car il utilise deux colonnes, le mois et l'année, pour représenter une donnée, une absolue mois. Voici notre cahier des charges pour la nouvelle colonne calculée:
Nous allons le faire comme une transformation linéaire, tel qu'il trie la même chose que (y, m), et telle que pour tout (y,m) n-uplet il y a une et une seule valeur, et toutes les valeurs sont consécutifs:
create view cm_abs_month as
select *, y * 12 + m as am from month_value;
Maintenant, ce que nous avons à tester est inhérente à notre spec, à savoir que pour tout n-uplet (y, m), il existe un et un seul (am), et que (am)s sont consécutifs. Nous allons écrire quelques tests.
Notre test sera un SQL select
de la requête, avec la structure suivante: un nom de test et les cas de déclaration concated ensemble. Le nom de test est juste une chaîne de caractères arbitraire. L'instruction case est juste case when
test consolidés then 'passed' else 'false' end
.
Le test des déclarations sera juste SQL sélectionne (sous-requêtes) qui doit être vrai pour le test à passer.
Voici notre premier test:
--a select statement that catenates the test name and the case statement
select concat(
-- the test name
'For every (y,m) there is one and only one (am): ',
-- 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 y, m) from month_value)
--expected value,
= ( select count(distinct am) from cm_abs_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.
L'exécution de cette requête donne ce résultat: For every (y,m) there is one and only one (am): passed
Tant qu'il y a suffisamment de données de test dans month_value, ce test fonctionne.
Nous pouvons ajouter un test de suffisamment de données de test, trop:
select concat( 'Sufficient and sufficiently varied month_value test data: ',
case when
( select count(distinct y, m) from month_value) > 10
and ( select count(distinct y) from month_value) > 3
and ... more tests
then 'passed' else 'failed' end );
Maintenant, nous allons tester consécutives:
select concat( '(am)s are consecutive: ',
case when ( select count(*) from cm_abs_month a join cm_abs_month b
on (( a.m + 1 = b.m and a.y = b.y) or (a.m = 12 and b.m = 1 and a.y + 1 = b.y) )
where a.am + 1 <> b.am ) = 0
then 'passed' else 'failed' end );
Maintenant, nous allons mettre nos tests, qui sont simplement des requêtes, dans un fichier, et lancez le script sur la base de données. En effet, si nous conservons notre vue de définitions dans un script (ou des scripts, je vous recommande un fichier par vues associées) à exécuter sur la base de données, nous pouvons ajouter nos tests pour chaque vue de la même script, de sorte que la loi de (re-) création de notre point de vue dirige également le point de vue de tests. De cette façon, nous avons tous deux obtenir des tests de régression lorsque nous re-créer des vues, et, lors de la création de la vue va à l'encontre de la production, de la vue seront également testés en production.