Une alternative open source à SQL, née

L'une des intentions initiales de l'invention de SQL est évidemment de réduire la difficulté des personnes à mettre en œuvre des calculs de requêtes de données. Beaucoup de vocabulaire et de grammaire de type anglais sont utilisés dans SQL, ce que l'on espère que le personnel non technique pourra également maîtriser. En effet, le SQL simple peut être lu comme de l'anglais, même par des personnes n'ayant aucune expérience en programmation.

Cependant, face à des exigences de calcul de requête légèrement complexes, SQL apparaîtra impuissant, écrivant souvent des centaines de lignes d'instructions imbriquées à plusieurs niveaux. Ce type de SQL, sans compter qu'il est difficile à réaliser pour le personnel non technique, n'est pas facile même pour les programmeurs professionnels, et il devient souvent le point culminant des examens d'application de nombreux éditeurs de logiciels. Le SQL à trois et cinq lignes n'existe que dans les manuels et les cours de formation. En réalité, le SQL utilisé pour la requête de rapport est généralement mesuré en "K".

Analyse et discussion des difficultés SQL

Pourquoi est-ce? Nous utilisons un exemple très simple pour examiner les lacunes de SQL en termes de calculs.

Considérez un tableau de performances des ventes avec trois champs (informations de date omises pour plus de simplicité) :

montant des ventes Tableau des performances des ventes
ventes Nom du vendeur, en supposant qu'il n'y a pas de nom en double
produit Produits en vente
montant Ventes par ce vendeur sur ce produit

Maintenant, nous voulons connaître la liste des 10 meilleurs vendeurs qui sont à la fois des climatiseurs et des téléviseurs.

Ce problème n'est pas difficile, les gens concevront naturellement le processus de calcul suivant :

1. Triez par ventes de climatiseurs pour trouver le top 10 ;

2. Triez par ventes de téléviseurs pour trouver le top 10 ;

3. Prenez l'intersection des résultats de 1 et 2 pour obtenir la réponse ;

Faisons-le maintenant avec SQL.

Les premiers SQL ne prennent pas en charge les étapes, il est donc un peu fastidieux d'écrire les deux premières étapes dans des sous-requêtes :

select * from     ( select top 10 sales from sales_amount where product='AC' order by amount desc )intersect     ( select top 10 sales from sales_amount where product='TV' order by amount desc )

Plus tard, SQL a également découvert qu'il serait gênant de ne pas suivre étape par étape. Il a donc fourni la syntaxe CTE, qui peut utiliser le mot-clé with pour nommer les résultats de la requête dans les étapes précédentes et les utiliser dans les étapes suivantes :

with A as       select top 10 sales from sales_amount where product='AC' order by amount desc     B as       select top 10 sales from sales_amount where product='TV' order by amount descselect * from A intersect B

Les phrases ne sont pas plus courtes, mais les idées deviennent plus claires après étape par étape.

Maintenant, compliquons un peu le problème et modifions-le pour calculer les vendeurs dont les ventes de tous les produits sont dans le top 10. Imaginez simplement comment le calculer. Il est facile d'y penser en prolongeant les idées mentionnées ci-dessus. :

1. Énumérez tous les produits ;

2. Sortez le top 10 de chaque produit et enregistrez-les séparément ;

3. Prenez l'intersection de tous les 10 premiers;

Cependant, l'utilisation de la syntaxe CTE ne permet d'effectuer des calculs supplémentaires que pour un certain nombre de résultats intermédiaires. Et nous ne savons pas à l'avance qu'il y a plusieurs produits au total, ce qui rendra le nombre de clauses dans WITH incertain, nous ne pouvons donc pas l'écrire.

Une autre façon de penser :

1. Regroupez les données par produit, triez chaque groupe et sortez le top 10 ;

2. Prenez l'intersection de tous les 10 premiers;

Mais cela doit enregistrer le résultat du regroupement de la première étape, et ce résultat intermédiaire est une table, qui a un champ pour stocker les 10 premiers membres du regroupement correspondant, c'est-à-dire que la valeur du champ sera un ensemble, qui n'est pas pris en charge par SQL Ce type de données ne peut toujours pas être écrit.

Si vous disposez du support des fonctions de fenêtre, vous pouvez à nouveau changer d'avis. Après le regroupement par produit, calculez le nombre de fois où chaque vendeur apparaît dans le top 10 de tous les groupes. S'il est égal au nombre total de produits, il signifie que le vendeur est dans les ventes de tous les produits. sont dans le top 10.

