cette table veut dire que j'ai deux ensembles:
l'ensemble 1 qui contient une salade et une pomme
l'ensemble 2 qui contient une salade, une pomme et une orange.
Je souhaiterai trouver un moyen efficace (en pur SQL) pour avoir les id des ensembles qui contiennent exactement les mêmes éléments.
Le seul truc que je vois, ce serait de créer une empreinte pour chaque panier, et regarde si une empreinte existe en plus d'un exemplaire. Par exemple, avec MySQL et GROUP_CONCAT :
--
SELECT GROUP_CONCAT(id_panier ORDER BY id_panier ASC)
FROM (SELECT id_panier, GROUP_CONCAT(nom_fruit ORDER BY nom_fruit ASC) AS nom_fruits
FROM panier
GROUP BY id_panier) tmp
GROUP BY nom_fruits
HAVING COUNT(*) > 1;
Ce qui retournerait différentes listes de paniers identiques. Mais je trouve que ça fait moche avec autant de GROUP_CONCAT, je me demande s'il n'y a pas une solution plus élégante.
CREATE TABLE ensemble ( ens INTEGER NOT NULL, elem TEXT NOT NULL, PRIMARY KEY (ens,elem) );
INSERT INTO ensemble VALUES
(1 , 'salade'),
(1 , 'pomme'),
(2 , 'salade'),
(2 , 'pomme'),
(2 , 'orange'),
(3 , 'salade'),
(3 , 'pomme'),
(4 , 'salade');
-- équivalent du GROUP_CONCAT (en mieux : pommefraise marche)
SELECT array_agg( ens ), l FROM (
SELECT ens, array_agg( elem ) AS l FROM (
SELECT * FROM ensemble ORDER BY ens, elem
) AS e GROUP BY ens)
AS f GROUP BY l;
array_agg | l
-----------+-----------------------
{2} | {orange,pomme,salade}
{1,3} | {pomme,salade}
{4} | {salade}
-- SQL pur, probablement beaucoup plus lent
WITH
tailles AS (SELECT ens, count(*) AS taille FROM ensemble GROUP BY ens),
candidats AS (SELECT a.ens aens, b.ens bens, a.taille FROM tailles a JOIN tailles b ON (a.taille=b.taille AND a.ens <= b.ens))
SELECT aens, bens, taille, count(*) AS identiques FROM candidats c JOIN ensemble a ON (a.ens=c.aens) JOIN ensemble b ON (b.ens=c.bens AND b.elem=a.elem) GROUP BY aens, bens, taille HAVING taille=count(*);
aens | bens | taille | identiques
------+------+--------+------------
1 | 1 | 2 | 2
2 | 2 | 3 | 3
1 | 3 | 2 | 2
3 | 3 | 2 | 2
4 | 4 | 1 | 1
Le dernier retourne des correspondances entre ensembles (par exemple aens=1 et bens=3 indique que les ensembles 1 et 3 sont identiques). C'est assez chiadé.
CREATE TABLE ensemble ( ens INTEGER NOT NULL, elem INTEGER NOT NULL, PRIMARY KEY (ens,elem) );
INSERT INTO ensemble (ens, elem) SELECT DISTINCT (n/10)::INTEGER, (random()*10)::INTEGER FROM generate_series( 1,10000 ) AS n;
requête array_agg() : 0.012 s
requête sql pur : 1.02 s
no comment sur les performances...
> Euh, si tu construis ta table n'importe comment, c'est normal que ça fonctionne pas.
Je voulais le faire avec array_agg au début, puis je me suis dit que de toute façon, il faudrait que je le refasse avec MySQL et GROUP_CONCAT parce que l'auteur ne comprendrait pas.
Par contre, j'ai pas compris comment ça marcherait si l'élément valait "pommefraise".
Ben GROUP_CONCAT est un canon à pied parce que ça colle des strings dans une string, tu choisis le séparateur, par exemple "***", mais si une des chaînes d'origine contient le séparateur, c'est mort.
En l'occurence si y'a "pomme", "fraise" et "pommefraise" comme éléments de l'ensemble, après GROUP_CONCAT, tu sauras jamais si "pommefraise" était "pommefraise" ou "pomme" + "fraise", à moins de mettre un séparateur comme un espace, mais si il y a des espaces dans les chaînes d'origine, etc, etc.
Tandis qu'avec un array, au moins t'es sûr que les éléments sont des éléments...
Oui, je comprends, mais si tu regardes comme ledemonboiteux conçoit sa base de données, il met dans le panier 1 l'élément "pommefraise" et dans le panier 2 les éléments "pomme" et "fraise", puis se demande pourquoi ça fonctionne pas...
Et par défaut, GROUP_CONCAT sépare les éléments par des virgules, donc dans les exemples montrés, ça devrait quand même fonctionner. Même si c'est certain qu'array_agg est une bien meilleure solution.
Fayden.
La méthode de Lord Casque Noir marche dans mon cas,
si j'ai un élément ``pommefraise'' il est bien distinct des éléments du tableau : pomme et fraise.
La confusion vient du fait que j'ai du mal expliquer mon exemple.
Si j'ai dans un même ensemble une pomme et une fraise, ma table d'origine aura:
1 pomme
1 fraise
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
* Un wrapper C++ pour sqlite * Une alternative a boost units
* Un wrapper C++ pour sqlite * Une alternative a boost units
* Un wrapper C++ pour sqlite * Une alternative a boost units
* Un wrapper C++ pour sqlite * Une alternative a boost units