Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

MySQL - Combinando duas instruções select em um resultado com LIMIT eficientemente


Você pode combinar várias consultas com UNION , mas somente se as consultas tiverem o mesmo número de colunas. Idealmente, as colunas são as mesmas, não apenas no tipo de dados, mas também em seu significado semântico; no entanto, o MySQL não se importa com a semântica e lidará com diferentes tipos de dados convertendo para algo mais genérico - então, se necessário, você poderia sobrecarregue as colunas para que tenham significados diferentes de cada tabela e, em seguida, determine qual significado é apropriado em seu código de nível superior (embora eu não recomende fazê-lo dessa maneira).

Quando o número de colunas é diferente, ou quando você deseja obter um alinhamento de dados melhor/menos sobrecarregado de duas consultas, você pode inserir colunas literais fictícias em seu SELECT declarações. Por exemplo:
SELECT t.cola, t.colb, NULL, t.colc, NULL FROM t;

Você pode até ter algumas colunas reservadas para a primeira tabela e outras para a segunda tabela, de modo que sejam NULL em outro lugar (mas lembre-se de que os nomes das colunas vêm da primeira consulta, portanto, você pode querer garantir que todos sejam nomeados lá):
  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;

Você pode tentar alinhar suas duas consultas dessa maneira e combiná-las com um UNION operador; aplicando LIMIT para a UNION , você está perto de atingir sua meta:
  (SELECT ...)
UNION
  (SELECT ...)
LIMIT 10;

O único problema que permanece é que, conforme apresentado acima, 10 ou mais registros da primeira tabela "empurrarão" quaisquer registros da segunda. No entanto, podemos utilizar um ORDER BY na consulta externa para resolver isso.

Juntando tudo:
(
  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;

Claro, agora cabe a você determinar com que tipo de linha você está lidando enquanto lê cada registro no conjunto de resultados (sugiro que você teste request_id e/ou alert_id para NULL valores; alternativamente, pode-se adicionar uma coluna adicional aos resultados que indica explicitamente de qual tabela cada registro se originou, mas deve ser equivalente desde que id colunas são NOT NULL ).