J'ai un problème abstrait qui peut être simplifié comme le problème suivant: Supposons que nous avons deux tables persons
et names
qui ressemblent comme suit:Comment écrire une requête MySQL SELECT pour atteindre ce résultat?
SELECT * FROM persons;
+----+-------+--------+
| id | name | fan_of |
+----+-------+--------+
| 1 | alice | 2 |
| 2 | bob | 4 |
| 3 | carol | 1 |
| 4 | dave | 3 |
| 5 | bob | 2 |
+----+-------+--------+
et
SELECT * FROM names;
+----+-------+--------+
| id | name | active |
+----+-------+--------+
| 1 | alice | 1 |
| 2 | bob | 1 |
| 3 | carol | 0 |
| 4 | dave | 1 |
+----+-------+--------+
Toute personne (une rangée dans la table persons
) est un fan de lui-même ou d'une autre personne (représentée par les autres personnes id
dans la colonne fan_of
). La table names
contient des noms qui peuvent être actifs ou inactifs.
Pour un offset donné k
, je veux SELECT
les personnes (lignes de persons
) qui ont le nom k+1
-ème actif comme leur nom ou qui ont une de ces personnes que leurs fans. Par exemple, si le décalage est 1, le deuxième nom actif est bob et je veux donc sélectionner toutes les personnes avec le nom bob plus les personnes qui ont un de ces bobs en tant que leurs fans, qui est dans cet exemple la rangée de personnes avec id
= 4. Cela signifie que je veux avoir le résultat:
+----+------+--------+
| id | name | fan_of |
+----+------+--------+
| 2 | bob | 4 |
| 4 | dave | 3 |
| 5 | bob | 2 |
+----+------+--------+
Ce que j'ai à ce jour est la requête suivante:
1 SELECT * FROM persons WHERE
2 EXISTS (
3 SELECT * FROM (
4 SELECT * FROM names WHERE active=true LIMIT 1 OFFSET 1
5 ) AS selectedname WHERE (selectedname.name=persons.name)
6 )
7 OR
8 EXISTS (
9 SELECT * FROM(
10 SELECT * FROM persons WHERE EXISTS (
11 SELECT * FROM (
12 SELECT * FROM names WHERE active=true LIMIT 1 OFFSET 1
13 ) AS selectedname WHERE (selectedname.name=persons.name)
14 )
15 ) AS personswiththatname WHERE persons.id=personswiththatname.fan_of
16 );
Il me donne le résultat souhaité ci-dessus, mais s'il vous plaît noter qu'il est inefficace, car les lignes 3-5 et 11-13 sont les mêmes.
je les deux questions suivantes:
- Que peut-on faire pour éviter cette inefficacité?
j'ai réellement besoin de faire la distinction entre les lignes qui venaient de la
name
condition (ici les lignes avec le nom = bob) et ceux qui sont venus de la conditionfan_of
(ici la ligne avec le nom = dave). Ce pourrait être fait dans le code d'application mais alors j'aurais besoin d'une autre requête de base de données avant de trouver lek+1
-th nom actif et ceci pourrait être lent (s'il vous plaît corrigez-moi si c'est la meilleure solution). Je préférerais une colonne supplémentairez
qui me permet de distinguer comme+----+------+--------+---+ | id | name | fan_of | z | +----+------+--------+---+ | 2 | bob | 4 | 1 | | 4 | dave | 3 | 0 | | 5 | bob | 2 | 1 | +----+------+--------+---+
Comment une telle sortie est atteint?
Sur la base de votre exemple, devrait: "Pour un décalage k donné, je veux SÉLECTIONNER les personnes (rangées de personnes) ayant comme nom le k + 1-ème nom actif ou qui ont l'une de ces personnes comme leurs fans" Ne signifie pas réellement "Je veux sélectionner chaque personne de" personne "qui a le k + 1-ème nom actif, ou chaque personne qui est fan d'une autre personne avec ce nom? C'est la seule façon dont votre description a du sens pour moi –
@ChrisJ Non, je veux dire comme il est dit, mais j'avoue que cela n'a pas de sens comme un exemple du monde réel. Ce que je veux, c'est que toutes les personnes avec ce nom et tout ce qui est référé par la colonne 'fan_of'. – phinz
Donc, 'Dave' est récupéré parce que Bob est un fan de lui, et Bob est le nième nom actif (sélectionné)? –