выбор по одному результату запроса

#sql #sql-server-2005 #tsql

#sql #sql-server-2005 #tsql

Вопрос:

Я пытаюсь запросить несколько таблиц в нашей базе данных, которые содержат данные о продукте. Это база данных MSSQL 2005. Проблема в том, что он возвращает несколько строк для одного продукта, когда мне нужно, чтобы он создавал только одну строку для каждого продукта. Blow — это запрос и результаты, которые я использую.

 SELECT      ProductItem.sku, ProductItem.title, ProductItem.short_desc, ProductItem.long_desc, ProductItem.active, ProductItem.product_item_id, 
                    ProductCategory.category_desc, ProductCategoryMap.product_id, ProductCategory.active AS activecat, Product.adwords_label, 
                    ProductItem.item_price, ProductItem.sale_price
FROM          Product INNER JOIN
                        ProductCategoryMap INNER JOIN
                        ProductCategory ON ProductCategoryMap.product_category_id = ProductCategory.product_category_id ON 
                        Product.product_id = ProductCategoryMap.product_id FULL OUTER JOIN
                        ProductItem ON Product.product_key = ProductItem.sku
WHERE      (ProductItem.active = 1) AND (ProductCategory.active = 1)
  

Это возвращает следующие результаты:введите описание изображения здесь

Я знаю, что проблема возникает из-за того, что продукт находится в нескольких категориях, но на самом деле мне не нужны все категории, в которых он находится, только одна из них. Поэтому в идеале только один продукт для каждой возвращаемой строки

Однако я не могу понять, как заставить мой запрос достичь этого.

Кто-нибудь может мне помочь, пожалуйста?

Комментарии:

1. Если для продукта существует несколько категорий, и вы выбираете category_desc в списке выбора. Какую категорию вы хотите отобразить или вам все равно, какая из них отображается?

2. Для этого проекта мне все равно, какой из них отображается.

3. Мой ответ наиболее похож на KMs

Ответ №1:

На первый взгляд, уберите столбцы категорий и добавьте DISTINCT. Вы запросили «категорию», чтобы получить все категории.

Также:

  • где изменяет ваше ПОЛНОЕ ВНЕШНЕЕ соединение на ВНУТРЕННЕЕ
  • получить product_id из Product
  • столбец activecat в любом случае подразумевается предложением where

Я изменил его для наглядности и добавил агрегат, чтобы получить одну категорию

 SELECT
   PI.sku, PI.title, PI.short_desc, PI.long_desc, 
   PI.active, PI.product_item_id, 
   PI.item_price, PI.sale_price, 

   MIN(PC.category_desc),
   P.product_id,
   1 AS activecat, --implied by filter

   P.adwords_label
FROM 
    ProductItem PI
    INNER JOIN
    Product P ON P.product_key = PI.sku
    INNER JOIN
    ProductCategoryMap PCM ON P.product_id = PCM.product_id
    INNER JOIN
    ProductCategory PC ON PCM.product_category_id = PC.product_category_id
WHERE
   (PI.active = 1) AND (PC.active = 1)
GROUP BY
   PI.sku, PI.title, PI.short_desc, PI.long_desc, 
   PI.active, PI.product_item_id, 
   PI.item_price, PI.sale_price, 
   P.product_id,
   P.adwords_label
  

Редактировать: вы можете привести его в порядок с помощью APPLY, который также будет иметь дело с отсутствием категорий, если изменить его на OUTER APPLY

 SELECT
   PI.sku, PI.title, PI.short_desc, PI.long_desc, 
   PI.active, PI.product_item_id, 
   PI.item_price, PI.sale_price, 

   PC2.category_desc,
   P.product_id,
   PC2.active AS activecat,

   P.adwords_label
FROM 
    ProductItem PI
    INNER JOIN
    Product P ON P.product_key = PI.sku
    CROSS APPLY
    (
    SELECT TOP 1
        PC.category_desc, PC.active
    FROM
        ProductCategoryMap PCM
        INNER JOIN
        ProductCategory PC ON PCM.product_category_id = PC.product_category_id
    WHERE
       P.product_id = PCM.product_id AND PC.active = 1
    ORDER BY 
       PC.category_desc
    ) PC2
WHERE
   PI.active = 1
  

