it-swarm-fr.com

Comment puis-je faire un groupe complexe par MySQL?

J'ai une table contenant plusieurs clés dans d'autres tables (où chaque clé est composée de multiples colonnes). J'aimerais pouvoir regrouper des lignes ensemble qui ont une clé égale, mais je ne veux pas grouper tout d'entre eux ensemble. Ce n'est pas un simple GROUP BY Sur la clé, mais je veux plutôt pouvoir faire des groupes de dises. Donc, si une clé particulière a montré 50 fois, j'obtiendrais 5 résultats lorsque je fais ce groupe (5 groupes de 10). Je veux aussi que ce groupe se produise au hasard dans la clé.

Je ne connaissais pas la voie directe de le faire et la méthode du rond-point que j'ai proposée ne fonctionne pas comme je pense que cela devrait. La solution rond-point que j'ai proposée était de créer une nouvelle colonne pour chaque clé qui serait un entier tel que la valeur i représente la survenue ith occurrence de cette clé (mais dans un ordre aléatoire). Je pourrais alors faire une division entière afin que chaque n (disons 10) rangées dans la clé ait la même valeur et que je pourrais faire un GROUP BY sur cette valeur.

Y a-t-il une façon plus directe d'accomplir ce que je viens de décrire? C'est assez maladroit et j'ai rencontré des problèmes dans la création de la nouvelle colonne d'index (comme je l'ai décrit dans cette question ).

Edit: Tout d'abord, notez que c'est pour MySQL. J'ajouterai un exemple au cas où mon objectif n'est pas clair. Les documents MySQL montrent une méthode pour obtenir presque là :

CREATE TABLE animals (
    grp ENUM('fish','mammal','bird') NOT NULL,
    id MEDIUMINT NOT NULL AUTO_INCREMENT,
    name CHAR(30) NOT NULL,
    PRIMARY KEY (grp,id)
) ENGINE=MyISAM;

INSERT INTO animals (grp,name) VALUES
    ('mammal','dog'),('mammal','cat'),
    ('bird','penguin'),('fish','lax'),('mammal','whale'),
    ('bird','ostrich');

SELECT * FROM animals ORDER BY grp,id;

Cela crée une table qui, bien que pas ce que je veux, se rapproche:

+--------+----+---------+
| grp    | id | name    |
+--------+----+---------+
| fish   |  1 | lax     |
| mammal |  1 | dog     |
| mammal |  2 | cat     |
| mammal |  3 | whale   |
| bird   |  1 | penguin |
| bird   |  2 | ostrich |
+--------+----+---------+

Je voudrais essentiellement GROUP BY ID, sauf que je souhaiterais que les enregistrements avec mammal ont un "groupe" pour IDS 1-10, un autre "groupe" pour IDS 11-20, etc. Cependant, je le ferais avec un Table existante, et je ne voudrais pas nécessairement que "chien" apparaître avec ID 1. Je voudrais que la commande initiale soit aléatoire, mais puis déterministe à partir de là.

8
Michael McGowan

Qu'en est-il de faire un peu de mathématiques contre votre colonne d'identité pour générer dynamiquement le groupe?

SELECT grp, FLOOR(id/10) AS id_grp
FROM animals
GROUP BY grp, id_grp

Cela vous donnerait des groupes de 10 basés sur l'identifiant de l'enregistrement. J'ai utilisé votre table d'animaux ci-dessus pour générer les données ci-dessous.

Exemple de données

 INSERT INTO animals VALUES
 ('mammal',10,'dog'),('mammal',11,'dog'),('mammal',12,'dog'),
 ('mammal',21,'cat'),('mammal',22,'cat'),('mammal',23,'cat'),
 ('mammal',24,'cat'),('mammal',25,'cat'),('mammal',26,'cat'),
 ('bird',30,'penguin'),('bird',31,'penguin'),('bird',32,'penguin'),
 ('bird',33,'penguin'),('fish',44,'lax'),('fish',45,'lax'),
 ('fish',46,'lax'),('fish',47,'lax'),('fish',48,'lax'),
 ('mammal',31,'whale'),*'fish',51,'lax'),('fish',52,'lax'),
 ('fish',53,'lax'),('fish',54,'lax'),('bird',10,'ostrich');

Sortie de requête

 +--------+--------+
 | grp    | id_grp |
 +--------+--------+
 | fish   |      4 |
 | fish   |      5 |
 | mammal |      1 |
 | mammal |      2 |
 | mammal |      3 |
 | bird   |      1 |
 | bird   |      3 |
 +--------+--------+
 7 rows in set (0.00 sec)
5
nabrond

Dans SQL, cela serait généralement:

  • un sous-sélection distinct
  • Revenir à la table principale sur les clés distinctes
  • Ntile avec une partition par des clés distinctes et une commande en créant des godets

Ce n'est pas un groupe d'agrégats, alors groupe n'est pas nécessaire

Éditer:

En fait, NTILE suffit à créer "n gaux par série de valeurs distinctes"

2
gbn

Je ne vois toujours pas de solutions complètes (qui fonctionnent réellement dans MySQL), c'est donc la solution que je vais probablement utiliser:

  1. Générez les identifiants aléatoires en dehors de SQL entièrement (dans une sorte de script)
  2. Appliquez une division entière sur ces identifiants pour les grouper en conséquence.

J'espère toujours que quelqu'un peut battre cette réponse; Je ne veux pas avoir à accepter ma propre réponse. J'ai déjà dit cela auparavant, mais je savais dès le début comment faire n ° 2; # 1 est ce qui me trouble. Si vous pouvez répondre au numéro 1, vous répondez réellement ne autre question aussi, mais il pourrait être possible de répondre à cette question d'une autre manière afin de contourner le passage n ° 1.

1
Michael McGowan
-- Change 'ValueField' to whatever provides your 'group' values

set @rownum := 0;
set @groupnum := 0;
set @lastGroup := 0;

select
    ValueField, 
    Grouping, 
    count(1) as Count
from
    (
        -- We have a row number for each record
        select
            -- Set the record number
            case when @lastGroup != ValueField 
                then @rownum := 0 else (@rownum := @rownum + 1) 
            end as Record, 

            -- Determine which group we are in
            case
                -- If the 'Group' changed, reset our grouping
                when @lastGroup != ValueField 
                    then @groupnum := 0

                -- Determines the grouping value; group size is set to 10
                when floor(@rownum / 10) != @groupnum 
                    then @groupnum := @groupnum + 1 
                else @groupnum
            end as Grouping,

            -- Track the last Group
            case 
                when @lastGroup != ValueField 
                    then @lastGroup := ValueField 
                else @lastGroup 
            end as LastGroup,

            -- Value field that will be aggregated
            ValueField 
        from 
            YourTable
        order by 
            ValueField
    ) as x
group by
    ValueField, 
    Grouping;
0
dba4life