SQL选择前1个唯一

时间:2012-08-21 19:22:12

标签: sql sql-server

我有一个SQL查询,希望你能帮我解决。

这应该很容易,我的头脑今天不生产。

以下是表格的示例

TblProducts

ID | SKU  | Price
-----------------
1  | ABC  | 10.00 
2  | DEF  | 5.00 
3  | OSKD | 6.00
4  | 123  | 6.00
5  | LPD  | 12.00
6  | TRE  | 3.00

TblCategories

ID | Name  | Active |Sort 
-------------------------
1  | Home  | 1      |4 
2  | Garden| 1      |55 
3  | Misc  | 1      |2
4  | Test  | 0      |1

TblAlternateCategoryName

ID | CategoryID | AltName
-------------------------
1  | 1          | House 
2  | 1          | Crib
3  | 3          | Anything

TblProductXCategories

ID | ProductID | CategoryID | SortOrder
---------------------------------------
1  | 1         | 1          | 1
2  | 1         | 2          | 1
4  | 2         | 2          | 4
5  | 2         | 3          | 6
6  | 3         | 3          | 6  
7  | 4         | 4          | 0 
8  | 5         | 2          | 1 

需要此结果

 SKU  | Price | Category | AlternateCategory
 -------------------------------------------
 ABC  | 10.00 | Home     | House 
 DEF  | 5.00  | Misc     | Anything
 OSKD | 6.00  | Misc     | Anything
 LPD  | 12.00 | Garden   | Null

规则

  1. 每件商品返回一个类别。 (最低排序)
  2. 产品必须处于活动类别。
  3. 如果可用但不要求使用AlternateCategory。
  4. 排序有时可能会重复。
  5. 提前致谢

    这是原始的SQL Statment

        DECLARE @feedID int =4
        SELECT Pro_Chl.id, 
           Pro_Chl.sku, 
           Pro_Chl.productname, 
           (SELECT top 1 tbl_componentsettinglist.componentsubtype 
                FROM   tbl_offers 
                   INNER JOIN tbl_componentsettinglist 
                           ON tbl_offers.id = tbl_componentsettinglist.componentid 
                WHERE  ( tbl_componentsettinglist.componentsubtype = N'Free Shipping' ) 
                   AND ( tbl_componentsettinglist.componenttype = N'Offer' ) 
                   AND ( tbl_offers.startdate <= { fn NOW() } ) 
                   AND ( tbl_offers.enddate > { fn NOW() } ) 
                   AND ( tbl_offers.enabled = 1 ) 
                   AND ( Pro_Chl.id = tbl_componentsettinglist.setting1 ) 
                ORDER  BY tbl_offers.[order]) AS FreeShipping, 
           TblCategories.name              AS CategoryName, 
           TblAlternateCategoryName.value     AS FeedCat 
        FROM   TblProducts AS Pro_Chl 
           INNER JOIN (
                                SELECT productid, 
                                          categoryid, 
                                          sortorder 
                                   FROM   TblProductXCategories main 
                                   WHERE  sortorder = (
                                                           SELECT top 1 Min(srt.sortorder) 
                                                           FROM   TblProductXCategories srt 
                                                                  INNER JOIN TblCategories 
                                                                          ON srt.categoryid = 
                                                                                 TblCategories.id 
                                                           WHERE  srt.productid = main.productid 
                                                                AND srt.categoryid = main.categoryid 
                                                                  AND TblCategories.hidden = 0
                                                   )
    
                        ) 
                         AS PxC
    
                   ON ( Pro_Chl.id = PxC.productid 
                         OR Pro_Chl.parentid = PxC.productid ) 
           INNER JOIN TblCategories 
                   ON PxC.categoryid = TblCategories.id 
           LEFT OUTER JOIN TblAlternateCategoryName 
                        ON PxC.categoryid = TblAlternateCategoryName.categoryid AND TblAlternateCategoryName.feedid = @feedID  
        WHERE  (
                         ( Pro_Chl.parentid = '' ) 
                         AND ( Pro_Chl.id NOT IN (SELECT parentid 
                                                FROM   TblProducts AS pc 
                                                WHERE  ( customproperties LIKE '%upc%' )) ) 
    
                         AND ( Pro_Chl.status = 1 ) 
                         AND ( Pro_Chl.manufacturerid IS NOT NULL ) 
                         AND ( Pro_Chl.manufacturerid <> '' ) 
                         AND ( Pro_Chl.manufacturerid <> '- No Manufacturer -' ) 
                         AND ( Pro_Chl.id NOT IN (SELECT productid 
                                                FROM   TblProductschoicecombinations 
                                                WHERE  available = 0) ) 
                         AND Pro_Chl.manufacturerid NOT IN ( 
                         'f46c9a25-8172-49a8-991a-a8219663453b' ) 
                ) 
                OR 
                (
                         ( Pro_Chl.parentid <> '' ) 
                 AND ( Pro_Chl.customproperties LIKE '%upc%' ) 
                 AND ( Pro_Chl.parentid IN (SELECT id 
                                                FROM   TblProducts AS cp 
                                                WHERE  ( status = 1 ) 
                                                   AND ( parentid = '' )) ) 
    
                 AND ( Pro_Chl.status = 1 ) 
                 AND ( Pro_Chl.manufacturerid IS NOT NULL ) 
                 AND ( Pro_Chl.manufacturerid <> '' ) 
                 AND ( Pro_Chl.manufacturerid <> '- No Manufacturer -' ) 
                 AND ( Pro_Chl.id NOT IN (SELECT productid 
                                                FROM   TblProductschoicecombinations 
                                                WHERE  available = 0) ) 
                 AND Pro_Chl.manufacturerid NOT IN ( 
                         'f46c9a25-8172-49a8-991a-a8219663453b' 
                                                   ) 
                  ) 
    