select salesfrom ( select sales,     from ( select sales,                   rank() over (partition by product order by amount desc ) ranking            from sales_amount)     where ranking <=10 )group by saleshaving count(*)=(select count(distinct product) from sales_amount)

Cela peut être écrit, mais combien de personnes peuvent écrire un SQL aussi complexe ?

Les deux premières idées simples ne peuvent pas être réalisées avec SQL, seule la troisième façon de penser détournée peut être utilisée. La raison ici réside dans une lacune importante de SQL : collection incomplète .
Bien que SQL ait le concept d'ensembles, il ne fournit pas d'ensembles comme type de données de base. La valeur d'une variable ou d'un champ ne peut pas être un ensemble, et il n'y a pas d'autres types de données d'ensemble à l'exception des tables, ce qui entraîne un grand nombre d'opérations d'ensemble. dans l'esprit Des détours sont nécessaires lors de l'écriture et de l'écriture.

Nous avons utilisé le mot-clé top dans le calcul ci-dessus. En fait, il n'y a rien de tel dans la théorie de l'algèbre relationnelle (il peut être combiné par d'autres calculs). Ce n'est pas une manière standard d'écrire du SQL.

Voyons à quel point il est difficile de trouver le top 10 sans top ?

L'idée générale est la suivante : trouvez le nombre de membres qui sont plus grands que vous comme classement, puis retirez les membres dont le classement ne dépasse pas 10, et écrivez le SQL comme suit :

select salesfrom ( select A.sales sales, A.product product,             (select count(*)+1 from sales_amount              where A.product=product AND A.amount<=amount) ranking       from sales_amount A )where product='AC' AND ranking<=10

ou

select salesfrom ( select A.sales sales, A.product product, count(*)+1 ranking       from sales_amount A, sales_amount B       where A.sales=B.sales and A.product=B.product AND A.amount<=B.amount       group by A.sales,A.product )where product='AC' AND ranking<=10

Il n'est peut-être pas facile pour les programmeurs professionnels d'écrire de telles instructions SQL ! Au lieu de cela, seul un top 10 est calculé.

Prendre du recul, même s'il y a un sommet, cela ne fait que faciliter la sortie de la partie précédente. Si on change le problème pour passer de la 6ème à la 10ème place, ou trouver le vendeur qui a 10% de ventes en plus que le suivant, ces difficultés existent toujours, et il faut encore un détour pour le faire avec SQL.

La raison de ce phénomène est une autre lacune importante de SQL : le manque de support ordonné . SQL hérite de l'ensemble non ordonné en mathématiques, ce qui rend directement les calculs liés à l'ordre assez difficiles, et il est concevable à quel point les calculs liés à l'ordre seront courants (par exemple par rapport au mois dernier, par rapport à la même période l'année dernière, top 20 %, classement, etc).

La fonction de fenêtre ajoutée dans la norme SQL2003 fournit certaines capacités de calcul liées à la commande, ce qui rend certains des problèmes ci-dessus plus simples et atténue ce problème de SQL dans une certaine mesure. Cependant, l'utilisation des fonctions de fenêtre s'accompagne souvent de sous-requêtes, qui ne permettent pas aux utilisateurs d'utiliser directement l'accès séquentiel aux membres de la collection, et il existe encore de nombreuses opérations ordonnées difficiles à résoudre.

Nous voulons maintenant nous concentrer sur le ratio hommes-femmes des "bons" vendeurs calculé ci-dessus, c'est-à-dire combien d'hommes et de femmes il y a. Dans des circonstances normales, les informations sur le sexe du vendeur seront enregistrées sur la liste au lieu du tableau des performances, simplifié comme suit :

employé formulaire employé
nom Nom de l'employé, en supposant qu'il n'y a pas de noms en double
genre sexe de l'employé

Nous avons déjà calculé la liste des "bons" vendeurs, et l'idée la plus naturelle est d'utiliser la liste pour connaître leur sexe au moment d'aller au roster, et de les recompter. Mais obtenir des informations sur les tables en SQL nécessite une jointure entre les tables, donc, suivant le résultat d'origine, le SQL serait écrit comme suit :

select employee.gender,count(*)from employee,    ( ( select top 10 sales from sales_amount where product='AC' order by amount desc )    intersect    ( select top 10 sales from sales_amount where product='TV' order by amount desc ) ) Awhere A.sales=employee.namegroup by employee.gender

Une seule table d'association de plus conduira à une telle lourdeur, mais en réalité, il y a beaucoup d'informations stockées dans les tables, et il y a souvent plusieurs couches. Par exemple, le vendeur a un département, et le département a un responsable. Maintenant, nous voulons savoir quels responsables sont responsables du "bon" vendeur, nous devons donc connecter trois tables. Il n'est pas facile d'écrire clairement où et groupe dans ce calcul. C'est du travail.

