0

我有一个 SQL 查询,希望你能帮我弄清楚。

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

这是表格的示例

Tbl产品

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

TblProductX类别

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. 排序有时可能是重复的。

提前致谢

这是原始的 SQL 语句

    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' 
                                               ) 
              ) 
4

3 回答 3

2

这是一个SQLFiddle 演示。此查询选择具有 min(TblCategory.Sort) 的类别。如果您需要使用 min(TblProductXCategories.SortOrder) 选择类别,只需将OVER 语句中的按列顺序替换为 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
于 2012-08-21T20:09:30.860 回答
1

Based on your sample data you will get two results for the Alternate Category since the Home category has two alternates, so the final results in 5 rows instead of the two you asked for. But the below query should give you the results you want:

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

See SQL Fiddle with Demo

Edit: if you want the Alternate Categories to be combined in one column:

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

See SQL Fiddle with Demo

Edit #2: you stated that you only want one alternate categor., You need to decide the criteria of which alt name you want but the following will select the 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

See SQL Fiddle with Demo

于 2012-08-21T19:49:57.570 回答
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

它将所有内容连接在一起,计算最小排序,然后连接回类别信息。

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

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

这会输入一个随机序列号,然后选择第一个。当有关系时,它应该从大约相等的选项中进行选择。

于 2012-08-21T19:37:37.170 回答