2017-06-22 1 views
3

J'ai une requête qui a fonctionné dans notre module de données SQL Firebird.Migration de requête Firebird vers MySQL - Sélectionnez Inner Join Sous-requête

Nous avons migré vers MySQL et toutes mes requêtes ne posent aucun problème sauf pour celui-ci.

S'il vous plaît aidez-moi à résoudre ce problème. Je reçois une erreur:

Failed to Execute. Unknown column 'part.id' in 'on clause'

Ma requête Firebird:

SELECT vendor.name AS "Vendor Name", 
    Cast(Cast(vendorparts.lastdate AS date) AS CHAR(10)) AS "Last Date", 
    CASE product.price 
    WHEN '0' THEN 'CONFIRM' 
    WHEN NULL THEN 'CONFIRM' 
    ELSE Round(product.price, 2) 
    end AS "D-Price", 
    Cast(vendorparts.lastcost AS DECIMAL(18, 2)) AS "Last Cost", 
    Cast(lowestcost.lowestcost AS DECIMAL(18, 2)) AS "Lowest Cost", 
    Cast(highestcost.highestcost AS DECIMAL(18, 2)) AS "Highest Cost", 
    part.num AS "Part Number", 
    part.description AS "Part Description" 

FROM vendor, 
     vendorparts, 
     part, 
     product 
     INNER JOIN (SELECT vendorparts.partid, 
          Max(vendorparts.lastcost) AS Highestcost 
        FROM vendorparts 
        GROUP BY vendorparts.partid) AS highestcost 
       ON part.id = highestcost.partid 
     INNER JOIN (SELECT vendorparts.partid, 
          Min(vendorparts.lastcost) AS Lowestcost 
        FROM vendorparts 
        GROUP BY vendorparts.partid) AS lowestcost 
       ON part.id = lowestcost.partid 
WHERE vendor.id = vendorparts.vendorid 
     AND product.partid = part.id 
     AND vendorparts.partid = part.id 
     AND vendorparts.lastcost <> 0 

Toutes les tables sont dans la base de données, sauf pour lowestcost et highestcost qui ont été créés dans les sous-requêtes.

J'espère que ma demande est clairement écrite. Mais pour résumer, j'ai besoin que cette requête Firebird fonctionne pour migrer vers MySQL.

Pourquoi cela fonctionnerait-il dans Firebird mais pas dans MySQL?

+1

ne pas mélanger des virgules et la syntaxe de jointure jointure interne syntaxe .. –

+0

Puis-je demander pourquoi vous migrez vers MySQL? – skafinski

+1

@skafinski Notre système de gestion des stocks mis à jour vers une nouvelle version hier. L'ensemble du système a migré de Firebird SQL vers MySQL. Jusqu'à présent, les performances ont été nettement améliorées et les requêtes sont compilées beaucoup plus rapidement. –

Répondre

4

Le problème est que dans le mySQL comma operator has lower precedence que l'opérateur join donc le product inner join (subquery) on part.id = highestcost.partid inner join (subquery) on part.id = lowestcost.partid sont évalués jointures avant la table part est rejoint dans l'expression, d'où le message d'erreur.

Remplacer les opérateurs par des virgules avec de simples join opérateurs et déplacer les conditions de jointure de la clause where à on clauses et tout ira bien:

... 
FROM vendor 
     inner join vendorparts on vendor.id = vendorparts.vendorid 
     inner join part on vendorparts.partid = part.id 
     inner join product on product.partid = part.id 
     INNER JOIN (SELECT vendorparts.partid, 
          Max(vendorparts.lastcost) AS Highestcost 
        FROM vendorparts 
        GROUP BY vendorparts.partid) AS highestcost 
       ON part.id = highestcost.partid 
     INNER JOIN (SELECT vendorparts.partid, 
          Min(vendorparts.lastcost) AS Lowestcost 
        FROM vendorparts 
        GROUP BY vendorparts.partid) AS lowestcost 
       ON part.id = lowestcost.partid 
WHERE vendorparts.lastcost <> 0 

Si vous avez plus de telles requêtes où vous mélangez opérateur virgule et explicite joint, alors vous devriez les vérifier car ils peuvent produire des résultats différents même s'il n'y avait pas d'erreur de syntaxe dans MySQL.

+0

Merci Shadow. C'était la première réponse et a fonctionné tout de suite. Explication simple. –

+0

Le mélange de jointures explicites (SQL-92) et implicites (SQL-89) dans Firebird est également considéré comme un mauvais style, connu pour provoquer des effets inattendus et même des bogues. Ces requêtes seront mieux retravaillées même pour la base de données Firebird initiale –

1

Cette requête ne fonctionnerait pas non plus dans Firebird 3.0 et versions ultérieures (voir Support for Mixed-Syntax Joins is Gone). La raison en est que vous combinez des jointures de style SQL-89 avec des jointures de style SQL-92.

Vous devez réécrire la requête d'utiliser jointures explicites partout, donc:

... 
FROM vendor 
    inner join vendorparts on vendor.id = vendorparts.vendorid 
    inner join part on vendorparts.partid = part.id 
    inner join product on product.partid = part.id 
    INNER JOIN (SELECT vendorparts.partid, 
         Max(vendorparts.lastcost) AS Highestcost 
       FROM vendorparts 
       GROUP BY vendorparts.partid) AS highestcost 
      ON part.id = highestcost.partid 
    INNER JOIN (SELECT vendorparts.partid, 
         Min(vendorparts.lastcost) AS Lowestcost 
       FROM vendorparts 
       GROUP BY vendorparts.partid) AS lowestcost 
      ON part.id = lowestcost.partid 
WHERE vendorparts.lastcost <> 0 
1

Ne pas mélanger rejoindre explicites et implicites
Évitez l'utilisation de même alias dans les noms de colonne et de table (dans cet échantillon ai se référer à t1 et t2) et éviter l'AS pour le nom de table subselect

SELECT 
    vendor.name AS "Vendor Name", 
    Cast(Cast(vendorparts.lastdate AS date) AS CHAR(10)) AS "Last Date", 
    CASE product.price 
    WHEN '0' THEN 'CONFIRM' 
    WHEN NULL THEN 'CONFIRM' 
    ELSE Round(product.price, 2) 
    end AS "D-Price", 
    Cast(vendorparts.lastcost AS DECIMAL(18, 2)) AS "Last Cost", 
    Cast(lowestcost.lowestcost AS DECIMAL(18, 2)) AS "Lowest Cost", 
    Cast(highestcost.highestcost AS DECIMAL(18, 2)) AS "Highest Cost", 
    part.num AS "Part Number", 
    part.description AS "Part Description" 

FROM vendor 
INNER JOIN vendorparts on vendor.id = vendorparts.vendorid AND vendorparts.lastcost <> 0 
INNER JOIN part on vendorparts.partid = part.id and 
INNER JOIN product on product.partid = part.id 
INNER JOIN (SELECT vendorparts.partid, 
          Max(vendorparts.lastcost) AS Highestcost 
        FROM vendorparts 
        GROUP BY vendorparts.partid) t1 
       ON part.id = t1.partid 
INNER JOIN (SELECT vendorparts.partid, 
          Min(vendorparts.lastcost) AS Lowestcost 
        FROM vendorparts 
        GROUP BY vendorparts.partid) t2 
       ON part.id = t2.partid