C'est la prochaine difficulté importante de SQL dont nous voulons parler : le manque de mécanisme de référence d'objet , la relation entre les objets dans l'algèbre relationnelle est complètement maintenue par la même valeur de clé étrangère, ce qui est non seulement inefficace lors de sa recherche, mais ne peut pas non plus être utilisé par des clés étrangères Le membre d'enregistrement pointé est directement traité comme un attribut de cet enregistrement. Imaginez si la phrase ci-dessus peut être écrite comme ceci :

select sales.gender,count(*)from (…) // …是前面计算“好”销售员的SQLgroup by sales.gender

De toute évidence, cette phrase est non seulement plus claire, mais aussi plus efficace en termes de calcul (pas de calculs de jointure).

Nous avons analysé plusieurs difficultés importantes de SQL à travers un exemple simple, qui est aussi la principale raison pour laquelle SQL est difficile ou long à écrire. Le processus de résolution de problèmes commerciaux basé sur un système informatique est le processus de traduction de la solution du problème commercial en une grammaire informatique formelle (similaire aux élèves du primaire résolvant des problèmes et traduisant les problèmes en quatre opérations arithmétiques formalisées). Les difficultés mentionnées ci-dessus en SQL entraîneront de grands obstacles à la traduction des solutions aux problèmes. Dans des cas extrêmes, un phénomène aussi étrange se produira : la difficulté de formaliser la solution du problème dans une grammaire informatique est bien plus grande que la difficulté de résoudre le problème. lui-même .

Un autre exemple facile à comprendre pour les programmeurs est que l'utilisation de SQL pour effectuer des calculs de données est similaire à l'utilisation du langage d'assemblage pour effectuer les quatre opérations arithmétiques. Il est facile pour nous d'écrire une formule comme 3+5*7, mais si nous utilisons le langage d'assemblage (prenons X86 comme exemple), nous devons l'écrire comme

mov ax,3mov bx,5mul bx,7add ax,bx

Ce type de code est bien pire que 3+5*7 à la fois en écriture et en lecture (ce sera encore plus terrible si vous rencontrez des décimales). Bien que ce ne soit pas trop compliqué pour les programmeurs expérimentés, cette façon d'écrire est encore trop obscure pour la plupart des gens.En ce sens, FORTRAN est en effet une grande invention.

Pour la commodité de la compréhension, l'exemple que nous donnons est encore une tâche très simple. Les tâches en réalité sont beaucoup plus compliquées que ces exemples, et de nombreuses difficultés, grandes et petites, seront rencontrées dans le processus. Écrivez quelques lignes de plus pour cette question, et quelques lignes de plus pour cette question. Il n'est pas surprenant qu'une tâche un peu plus compliquée écrive des centaines de lignes de SQL imbriqué à plusieurs niveaux. De plus, ces centaines de lignes sont souvent une instruction.Pour des raisons d'ingénierie, SQL est difficile à déboguer, ce qui aggrave encore la difficulté de l'analyse de requêtes complexes.

plus d'exemples

Donnons quelques exemples supplémentaires pour illustrer ces aspects.

Afin de rendre le SQL de l'exemple aussi simple que possible, un grand nombre de fonctions de fenêtre sont utilisées ici, c'est pourquoi la syntaxe de la base de données ORACLE qui prend en charge les fonctions de fenêtre est adoptée. Il est généralement plus compliqué d'écrire ces SQL en utilisant la syntaxe d'autres bases de données.
Ces problèmes eux-mêmes ne doivent pas être considérés comme très compliqués, et ils apparaissent souvent dans l'analyse quotidienne des données, mais c'est déjà difficile pour SQL.

trouble de la collection

Les calculs ordonnés sont très courants dans les calculs de données par lots (prenez la 3/3e place, comparez au numéro précédent, etc.), mais SQL continue d'utiliser le concept d'ensembles non ordonnés en mathématiques, les calculs ordonnés ne peuvent pas être effectués directement et peuvent ne peut être ajusté qu'en changeant la méthode des idées.

 Tâche 1    Employés d'âge moyen dans l'entreprise

 
 
select name, birthdayfrom (select name, birthday, row_number() over (order by birthday) ranking      from employee )where ranking=(select floor((count(*)+1)/2) from employee)

