Dot.Blog

C#, XAML, Xamarin, UWP/Android/iOS

Un Parser SQL Gratuit, et un beautifier en prime

[new:30/06/2011]On parle tellement de technologies avancées comme Entity Framework qu’on en oublie parfois qu’au bout de la chaine ce bon vieux SQL existe toujours et que plus souvent qu’on le croit il faut en écrire, voire en mettre en forme, et plus difficile encore, en parser. Mais parser SQL est une tâche très difficile. Sauf si on ruse un peu...Plus...

Comment passer outre la limitation du DISTINCT sur un SELECT contenant un champ text sous SQL Server

Voici un billet moins "hi-tech" que d'habitude. Point de LINQ dans tout çà, juste un bon server SQL SERVER, une table contenant un champ Text ou NText et une bête requête qui peut retourner plusieurs fois le même enregistrement. Et comme on ne désire pas voir les copies éventuelles, bien entendu on place instinctivement une clause DISTINCT dans le SELECT.

C'est beau, simple comme SQL... Sauf que... SQL Server n'aime pas du tout la clause DISTINCT s'il y a un champ texte dans le SELECT. Et pour cause, il ne sait pas comment comparer les contenus, du coup point de DISTINCT possible.

Quelques bonnes âmes vous conseilleront peut-être :

a) de changer tous vos champs texte en varchar
b) de vous passer du champ texte dans le SELECT et de l'obtenir à part dans une autre requête

Les conseilleurs ne sont pas les codeurs ! Les varchar ont une limite de 8000 caractères et il n'est pas toujours possible de les substituer à Text/NText. De plus modifier tous les champs de ce type dans une application peut être un énorme travail (code, procédures stockées, vues, tout cela à mettre à jour). Solution bidon donc.

Quant à faire le SELECT DISTINCT sans les champs texte puis à faire une seconde requêtre derrière pour les obtenir, c'est franchement lourd et pas forcément sans conséquence sur le code appelant (qui doit faire autant de sous requêtes que de records pour obtenir les champs texte, et les stocker, etc).

Non, il existe plus simple, et un peu plus vicieux : faire une jointure de la table sur elle même.

Oui, tout simplement. L'astuce consiste à faire un select dans la table de tous les champs (y compris les champs texte) mais sans la clause DISTINCT, table qu'on lie à elle même mais ce coup ci en faisant un SELECT DISTINCT qui lui omet les champs texte... La feinte est bonne, mais elle ne saurait faire de miracle, en effet, les champs texte ne seront pas utilisés pour faire la DISCTINCTion entre les records. Cette solution n'a donc qu'un seul hic : elle ne peut pas fonctionner si vous voulez vraiment que le DISTINCT prenne en compte les champs texte. Là je n'ai pas vraiment d'astuce à vous proposer. Mais pour les autres, voici un bout de code SQL fictif qui vous montrera la syntaxe à utiliser :

SELECT t1.c1, t1.c2, t1.LeChampTexte
FROM MaTable t1 JOIN
     (SELECT DISTINCT c1,c2 FROM MaTable WHERE Desc LIKE 'Test%') AS t2
     ON t1.c1 = t2.c1

on suppose ici que le champ "c1" représente la clé (il peut s'agir de plusieurs champs, of course, à vous d'adapter le code), que le champ "c2" est un autre champ sur lequel le DISTINCT portera et que "LeChampTexte" ... est le champ texte qui pose problème. On voit mieux ici que le DISTINCT ne sera effectué que sur "c1" et "c2". Mais cela permet bien de faire un DISTINCT tout en retournant les champs texte, le tout en une seule requête...

Bon SQL et... Stay Tuned !

SQL Server 2008 et le type FileStream - résumé de la conférence DAT304 des TechEd 2007

Gérer des données "raw" tels que des fichiers multimédia, de la documation, etc, dans une base de données est un sujet qui divise les développeurs depuis longtemps. SQL Server 2008 va (enfin) mettre fin à cette dispute de principe !

DAT304 - Managing Unstructured Data in SQL Server 2008: Introducing the Filestream Datatype

Je n'ai suivi que partiellement cette conférence, il faudra d'ailleurs que je profite de la diffusion en ligne des vidéos pour les participants aux TechEd pour la regarder en totalité. Ce qui m'intéressait c'était l'info elle-même qui se résume à un nouveau type champ dans SQL Server. Mais c'est une avancée de taille, je vais vous expliquer pourquoi en quelques lignes...

Le duel blob vs file system pour les données raw

En effet, il y a d'une côté les tenants du "tout file system" c'est à dire le stockage des fichiers en dehors de la base de données avec juste le stockage des noms de fichiers dans la base elle-même. Pour: la simplicité, la gestion des flux du file sytem généralement plus performante que les blobs. Contre: le manque cruel de consistence, pas de contexte transactionnel, backups à faire séparément, etc, etc. Je fais partie des "anti" d'ailleurs.

De l'autre côté il y a ceux qui préfèrent le stockage en blob. Pour : consistence des données, contexte transactionnel, backup unique, etc. Je pour pour cette solution en général. Contre : les blobs sont moins rapide en lecture / écriture de flux que le file system, certains SGBD imposent des limites à la taille des blobs. Si on fait abstraction de ce dernier argument (il suffit d'utiliser une base n'ayant pas cette limite, par exemple SQL Server 2005 ou même Firebird/Interbase), le léger inconvénient de la rapidité (qui reste modeste et peu gênant dans la plupart des cas) est largement, à mon avis et par expérience, compensé par les avantages de cette technique. Reste qu'on peut faire mieux...

Mélanger le meilleur des deux solutions 

C'est justement ce que propose SQL Server 2008 avec le nouveau type FileStream qui est une extension de VARBINARY(MAX) qui s'en distingue par un attribut lors de la création du champ.

Le principe est simple : on marie le meilleur des deux solutions existantes. On prend la souplesse (gestion des quotas par ex) et la rapidité du file system (NTFS obligatoirement) et on l'associe à la cohérence des données de la solution blob. En gros, SQL Server 2008 stocke les fichiers dans le file system mais assure l'accès à ces fichiers comme à n'importe quel autre champ ce qui permet la gestion transactionnelle, le backup unique et centralisé.

Conclusion 

Une solution simple et performante à un problème de plus en plus crucial, les utilisateurs devant de plus en plus gérer des données lourdes (photos, documents digitalisés, vidéos...) en synchronisme parfait avec les bases de données. Une fichier client peut comporter une photo, une fiche article une vidéo de présentation, tout cela n'est plus "exotique", cela devient une contrainte légitime d'exploitation.

Pour l'instant SQL Server 2008 est en bêta, mais comme son nom l'indique il devrait être bientôt sur le marché...

Encore une bonne idée, ingénieuse et simple à mettre en oeuvre. Je trouve que les équipes de dev de MS ont vraiment l'âme créative depuis qu'on est entré dans ce que j'appelle "l'ére .NET". Souhaitons que ça dure le plus longtemps possible !

A+ pour un nouveau billet. Stay tuned !