Seleziona le righe in base alla data più recente con più join


8

Ho questa domanda ( SQLFiddle ):

SELECT
c.name,
a.user_id,
a.status_id,
a.title,
a.rtime,
u.user_name,
s.status_name

FROM company c

LEFT JOIN action a ON a.company_id=c.id
LEFT JOIN user u ON u.id=a.user_id
LEFT JOIN status s ON s.id=a.status_id



WHERE u.user_name='Morgan'

-- WHERE c.name='Fiddle'

GROUP BY c.id

HAVING a.rtime IS NULL OR a.rtime = (
 SELECT max(rtime)
 FROM action a2
 WHERE deleted IS NULL
 AND a2.company_id = c.id
 )

Problema 1

Voglio elencare tutte le società e mostrare l'utente e lo stato in cui hanno fatto un'azione per l'ultima volta sulla società. Allo stesso tempo, mostrare alle aziende in cui non sono state intraprese azioni.

Problema 2

Devo anche essere in grado di cercare l'utente per nome, quindi selezionando tutte le società in cui questo utente ha avuto l'ultima attività. La query è fatta da un modulo, quindi posso iniettare variabili.


Al momento non sono in grado di modificare il database SCHEMA, ma i consigli per una futura migrazione sono molto apprezzati.

Ho provato a legarlo insieme INNER JOIN ( SELECT.. ) t ONma non riesco a pensarci.

Ho anche provato i metodi da qui , qui e qui, ma non riesco a trovare la persona con l'ultima attività nel modo giusto.

Versione MySQL: 5.5.16. La tabella aziendale ha circa 1 milione di file e la tabella azioni è a 70 KB, in crescita. Le prestazioni sono importanti per me qui.

Come può essere risolto?


2
Vedi questa domanda: MySQL query ottimizzata Invece di MAX(Marks)per TaskID, vuoi MAX(ActivityDate)per Company.) Non c'è molta differenza se hai una tabella o un join.
ypercubeᵀᴹ

Risposte:


7

La tua query può essere semplificata per:

SELECT
    c.id,
    c.name,
    a.rtime,
    s.status_name,
    u.user_name
FROM company c
    LEFT JOIN
      ( SELECT 
            company_id,
            MAX(rtime) AS maxdate
        FROM action
        WHERE deleted IS NULL
        GROUP BY company_id
      ) AS x ON x.company_id = c.id
    LEFT JOIN action a ON  a.deleted IS NULL
                       AND a.company_id = x.company_id 
                       AND a.rtime = x.maxdate 
    LEFT JOIN user u ON u.id = a.user_id
    LEFT JOIN status s ON s.id = a.status_id
WHERE 
    c.name LIKE 'Company%' ;

Un indice (deleted, company_id, rtime)attivo renderebbe efficiente la sottoquery della tabella derivata. Suppongo che tu abbia già indici sulle colonne utilizzate per i join e sul Company (name).

SQL-Fiddle


1
Questo è più semplice e sembra circa 0,3 secondi più veloce per 100 righe rispetto alla mia risposta.
stiq

2

Dopo aver provato le diverse risposte, l'ho fatto funzionare, ma l'ho trovato lento nella mia configurazione.

ypercube mi ha indicato una risposta che ha indicato altre domande simili su come MySQL sta raggruppando i risultati. Questo mi ha portato a questa risorsa dove ho finalmente capito cosa stava succedendo.

Il risultato è una query come questa:

SELECT
c.id,
c.name,

a.rtime,

s.status_name,

u.user_name


FROM company c

LEFT JOIN (
    SELECT 
        a.company_id,
        a.rtime,
        a.user_id,
        a.status_id
        FROM
            (
            SELECT company_id,
 MAX(rtime) as maxdate
            FROM action
            WHERE deleted IS NULL
            GROUP BY company_id
            ) as x

        LEFT JOIN action a ON a.rtime=x.maxdate AND a.company_id=x.company_id

) as a ON a.company_id=c.id

LEFT JOIN user u ON u.id=a.user_id
LEFT JOIN status s ON s.id=a.status_id

WHERE (1)

-- Search by user
-- AND u.user_name LIKE 'Johnny'

-- Seach by company name
AND c.name LIKE 'Company%'

Ecco un violino con la query funzionante


1

È necessario spostare le tabelle utente, azione e stato in una query secondaria, come questa:

SELECT
c.name,
a.user_id,
a.status_id,
a.title,
a.max_rtime,
a.user_name,
a.status_name

FROM company c

LEFT JOIN
(select company_id, user_id, 
 max(rtime) max_rtime, 
 title, status_id, s.status_name,
 u.user_name
 from action INNER JOIN
  status s ON s.id=action.status_id
  INNER JOIN user u ON u.id=action.user_id
 where action.deleted IS NULL
 group by company_id, user_id, status_id, s.status_name, title, u.user_name
) a ON a.company_id=c.id AND a.user_name='Morgan'


GROUP BY c.id

SQL Fiddle

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.