La médiane est un calcul courant. A l'origine, il est très simple de retirer le membre du milieu dans l'ensemble trié. Cependant, le mécanisme de collecte non ordonné de SQL ne fournit pas de mécanisme pour accéder directement aux membres par emplacement. Il est nécessaire de créer artificiellement un champ de numéro de séquence, puis d'utiliser la méthode de requête conditionnelle pour le sélectionner, ce qui entraîne l'utilisation de sous-requêtes à compléter.

 Tâche 2    Combien de jours de bourse est la plus longue hausse continue d'un certain stock

select max (consecutive_day)from (select count(*) (consecutive_day      from (select sum(rise_mark) over(order by trade_date) days_no_gain            from (select trade_date,                         case when                              closing_price>lag(closing_price) over(order by trade_date)                         then 0 else 1 END rise_mark                from stock_price) )     group by days_no_gain)

Les collections non ordonnées peuvent également conduire à une distorsion des idées.

La manière classique de calculer le nombre de jours croissants consécutifs : définissez une variable temporaire avec une valeur initiale de 0 pour enregistrer la date de montée consécutive, puis comparez-la avec le jour précédent. Si elle n'a pas augmenté, elle sera remise à 0. , et s'il a augmenté, ajouter 1. A la fin du cycle, voir la valeur apparaît la valeur maximale.

Ce processus ne peut pas être décrit en utilisant SQL. Il est nécessaire de changer de mentalité et de calculer le nombre cumulé de jours non croissants depuis la date initiale jusqu'au jour actuel. Trouver son nombre maximum. Il n'est pas facile de lire cette phrase de SQL, mais il est encore plus difficile de l'écrire.

La collecte n'est pas complète

Il ne fait aucun doute que les collections sont à la base du calcul de données par lots. Bien que SQL ait le concept d'ensembles, il se limite à décrire des ensembles de résultats simples et n'utilise pas d'ensembles comme type de données de base pour étendre sa gamme d'applications.

 Tâche 3    Employés ayant le même anniversaire que d'autres dans l'entreprise

select * from employeewhere to_char (birthday, ‘MMDD’) in    ( select to_char(birthday, 'MMDD') from employee      group by to_char(birthday, 'MMDD')      having count(*)>1 )

L'intention initiale du regroupement est de diviser la collection source en plusieurs sous-collections, et la valeur de retour doit également être ces sous-ensembles. Mais SQL ne peut pas représenter cet "ensemble d'ensembles", forçant ainsi l'étape suivante des calculs agrégés pour ces sous-ensembles à former des ensembles de résultats réguliers.

Mais parfois, ce que nous voulons, ce n'est pas la valeur récapitulative du sous-ensemble, mais le sous-ensemble lui-même. A ce moment, il faut interroger à nouveau en utilisant les conditions obtenues par regroupement à partir de la collection source, et des sous-requêtes apparaissent inévitablement.

 Tâche 4    Trouvez les 10 meilleurs élèves dans chaque matière

select namefrom (select name      from (select name,                   rank() over(partition by subject order by score DESC) ranking            from score_table)      where ranking<=10)group by namehaving count(*)=(select count(distinct subject) from score_table)

Avec l'idée de collecte, triez et filtrez les sous-ensembles après le regroupement des sujets pour sélectionner le top 10 de chaque sujet, puis faites l'intersection de ces sous-ensembles pour terminer la tâche. Cependant, SQL ne peut pas exprimer "l'ensemble des ensembles", et il n'y a pas d'opération d'intersection pour les ensembles avec un nombre indéfini d'ensembles. A ce moment, il est nécessaire de changer de façon de penser, utilisez les fonctions de fenêtre pour trouver le top 10 des chaque matière, puis regroupez les élèves pour trouver les élèves dont les temps d'occurrence sont égaux au nombre de matières , ce qui entraîne des difficultés de compréhension.

manque de référence d'objet

En SQL, la relation de référence entre les tables de données est maintenue par la clé étrangère de même valeur, et l'enregistrement pointé par la clé étrangère ne peut pas être directement utilisé comme attribut de cet enregistrement. Lors d'une requête, il est nécessaire d'utiliser plusieurs des jointures de table ou des sous-requêtes à compléter, non seulement des écritures fastidieuses et inefficaces.

 Tâche 5    Les employés masculins de la responsable féminine

joindre plusieurs tables

select A.*from employee A, department B, employee Cwhere A.department=B.department and B.manager=C.name and      A.gender='male' and C.gender='female'

avec sous-requête

select * from employeewhere gender='male' and department in    (select department from department     where manager in          (select name from employee where gender='female'))

Si le champ département de la table des employés pointe vers l'enregistrement de la table des départements et que le champ responsable de la table des départements pointe vers l'enregistrement de la table des employés, la condition de requête peut simplement être écrite sous cette forme intuitive et efficace :

where gender='male' and department.manager.gender='female'

Mais en SQL, vous ne pouvez utiliser que des jointures ou des sous-requêtes multi-tables pour écrire les deux instructions évidemment obscures ci-dessus.

   Entreprise du premier emploi de l'employé de la tâche 6 

joindre plusieurs tables

select name, company, first_companyfrom (select employee.name name, resume.company company,             row_number() over(partition by resume. name                               order by resume.start_date) work_seq      from employee, resume where employee.name = resume.name)where work_seq=1

avec sous-requête

select name,    (select company from resume     where name=A.name and           start date=(select min(start_date) from resume                       where name=A.name)) first_companyfrom employee A

Il n'y a pas de mécanisme de référence d'objet et de SQL entièrement agrégé, et les sous-tables ne peuvent pas non plus être traitées comme des attributs (valeurs de champ) de la table principale. Les requêtes pour les sous-tables utilisent soit des jointures multi-tables pour augmenter la complexité de l'instruction, et filtrer ou regrouper le jeu de résultats dans une correspondance un à un avec les enregistrements de la table principale (les enregistrements connectés correspondent aux sous-tables un à -one); Soit utiliser une sous-requête pour calculer temporairement un sous-ensemble d'enregistrements de sous-table liés aux enregistrements de la table principale à chaque fois, en augmentant la quantité de calcul globale (la clause with ne peut pas être utilisée pour les sous-requêtes) et la complexité d'écriture.

Présentation de SPL

Maintenant que le problème est résolu, il est temps de parler de la solution.

En fait, lors de l'analyse du problème, la solution est spécifiée dans une certaine mesure, et le langage de calcul est repensé pour surmonter ces difficultés de SQL, et le problème est résolu.

C'est pourquoi SPL a été inventé !

SPL est un langage de programmation open source dont le nom complet est Structured Process Language, qui n'est qu'à un mot de SQL. Le but est de mieux résoudre le fonctionnement des données structurées. SPL met l'accent sur l'ordre, prend en charge le mécanisme de référence d'objet et réalise ainsi une collecte approfondie, ce qui réduira considérablement la difficulté de la "traduction de la solution" mentionnée ci-dessus.

L'espace ici n'est pas approprié pour présenter SPL en détail. Nous listons seulement le code SPL de l'exemple dans la section précédente pour le ressentir :

 tache 1   

UN
1 =employé.sort(anniversaire)
2 =A1((A1.len()+1)/2)

Pour les SPL basés sur des ensembles triés, la récupération des valeurs par position est une tâche simple.

 tâche 2   

UN
1 =stock_price.sort(trade_date)
2 =0
3 =A1.max(A2=if(prix_fermé>prix_fermé[-1],A2+1,0))

SPL écrit simplement des codes de calcul selon le processus de pensée naturel.

 tâche 3   

UN
1 =employé.groupe(mois(anniversaire),jour(anniversaire))
2 =A1.select(~.len()>1).conj()

SPL peut enregistrer des ensembles de résultats groupés et poursuivre le traitement comme des collections régulières.

 tâche 4   

UN
1 =score_table.group(sujet)
2 =A1.(~.rang(score).pselect@a(~<=10))
3 =A1.(~(A2(#)).(nom)).isect()

Pour utiliser SPL, il vous suffit d'écrire le code de calcul selon le processus de réflexion.

 tâche 5   

UN
1 =employee.select(gender=="homme" && department.manager.gender=="femme")

Une SPL qui prend en charge les références d'objet peut simplement accéder au champ de l'enregistrement vers lequel la clé étrangère pointe comme sa propre propriété.

 tâche 6   

UN
1 =employee.new(name,resume.minp(start_date).company:first_company)

SPL prend en charge les collections de sous-tables en tant que champs de table principaux, tout comme l'accès à d'autres champs, les sous-tables n'ont pas besoin d'être recalculées.

SPL dispose d'un IDE intuitif, qui fournit des fonctions de débogage pratiques et peut parcourir le code pour réduire davantage la complexité de l'écriture de code.

Pour les calculs intégrés à l'application, SPL fournit un pilote JDBC standard qui peut être intégré dans des applications Java telles que SQL :

Class.forName("com.esproc.jdbc.InternalDriver");Connection conn =DriverManager.getConnection("jdbc:esproc:local://");Statement st = connection.();CallableStatement st = conn.prepareCall("{call xxxx(?,?)}");st.setObject(1, 3000);st.setObject(2, 5000);ResultSet result=st.execute();...

 

Guess you like

Origin blog.csdn.net/2301_77463738/article/details/131142479