Комментарии:

1. Я понимаю, о чем вы говорите, и я бы так и сделал … НО мне нужно выделить хотя бы одну категорию для этого проекта.

2. Потрясающе, отлично сработало. Я не гуру sql и не разобрался бы в этом без вашей помощи. Спасибо!

Ответ №2:

Ответ немного зависит от того, что вы хотите.

Если вас интересует категория продукта только ради вопроса «есть ли у этого продукта хотя бы 1 активная категория?» Ваш запрос будет выглядеть следующим образом …

 SELECT      DISTINCT
            ProductItem.sku, 
            ProductItem.title, 
            ProductItem.short_desc, 
            ProductItem.long_desc, 
            ProductItem.active, 
            ProductItem.product_item_id, 
            ProductCategoryMap.product_id, 
            Product.adwords_label, 
            ProductItem.item_price, 
            ProductItem.sale_price
FROM      
            Product 
INNER JOIN  ProductCategoryMap   ON Product.product_id = ProductCategoryMap.product_id 
INNER JOIN  ProductCategory     ON ProductCategoryMap.product_category_id = ProductCategory.product_category_id 
FULL JOIN   ProductItem         ON Product.product_key = ProductItem.sku
WHERE      
            (ProductItem.active = 1) AND 
            (ProductCategory.active = 1)
  

Если вас вообще не волнует категория, это будет выглядеть так ….

 SELECT      
            ProductItem.sku, 
            ProductItem.title, 
            ProductItem.short_desc, 
            ProductItem.long_desc, 
            ProductItem.active, 
            ProductItem.product_item_id, 
            ProductCategoryMap.product_id, 
            Product.adwords_label, 
            ProductItem.item_price, 
            ProductItem.sale_price
FROM      
            Product 
INNER JOIN  ProductCategoryMap  ON Product.product_id = ProductCategoryMap.product_id 
ProductCategory.product_category_id 
FULL JOIN   ProductItem         ON Product.product_key = ProductItem.sku
WHERE      
            (ProductItem.active = 1) 
  

Если вы хотите включить названия активных категорий в виде списка CSV (просто учитывайте план выполнения, если это большой набор результатов)….

 SELECT      ProductItem.sku, 
            ProductItem.title, 
            ProductItem.short_desc, 
            ProductItem.long_desc, 
            ProductItem.active, 
            ProductItem.product_item_id, 
            ProductCategory.category_desc, 
            ProductCategoryMap.product_id, 
            ProductCategory.active AS activecat, 
            Product.adwords_label, 
            ProductItem.item_price, 
            ProductItem.sale_price,
            (SELECT substring((SELECT ( ', '   CAST(PC.category_desc AS varchar(50)))
                                FROM    ProductCategory PC
                                WHERE   PC.product_category_id =  ProductCategoryMap.product_category_id AND
                                        PC.active = 1
                                FOR XML PATH( '' )
                              ), 3, 8000 )  
                   )      AS    ProductCategoriesCSV
FROM      
            Product 
INNER JOIN  ProductCategoryMap  ON Product.product_id = ProductCategoryMap.product_id 
INNER JOIN  ProductCategory     ON ProductCategoryMap.product_category_id = ProductCategory.product_category_id 
FULL JOIN   ProductItem         ON Product.product_key = ProductItem.sku
WHERE      
            (ProductItem.active = 1) 
  

HTH,
-эрик

Ответ №3:

Попробуйте…

 SELECT      
  I.sku, 
  I.title, 
  I.short_desc, 
  I.long_desc, 
  I.active, 
  I.product_item_id, 
  T.category_desc, 
  P.product_id, 
  T.active AS activecat, 
  P.adwords_label, 
  I.item_price, 
  I.sale_price
FROM          
  Product P

  CROSS APPLY
  (
    SELECT TOP 1
      C.category_desc,
      C.active AS activecat
    FROM
      ProductCategoryMap CM 

      INNER JOIN ProductCategory C
      ON CM.product_category_id = C.product_category_id 
    WHERE
      P.product_id = CM.product_id
      AND 
     (C.active = 1)
  ) T

  FULL OUTER JOIN ProductItem I
  ON P.product_key = I.sku
WHERE 
 (I.active = 1)