web-dev-qa-db-fra.com

MySQL LIMIT dans JOIN

J'ai une association 1: m.

symbols table a plusieurs lignes dans company_key_statistics table. company_key_statistics a la colonne createdAt qui est l'horodatage indiquant quand la ligne a été créée. Je dois rejoindre la dernière symbols avec company_key_statistics, mais je n'ai besoin que des dernières company_key_statistics. Par exemple, je dois obtenir ORCL et MSFTsymbols et uniquement leur dernière company_key_statistics.

Jusqu'à présent, j'ai essayé cela.

SELECT `symbols`.`id`, 
       `symbols`.`symbol`, 
       `statistics`.
       `marketCapitalization` 
FROM   `symbols` 
       LEFT JOIN (SELECT `s`.`companyId`, 
                         `s`.`marketCapitalization` 
                  FROM   `company_key_statistics` AS `s`
                  WHERE  `s`.`companyId` = `symbols`.`id` 
                  ORDER by `createdAt` 
                  DESC LIMIT 1) AS `statistics` 
ON     `symbols`.`id` = `statistics`.`companyId` 
WHERE  `symbols`.`symbol` IN ('ORCL', 'SNAP');

Mais malheureusement, j'ai trouvé que je ne peux pas utiliser les colonnes de la requête parent dans les sous-requêtes JOIN.

Comment puis-je y parvenir?

3
Aren Hovsepyan

Essaye ça:

SELECT sym.id, sym.symbol, s.marketCapitalization 
  FROM symbols AS sym 
  INNER JOIN company_key_statistics AS s 
     ON sym.id = s.companyId 
  INNER JOIN (SELECT companyId, MAX(createdAt) AS createdAt 
                FROM company_key_statistics 
                GROUP BY companyId) AS smax 
     ON smax.companyId = s.companyId AND smax.createdAt = s.createdAt 
  WHERE sym.symbol IN ('ORCL','SNAP');

Étant donné que votre exemple publié était un LEFT JOIN, vous souhaitez peut-être également des entreprises sans données de capitalisation boursière dans votre réponse. Dans ce cas, nous devons imbriquer les sous-sélections, de cette façon:

SELECT sym.id, sym.symbol, s.marketCapitalization 
  FROM symbols AS sym 
  LEFT JOIN (SELECT * 
               FROM company_key_statistics
               INNER JOIN (SELECT companyId, MAX(createdAt) AS createdAt 
                             FROM company_key_statistics 
                             GROUP BY companyId) AS smax 
               USING (companyId, createdAt)) AS s 
    ON sym.id = s.companyId 
 WHERE sym.symbol IN ('ORCL','SNAP');

Le problème général que nous abordons ici est appelé maximum par groupe et de nombreuses réponses SO et DBA.SE le traitent). Vérifiez celui-ci par exemple.

2
Dario

Pour une sous-requête corrélée, vous devez utiliser un CROSS APPLY, malheureusement MySql ne le permet pas, mais vous pouvez le simuler de cette façon:

SELECT     `symbols`.`id`, 
           `symbols`.`symbol`, 
           `statistics`.
           `marketCapitalization`,
           `s`.`companyId`,
           `s`.`marketCapitalization`  
FROM       `symbols` 
INNER JOIN `company_key_statistics` `s`
ON         `s`.`pk` = (SELECT `pk`          -- the PK of company_key_statistics
                       FROM   `company_key_statistics`
                       WHERE  `companyId` = `symbols`.`id` 
                       ORDER by `createdAt` 
                       DESC LIMIT 1) 
WHERE  `symbols`.`symbol` IN ('ORCL', 'SNAP');

Vous pouvez trouver un exemple sur DONC .

3
McNets