Search code examples
mysqlsubquerymysql-error-1242

mySQL, need help getting many sub-queries into 1 SELECT query (displays 13 columns)


this is my first post. I know that this is horribly inefficient and repetitive code that won't actually work, what I need to do is combine all these outputs into 1 select statement. I am obviously fairly new at this, but I've been at it all day and I just can't get started in the right direction, each snippet works on its own...please help!

Essentially I'm working with a DB with many tables, and to get the right data for each column, I often have to account for 3 tables with joins.

Thanks for any insight or help!

SELECT 
  Product.ProductID,
  (
  SELECT Abbreviation AS Country
  FROM Product
  LEFT JOIN ProductCountry 
    ON Product.ProductID = ProductCountry.ProductID
  LEFT JOIN Location 
    ON ProductCountry.LocationID = Location.LocationID
  GROUP BY Product.ProductID
  ),

  (
  SELECT r.ResourceName AS Manufacturer, rr.ResourceName AS Brand
  FROM Product p
  LEFT JOIN Resource r 
    ON p.ManufactureCode = r.ResourceID
  INNER JOIN Resource rr 
    ON p.BrandCode = rr.ResourceID
  ),

  Product.Name,
  Product.UPC,
  Product.Size,

  (
  SELECT Unit.abbreviation AS Measure
  FROM Product
  LEFT JOIN Unit 
    ON Product.Unit = Unit.UnitID
  ),

  (
  SELECT Category.ParentID AS Category, Category.Description AS Sub_Category
  FROM Product
  LEFT JOIN ProductCategory 
    ON Product.ProductID = ProductCategory.ProductID
  LEFT JOIN Category 
    ON ProductCategory.CategoryID = Category.CategoryID
  ),

  (
  SELECT i.Description AS INGREDIENTS, i.MayContain AS Allergen_Statement
  FROM Product
  LEFT JOIN Ingredient i 
    ON Product.ProductID = i.IngredientID
  ),

  (
  SELECT GROUP_CONCAT( Special.Description SEPARATOR ', ' ) AS Free_From
  FROM Product
  LEFT JOIN ProductSpecial 
    ON Product.ProductID = ProductSpecial.ProductID
  LEFT JOIN Special 
    ON ProductSpecial.SpecialID = Special.SpecialID
  GROUP BY Product.ProductID
  )

FROM Product, ProductStatus
WHERE ProductStatus.ProductStatusID = 1

Solution

  • First, some notes and assumptions...

    • I'm assuming the Country column is in the Location table, otherwise why would you bother joining it.

    • If you have trouble with this part, change the second join to a LEFT JOIN. I've had occasional trouble doing left join a to b followed by inner join b to c. I've found it's easier to keep the LEFT JOIN going, so my example left-joins both tables:

        LEFT JOIN Resource r 
          ON p.ManufactureCode = r.ResourceID
        INNER JOIN Resource rr 
          ON p.BrandCode = rr.ResourceID
      
    • You're joining to Resource in two different ways. That's completely OK with MySQL (and all the mainstream databases). You just have to alias one or both of the joins. I've aliased one of them:

      LEFT JOIN Resource ON Product.ManufactureCode ...
      LEFT JOIN Resource BrandResource ON Product.BrandCode...
      
    • I don't know from your example how ProductStatus is joined. You'll have to supply that.

    • Start small using the example below. Join in the Country, then when you've got that working, join in Manufacturer, then Brand, then Measure, etc. The query isn't doing a lot of advanced stuff; it's complicated mostly due to the sheer number of tables. Tackle them one at a time and you'll win :)

    • Finally, as @Bohemian noted in the comments, the GROUP BY can't be brought up to the top. Actually, it probably can, but it will complicate things beyond belief. I've left that as a subquery.

    Here's the final result. Note that it's not tested because it's huge and I don't have table structures or sample data. But mostly because it's huge :) At any rate, this is meant as an example only.

    SELECT 
      Product.ProductID,
      Location.Country,
      Resource.ResourceName AS Manufacturer,
      BrandResource.ResourceName AS Brand,
      Product.Name,
      Product.UPC,
      Product.Size,
      Unit.Abbreviation AS Measure,
      Category.ParentID AS Category,
      Category.Description AS Sub_Category,
      Ingredient.Description AS Ingredients,
      Ingredient.MayContain AS Allergen_Statement,
      (SELECT GROUP_CONCAT( Special.Description SEPARATOR ', ' ) AS Free_From
        FROM Product
        LEFT JOIN ProductSpecial 
          ON Product.ProductID = ProductSpecial.ProductID
        LEFT JOIN Special 
          ON ProductSpecial.SpecialID = Special.SpecialID
        GROUP BY Product.ProductID
        )
    FROM Product
      INNER JOIN ProductStatus ON ... however it's joined
      LEFT JOIN ProductCountry ON Product.ProductID = ProductCountry.ProductID
      LEFT JOIN Location ON ProductCountry.LocationID = Location.LocationID
      LEFT JOIN Resource ON Product.ManufactureCode = Resource.ResourceID
      LEFT JOIN Resource BrandResource ON Product.BrandCode = BrandResource.ResourceID
      LEFT JOIN Unit ON Product.Unit = Unit.UnitID
      LEFT JOIN ProductCategory ON Product.ProductID = ProductCategory.ProductID
      LEFT JOIN Category ON ProductCategory.CategoryID = Category.CategoryID
      LEFT JOIN Ingredient ON Product.ProductID = i.IngredientID
    WHERE ProductStatus.ProductStatusID = 1