Mysql
 sql >> Base de données >  >> RDS >> Mysql

MySQL - Combinaison efficace de deux instructions select en un seul résultat avec LIMIT

Vous pouvez combiner plusieurs requêtes avec UNION , mais uniquement si les requêtes ont le même nombre de colonnes. Idéalement, les colonnes sont les mêmes, non seulement dans le type de données, mais aussi dans leur signification sémantique ; cependant, MySQL ne se soucie pas de la sémantique et gérera différents types de données en convertissant en quelque chose de plus générique - donc si nécessaire, vous pourriez surchargez les colonnes pour avoir des significations différentes de chaque table, puis déterminez quelle signification est appropriée dans votre code de niveau supérieur (bien que je ne recommande pas de le faire de cette façon).

Lorsque le nombre de colonnes diffère, ou lorsque vous souhaitez obtenir un alignement meilleur/moins surchargé des données de deux requêtes, vous pouvez insérer des colonnes littérales factices dans votre SELECT déclarations. Par exemple :

SELECT t.cola, t.colb, NULL, t.colc, NULL FROM t;

Vous pourriez même avoir des colonnes réservées pour la première table et d'autres pour la deuxième table, de sorte qu'elles soient NULL ailleurs (mais n'oubliez pas que les noms de colonne proviennent de la première requête, vous pouvez donc vous assurer qu'ils sont tous nommés ici) :

  SELECT a, b, c, d, NULL AS e, NULL AS f, NULL AS g FROM t1
UNION ALL -- specify ALL because default is DISTINCT, which is wasted here
  SELECT NULL, NULL, NULL, NULL, a, b, c FROM t2;

Vous pouvez essayer d'aligner vos deux requêtes de cette manière, puis les combiner avec un UNION opérateur; en appliquant LIMIT à l'UNION , vous êtes sur le point d'atteindre votre objectif :

  (SELECT ...)
UNION
  (SELECT ...)
LIMIT 10;

Le seul problème qui subsiste est que, comme présenté ci-dessus, 10 enregistrements ou plus de la première table "poussent" tous les enregistrements de la seconde. Cependant, nous pouvons utiliser un ORDER BY dans la requête externe pour résoudre ce problème.

Rassembler le tout :

(
  SELECT
    dr.request_time AS event_time, m.member_name,      -- shared columns
    dr.request_id, dr.member1, dr.member2,             -- request-only columns
    NULL AS alert_id, NULL AS alerter_id,              -- alert-only columns
      NULL AS alertee_id, NULL AS type
  FROM dating_requests dr JOIN members m ON dr.member1=m.member_id 
  WHERE dr.member2=:loggedin_id
  ORDER BY event_time LIMIT 10 -- save ourselves performing excessive UNION
) UNION ALL (
  SELECT
    da.alert_time AS event_time, m.member_name,        -- shared columns
    NULL, NULL, NULL,                                  -- request-only columns
    da.alert_id, da.alerter_id, da.alertee_id, da.type -- alert-only columns
  FROM
    dating_alerts da
    JOIN dating_alerts_status das USING (alert_id, alertee_id)
    JOIN members m ON da.alerter_id=m.member_id
  WHERE
    da.alertee_id=:loggedin_id
    AND da.type='platonic'
    AND das.viewed='0'
    AND das.viewed_time<da.alert_time
  ORDER BY event_time LIMIT 10 -- save ourselves performing excessive UNION
)
ORDER BY event_time
LIMIT 10;

Bien sûr, c'est maintenant à vous de déterminer à quel type de ligne vous avez affaire lorsque vous lisez chaque enregistrement dans le jeu de résultats (nous vous suggérons de tester request_id et/ou alert_id pour NULL valeurs; alternativement, on pourrait ajouter une colonne supplémentaire aux résultats qui indique explicitement de quelle table provient chaque enregistrement, mais cela devrait être équivalent à condition que ces id les colonnes sont NOT NULL ).