0

Iv'e got a SQL query that I hope you can help me figure out.

This should be easy, My head is just not producing today.

Here is a sample of the tables

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 

need this result

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

Rules

  1. Return one category per product. (lowest sort)
  2. Product Must be in active category.
  3. Use AlternateCategory if available but not required.
  4. sort could sometimes be duplicate.

Thanks in advance

Here is the original 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' 
                                               ) 
              ) 
4

3 に答える 3

2

これがSQLFiddleのデモです。このクエリは、min(TblCategory.Sort)でカテゴリを選択します。min(TblProductXCategories.SortOrder)でカテゴリを選択する必要がある場合は、OVERステートメントtoTblProductXCategories.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

The following query ignores the alternative category (you say it is not required). And, it assumes that the sort values in the categories have no duplicates:

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

It joins everything together, calculates the minsort, and then joins back the category information.

If you have duplicates in sort, you can solve the problem by choosing just one of them this way:

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

This puts in a random sequence number, and then chooses the first one. When there are ties, it should choose from among the options about equally.

于 2012-08-21T19:37:37.170 に答える