J'ai cette requête ( 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
)
Problème 1
Je souhaite répertorier toutes les sociétés et afficher l'utilisateur et le statut de sa dernière action sur la société. En même temps, montrez aux entreprises où aucune action n'a été entreprise.
Problème 2
Je dois également pouvoir rechercher l'utilisateur par son nom, sélectionnant ainsi toutes les entreprises où cet utilisateur a eu la dernière activité. La requête est faite à partir d'un formulaire, donc je peux injecter des variables.
Je ne suis pas en mesure de modifier la base de données SCHEMA pour le moment, mais les conseils pour une future migration sont très appréciés.
J'ai essayé de le lier avec INNER JOIN ( SELECT.. ) t ON
mais je n'arrive pas à comprendre.
J'ai également essayé des méthodes de ici , ici , et ici mais je n'arrive pas à obtenir la bonne personne avec la dernière activité.
Version MySQL: 5.5.16. La table d'entreprise a environ 1 million de lignes et la table d'action est à 70K, en croissance. La performance est importante pour moi ici.
Comment résoudre ce problème?
Votre requête peut être simplifiée pour:
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 index sur (deleted, company_id, rtime)
Rendrait la sous-requête de table dérivée efficace. Je suppose que vous avez déjà des index sur les colonnes utilisées pour les jointures et sur la Company (name)
.
Après avoir essayé les différentes réponses, je l'ai fait fonctionner, mais je l'ai trouvé lent dans ma configuration.
ypercube m'a pointé vers une réponse qui a pointé d'autres questions similaires sur la façon dont MySQL regroupe les résultats. Cela m'a conduit à cette ressource où j'ai finalement compris ce qui se passait.
Le résultat étant une requête comme celle-ci:
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%'
Vous devez déplacer les tableaux d'utilisateurs, d'actions et d'état dans une sous-requête, comme ceci:
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