Mysql
 sql >> Datenbank >  >> RDS >> Mysql

MySQL - Kombinieren von zwei Select-Anweisungen zu einem Ergebnis mit LIMIT effizient

Sie können mehrere Abfragen mit UNION kombinieren , aber nur, wenn die Abfragen die gleiche Anzahl von Spalten haben. Idealerweise sind die Spalten gleich, nicht nur im Datentyp, sondern auch in ihrer semantischen Bedeutung; MySQL kümmert sich jedoch nicht um die Semantik und behandelt unterschiedliche Datentypen, indem es in etwas Allgemeineres umwandelt - Sie könnten es also notfalls tun Überladen Sie die Spalten so, dass sie unterschiedliche Bedeutungen aus jeder Tabelle haben, und bestimmen Sie dann, welche Bedeutung in Ihrem Code auf höherer Ebene angemessen ist (obwohl ich es nicht empfehle, dies auf diese Weise zu tun).

Wenn die Anzahl der Spalten unterschiedlich ist oder wenn Sie eine bessere/weniger überladene Ausrichtung der Daten aus zwei Abfragen erreichen möchten, können Sie Dummy-Literalspalten in Ihr SELECT einfügen Aussagen. Zum Beispiel:

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

Sie könnten sogar einige Spalten für die erste Tabelle und andere für die zweite Tabelle reservieren, sodass sie NULL sind an anderer Stelle (aber denken Sie daran, dass die Spaltennamen aus der ersten Abfrage stammen, daher möchten Sie vielleicht sicherstellen, dass sie alle dort benannt sind):

  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;

Sie könnten versuchen, Ihre beiden Abfragen auf diese Weise auszurichten und sie dann mit einer UNION zu kombinieren Operator; durch Anwenden von LIMIT an die UNION , Sie haben Ihr Ziel fast erreicht:

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

Das einzige Problem, das bleibt, ist, dass, wie oben dargestellt, 10 oder mehr Datensätze aus der ersten Tabelle alle Datensätze aus der zweiten "verdrängen". Wir können jedoch einen ORDER BY verwenden in der äußeren Abfrage, um dies zu lösen.

Alles zusammen:

(
  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;

Jetzt liegt es natürlich an Ihnen, zu bestimmen, mit welcher Art von Zeile Sie es zu tun haben, wenn Sie jeden Datensatz in der Ergebnismenge lesen (schlagen Sie vor, dass Sie request_id testen und/oder alert_id für NULL Werte; Alternativ könnte man den Ergebnissen eine zusätzliche Spalte hinzufügen, die explizit angibt, aus welcher Tabelle jeder Datensatz stammt, aber es sollte äquivalent sein, vorausgesetzt, diese id Spalten sind NOT NULL ).