简体   繁体   中英

Better way of doing multiple sub-selects?

Pretty standard setup with a table of products, categories and products in categories, but I was wondering if there is a better/more effective way to get the several top categories for a product (I don't really want to bring them back as separate rows so an inner join isn't viable).

The SQL I have currently is:

 SELECT p.*,
  (SELECT TOP 1 category_name FROM categories c INNER JOIN products_and_categories pc ON pc.category_id = c.category_id WHERE p.product_id = pc.product_id AND category_parent = 100 ORDER BY sort) AS cat_1,
  (SELECT TOP 1 category_name FROM categories c INNER JOIN products_and_categories pc ON pc.category_id = c.category_id WHERE p.product_id = pc.product_id AND category_parent = 200 ORDER BY sort) AS cat_2,
  (SELECT TOP 1 category_name FROM categories c INNER JOIN products_and_categories pc ON pc.category_id = c.category_id WHERE p.product_id = pc.product_id AND category_parent = 500 ORDER BY sort) AS cat_3,
  (SELECT TOP 1 category_name FROM (SELECT TOP 2 c.* FROM categories c INNER JOIN products_and_categories pc ON pc.category_id = c.category_id WHERE p.product_id = pc.product_id AND category_parent = 500  ORDER BY sort) c1 ORDER BY sort DESC) AS cat_4,
  (SELECT TOP 1 category_name FROM categories c INNER JOIN products_and_categories pc ON pc.category_id = c.category_id WHERE p.product_id = pc.product_id AND category_parent = 50 ORDER BY sort) AS cat_5,
  (SELECT TOP 1 category_name FROM (SELECT TOP 2 c.* FROM categories c INNER JOIN products_and_categories pc ON pc.category_id = c.category_id WHERE p.product_id = pc.product_id AND category_parent = 50  ORDER BY sort) c1 ORDER BY sort DESC) AS cat_6
FROM products AS p

I'm happy enough doing it this way for a couple of columns, but was wondering if there was any other way to do it? Either by joining on a PIVOT table or something else I've not thought of or if I should just accept doing it this way.

There are a couple of other restrictions (which may or may not be important):

  • Some of the sub queries may not bring back any results
  • Some of the rows I require the top 2 categories (as can be seen in the above code)

Since your correlated subqueries only have simple equals conditions you can move these to a join, then rather than using TOP 1 you can use ROW_NUMBER() to sort your categories, then only select the top 1 for each product_ID/Parent_category combination, or in the case of two of your fields, select the the second category.

I think this would work for you:

WITH ProductCategories AS
(   SELECT  pc.Product_ID,
            c.category_name,
            category_parent,
            RowNum = ROW_NUMBER() OVER(PARTITION BY pc.Product_ID, category_parent ORDER BY Sort)
    FROM    categories c 
            INNER JOIN products_and_categories pc 
                ON pc.category_id = c.category_id   
), MaxProductCategories AS
(   SELECT  Product_ID,
            [Cat_1] = MAX(CASE WHEN RowNum = 1 AND category_parent = 100 THEN category_name END),
            [Cat_2] = MAX(CASE WHEN RowNum = 1 AND category_parent = 200 THEN category_name END),
            [Cat_3] = MAX(CASE WHEN RowNum = 1 AND category_parent = 500 THEN category_name END),
            [Cat_4] = MAX(CASE WHEN RowNum = 2 AND category_parent = 500 THEN category_name END),
            [Cat_5] = MAX(CASE WHEN RowNum = 1 AND category_parent = 50 THEN category_name END),
            [Cat_6] = MAX(CASE WHEN RowNum = 2 AND category_parent = 50 THEN category_name END)
    FROM    ProductCategories
    WHERE   RowNum IN (1, 2)
    AND     category_parent IN (50, 100, 200, 500)
    GROUP BY Product_ID
)
SELECT  p.*,
        mpc.Cat_1,
        mpc.Cat_2,
        mpc.Cat_3,
        mpc.Cat_4,
        mpc.Cat_5,
        mpc.Cat_6
FROM    products p
        LEFT JOIN MaxProductCategories mpc
            ON mpc.Product_ID = p.Product_ID;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM