Notre expert en bases de données sur les résidents nous dit que les tableaux de chiffres sont inestimables . Je ne comprends pas trop pourquoi. Voici un tableau de chiffres:
USE Model
GO
CREATE TABLE Numbers
(
Number INT NOT NULL,
CONSTRAINT PK_Numbers
PRIMARY KEY CLUSTERED (Number)
WITH FILLFACTOR = 100
)
INSERT INTO Numbers
SELECT
(a.Number * 256) + b.Number AS Number
FROM
(
SELECT number
FROM master..spt_values
WHERE
type = 'P'
AND number <= 255
) a (Number),
(
SELECT number
FROM master..spt_values
WHERE
type = 'P'
AND number <= 255
) b (Number)
GO
Selon le blog, la justification est la suivante:
Les tableaux de chiffres sont vraiment précieux. Je les utilise tout le temps pour manipuler des chaînes, simuler des fonctions de fenêtre, remplir des tables de test avec beaucoup de données, éliminer la logique du curseur et de nombreuses autres tâches qui seraient incroyablement difficiles sans elles.
Mais je ne comprends pas exactement ce que sont ces utilisations - pouvez-vous fournir des exemples convaincants et précis de "tableaux de chiffres" vous épargnant une tonne de travail dans SQL Server - et pourquoi nous devrions les avoir?
la source
Réponses:
J'ai vu de nombreuses utilisations lorsque vous devez projeter des «données manquantes». Par exemple. vous avez une série chronologique (un journal d'accès par exemple) et vous souhaitez afficher le nombre de visites par jour au cours des 30 derniers jours (pensez au tableau de bord d'analyse). Si vous faites un,
select count(...) from ... group by day
vous obtiendrez le nombre pour chaque jour, mais le résultat n'aura qu'une ligne pour chaque jour où vous avez eu au moins un accès. Par contre, si vous projetez d’abord une table de jours à partir de votre table de chiffres (select dateadd(day, -number, today) as day from numbers
) et que vous quittez ensuite la liste des comptes eu aucun accès. Ceci n'est qu'un exemple. Bien sûr, on peut faire valoir que la couche de présentation de votre tableau de bord pourrait gérer les jours manquants et simplement afficher un 0, mais certains outils (par exemple, SSRS) ne pourront tout simplement pas gérer cela.D'autres exemples que j'ai vus utilisaient des astuces similaires sur les séries chronologiques (date / heure + / - nombre) pour effectuer toutes sortes de calculs de fenêtre. En général, lorsque vous utilisez une boucle for avec un nombre bien connu d'itérations dans un langage impératif, la nature déclarative et définie de SQL peut utiliser une astuce basée sur une table de nombres.
BTW, je ressens le besoin de rappeler le fait que, même si utiliser un tableau de nombres, cela ressemble à une exécution procédurale impérative, ne tombez pas dans l'erreur de supposer qu'il est impératif. Laissez-moi vous donner un exemple:
Ce programme produira 999999, ce qui est pratiquement garanti.
Essayons la même chose dans SQL Server, en utilisant une table numérique. Commencez par créer une table de 1 000 000 nombres:
Maintenant, faisons la boucle "for":
Le résultat est:
Si vous avez maintenant un moment WTF (après tout,
number
c'est la clé primaire en cluster!), L'astuce s'appelle le balayage d'ordre d'attribution et je ne l'ai pas insérée@j*1000+@i
par accident ... Vous pourriez aussi deviner et dire que le résultat est parce que parallélisme et que parfois peut être la bonne réponse.Il y a beaucoup de trolls sous ce pont et j'en ai mentionné quelques-uns dans On SQL Server, un court-circuit d'opérateur booléen et des fonctions T-SQL n'impliquant pas un certain ordre d'exécution
la source
J'ai trouvé un tableau de chiffres assez utile dans diverses situations.
A Pourquoi devrais - je envisager d' utiliser une table de numéros auxiliaires? , écrit en 2004, je montre quelques exemples:
Dans Bad habitudes to kick: en utilisant des boucles pour remplir de grandes tables , je montre comment utiliser une table de nombres pour insérer rapidement un grand nombre de lignes (par opposition à l’approche réflexe qui consiste à utiliser une boucle while).
Dans Traitement d’une liste d’entiers: mon approche et Autres explications sur le fractionnement des listes: délimiteurs personnalisés, prévention des doublons et maintien de l’ordre , je montre comment utiliser un tableau de nombres pour fractionner une chaîne (par exemple, un ensemble de valeurs séparées par des virgules) et fournir des performances. des comparaisons entre cette méthode et d’autres méthodes. Plus d'informations sur le fractionnement et autres manipulations de chaîne:
Et dans The SQL Server Numbers Table, Explained - Part 1 , je donne quelques informations de base sur le concept et les futures publications en magasin détaillent des applications spécifiques.
Il y a beaucoup d'autres utilisations, ce ne sont que quelques-unes qui m'ont suffisamment marqué pour écrire à leur sujet.
Et comme @gbn, j'ai quelques réponses sur le dépassement de capacité de la pile et sur ce site qui utilisent également un tableau de nombres.
Enfin, j'ai une série de billets de blog sur les groupes générateurs sans boucle, ce qui montre en partie l'avantage de l'utilisation d'un tableau de nombres par rapport à la plupart des autres méthodes (mis à part l'extrême bizarre de Remus):
la source
Voici un excellent exemple d' Adam Machanic que j'ai utilisé récemment :
J'ai utilisé quelque chose de similaire avec a
CTE
pour trouver une instance spécifique de sous-chaîne ("Trouvez le 3ème canal de cette chaîne") pour travailler avec des données délimitées corrélées:Si vous n'avez pas de tableau de nombres, l'alternative consiste à utiliser une boucle quelconque. Fondamentalement, un tableau de nombres vous permet d'effectuer une itération basée sur un ensemble, sans curseurs ni boucles.
la source
Je voudrais utiliser une table de nombres chaque fois que j'ai besoin d'un équivalent SQL d'Enumerable.Range. Par exemple, je viens de l’utiliser dans une réponse sur ce site: calcul du nombre de permutations
la source