3 个答案:

答案 0 :(得分:2)

这是SQLFiddle demo。此查询选择带有min的类别(TblCategory.Sort)。如果您需要选择min类别(TblProductXCategories.SortOrder),只需将OVER语句中的 order by 列替换为TBlProductXCategories.SortOrder。它可以与重复的排序器一起使用

with t as 
(select TblProductXCategories.*,TblCategories.Name CatName,
 row_number() over (partition by ProductID order by TblCategories.Sort) rownum 
  from TblProductXCategories
   join TblCategories on  TblProductXCategories.CategoryId = TblCategories.id 
         and TblCategories.Active=1 
 )
select TblProducts.SKU,TblProducts.Price,t.CatName,

(select top 1 AltName from TblAlternateCategoryName 
   where TblAlternateCategoryName.CategoryId=t.CategoryId order by Id )
from t 
left join TblProducts on t.productid=TblProducts.id
where rownum=1

或没有WITH的等价物。 SQLFiddle

select TblProducts.SKU,TblProducts.Price,t.CatName,
(select top 1 AltName 
        from TblAlternateCategoryName 
        where TblAlternateCategoryName.CategoryId=t.CategoryId 
        order by Id ) AltCat

from

(select TblProductXCategories.*,
        TblCategories.Name CatName,
        row_number() 
         over (partition by ProductID order by TblCategories.Sort) rownum 
 from TblProductXCategories
 join TblCategories  on  TblProductXCategories.CategoryId = TblCategories.id 
       and TblCategories.Active=1 
) t

left join TblProducts on t.productid=TblProducts.id
where rownum=1

答案 1 :(得分:1)

根据您的示例数据,您将获得Alternate Category的两个结果,因为Home类别有两个备用项,因此最终结果为5行而不是您要求的两行。但是下面的查询应该为您提供所需的结果:

select x1.sku, x1.price, c.name, ac.altname
from
(
  select x.sku, p.price, x.sort
  from 
  (
    select p.sku, min(c.sort) sort
    from products p
    left join  ProductXCategories pxc
      on p.id = pxc.productid
    left join Categories c
      on pxc.categoryid = c.id
    group by p.sku
  ) x
  inner join products p
    on x.sku = p.sku
) x1
inner join categories c
  on x1.sort = c.sort
left join AlternateCategoryName ac
  on c.id = ac.categoryid
where c.active = 1

请参阅SQL Fiddle with Demo

编辑:如果您希望将备用类别合并为一列:

select distinct x1.sku,
  x1.price,
  c.name,
  STUFF((SELECT ',' + ac.altname
          FROM AlternateCategoryName ac
          WHERE
            c.id = ac.categoryid
          FOR XML PATH('') 
        ),1,1,'') altname
from
(
  select x.sku,
    p.price,
    x.sort
  from 
  (
    select p.sku,
      min(c.sort) sort
    from products p
    left join  ProductXCategories pxc
      on p.id = pxc.productid
    left join Categories c
      on pxc.categoryid = c.id
    group by p.sku
  ) x
  inner join products p
    on x.sku = p.sku
) x1
inner join categories c
  on x1.sort = c.sort
left join AlternateCategoryName ac
  on c.id = ac.categoryid
where c.active = 1

请参阅SQL Fiddle with Demo

编辑#2:您声明只需要一个备用分类。您需要确定所需的alt名称的条件,但以下内容将选择max(altname)

select x1.sku,
  x1.price,
  c.name,
  ac.altname
from
(
  select x.sku,
    p.price,
    x.sort
  from 
  (
    select p.sku,
      min(c.sort) sort
    from products p
    left join  ProductXCategories pxc
      on p.id = pxc.productid
    left join Categories c
      on pxc.categoryid = c.id
    group by p.sku
  ) x
  inner join products p
    on x.sku = p.sku
) x1
left join categories c
  on x1.sort = c.sort
left join
(
  select categoryid, max(altname) altname
  from AlternateCategoryName
  group by categoryid
) ac
  on c.id = ac.categoryid
where c.active = 1

请参阅SQL Fiddle with Demo

答案 2 :(得分:0)

以下查询忽略了替代类别(您说它不是必需的)。并且,它假定类别中的排序值没有重复:

select SKU, price, c.name
from (select P.SKU, p.price, 
             MIN(p.sort) as minsort
      from tblProducts p join
           tblProductXCategories pxc
           on p.id = pxc.productid join
           tblCategory c
           on pxc.categoryid = c.categoryid and
              active = 1
      group by P.SKU, p.price
     ) p join
     tblCategories c
     on p.minsort = c.sort

它将所有内容连接在一起,计算minsort,然后加入类别信息。

如果您在排序中有重复项,则可以通过以下方式选择其中一个来解决问题:

select SKU, price, c.name
from (select P.SKU, p.price, 
             MIN(p.sort) as minsort
      from tblProducts p join
           tblProductXCategories pxc
           on p.id = pxc.productid join
           tblCategory c
           on pxc.categoryid = c.categoryid and
              active = 1
      group by P.SKU, p.price
     ) p join
     (select c.*,
             row_number() over (partition by sort order by newid()) as seqnum
      from tblCategories c
     ) c
     on p.minsort = c.sort and
        c.seqnum = 1

这会输入一个随机序列号,然后选择第一个序列号。当有关系时,应该从选项中做出相同的选择。