2014-07-08 61 views
1

我有數據的表看起來像這樣:SQL Server組

product_id | filter_id 
    __________________ 
     4525 5066 
     4525 5068 
     4525 5091 
     4526 5066 
     4526 5068 
     4526 5094 
     4527 5066 
     4527 5068 
     4527 5094 
     4528 5066 
     4528 5071 
     4528 5078 

其爲三個過濾器actualy組爲每個產品例如產品4525具有過濾器5066,5068和5091.第二組和第三組是與不同產品(4526和4527)綁定的完全相同的一組過濾器(5066,5068和5094)。

我想每個唯一的過濾器設置只有一次(換句話說,我想刪除重複的filter_ids集)。我並不關心product_id會發生什麼情況,我只希望我的三個filter_id的唯一集合與一個鍵組合在一起。

例如這也將做到:

new_id | filter_id 
    __________________ 
     1 5066 
     1 5068 
     1 5091 
     2 5066 
     2 5068 
     2 5094 
     3 5066 
     3 5071 
     3 5078 

我希望我解釋的不夠好。

謝謝。

+0

你可以檢查下面的查詢... – Azar

+0

在測試案例中,你有4個不同的產品ID,是預期的結果是否正確或應該有另一組過濾器new_id 4? – Serpiton

+0

@Serpiton在我的情況下,它不會超過3個,因爲這是我使用的過濾器的數量。但可能會更多。我還注意到可能會出現較少的過濾器組。 – xpy

回答

0
Select dense_rank() 
over(order by product_id asc),filter_id 
from table 
+0

它不會產生所需的結果,即使我更改列,它也有一個語法錯誤(第一個'asc')但這並不重要... – xpy

+0

我很抱歉刪除分區並嘗試 – Azar

+0

它只是替換帶有新ID的product_id,結果我有和以前一樣的結果集,沒有刪除重複項。 – xpy

1

請嘗試下面的查詢,這比我預期的要長一點。截至目前沒有得到任何其他邏輯!

select 
    distinct filter_id, 
    DENSE_RANK() over(order by sc) new_id 
from(
    select *, 
     (SELECT ' ' + cast(filter_id as nvarchar(10)) 
      FROM tbl b where b.product_id=a.product_id order by filter_id 
      FOR XML PATH('')) SC 
    From tbl a 
)x 
order by new_id 

/--------------另一種方式------------------/

SELECT 
    DENSE_RANK() OVER (ORDER BY PRODUCT_ID) new_id, 
    filter_id 
FROM 
    Table1 
WHERE product_id in (
    SELECT MIN(product_id) FROM(
     SELECT 
      product_id, 
      SUM(filter_id*RN) OVER (PARTITION BY PRODUCT_ID) SM 
     FROM(
      SELECT 
       *, 
       ROW_NUMBER() OVER (PARTITION BY product_id ORDER BY filter_id) RN 
      FROM Table1 
     )x 
    )xx GROUP BY SM) 
+0

這似乎工作,但我必須採取更緊密的戰利品結果,以確保...謝謝。 – xpy

+0

@xpy,請檢查編輯的答案... – TechDo

+1

這工作得很好!謝謝!這個方法非常酷,我想出了一些類似的東西,可能會稍微快一點。我只需要運行一些更多的測試。 – xpy

0

如果我對這個問題理解的很好,預期的結果只有產品4525,4526和4528的filter_id,因爲4526和4527具有相同的filter_id,所以只需要其中的一個,在這種情況下,該查詢將執行:

SELECT product_id 
    , dense_rank() OVER (ORDER BY PRODUCT_ID) new_id 
    , filter_id 
FROM table1 c 
WHERE NOT EXISTS (SELECT 1 
        FROM table1 a 
          LEFT JOIN table1 b ON a.product_id < b.product_id 
        WHERE b.product_id = c.product_id 
        GROUP BY a.product_id, b.product_id 
        HAVING COUNT(DISTINCT a.filter_id) 
         = COUNT(CASE WHEN a.filter_id = b.filter_id THEN 1 
            ELSE NULL 
           END)); 

SQLFiddle demo

要獲得結果,第一步是使用完整的filter_ID重複列表刪除產品。爲了獲得這些產品,子查詢將檢查每個產品對,以查看一箇中的filter_id數是否等於該對夫婦共享的filter_id。

如果你可以有不同數量的過濾器,如果與完全包含在其他產品的過濾器列表過濾器列表的產品應該從結果中移除的產品,例如,如果與基礎數據

product_id | filter_id 
-----------+---------- 
     4525 |  5066 
     4525 |  5068 
     4525 |  5091 
     4526 |  5066 
     4526 |  5068 

預期的結果是

new_id | filter_id 
-------+---------- 
    1 |  5066 
    1 |  5068 
    1 |  5091 

查詢需要改爲

SELECT product_id 
    , dense_rank() OVER (ORDER BY PRODUCT_ID) new_id 
    , filter_id 
FROM table1 c 
WHERE NOT EXISTS (SELECT b.product_id 
        FROM table1 a 
          LEFT JOIN table1 b ON a.product_id < b.product_id 
        WHERE b.product_id IS NOT NULL 
        AND b.product_id = c.product_id 
        GROUP BY a.product_id, b.product_id 
        HAVING COUNT(DISTINCT a.filter_id) 
         = COUNT(CASE WHEN a.filter_id = b.filter_id THEN 1 
            ELSE NULL 
           END) 
         OR COUNT(DISTINCT b.filter_id) 
         = COUNT(CASE WHEN a.filter_id = b.filter_id THEN 1 
            ELSE NULL 
           END)); 

SQLFiddle Demo


我想出了神似TechDo的第二個,在他之後經過九年小時查詢。即使結果是相似的,因爲想法不同的是,我的想法是用數學來Concat的過濾器_id值

;WITH B AS (
    SELECT Product_ID 
     , filter_id = filter_id - MIN(filter_id) OVER (PARTITION BY NULL) 
     , _ID = Row_Number() OVER (PARTITION BY Product_ID ORDER BY filter_id) - 1 
     , N = CEILING(LOG10(MAX(filter_id) OVER (PARTITION BY NULL) 
         - MIN(filter_id) OVER (PARTITION BY NULL))) 
    FROM table1 a 
), G1 AS (
    SELECT Product_ID 
     , _ID = SUM(Filter_ID * POWER(10, N * _ID)) 
    FROM B 
    GROUP BY Product_ID 
), G2 AS (
    SELECT Product_ID = MIN(Product_ID) 
    FROM G1 
    GROUP BY _ID 
) 
SELECT g2.product_id 
    , dense_rank() OVER (ORDER BY g2.PRODUCT_ID) new_id 
    , a.filter_id 
FROM G2 
     INNER JOIN table1 a ON g2.product_id = a.product_id; 

SQLFiddle demo

第一CTE做了很多工作:

  • filter_id的等級降低(根據數據的範圍從0減少到n-1個數字)
  • 屬於泰德以便在產品中過濾器上的順序號(_ID
  • 計算最大數量的減少過濾器_id的數字(N

在以下CTE這些值被用來使用來產生濾波器級聯SUM,公式SUM(Filter_ID * POWER(10, N * _ID))在每N個位置放置一個減少的filter_id,例如用OP提供的數據我們已經知道filter_id的最大差值是28,所以N是2並且結果是(爲了可讀性而添加的點)

Product_ID _ID 
----------- ----------- 
4525  25.02.00 
4526  28.02.00 
4527  28.02.00 
4528  12.05.00 

使用的公式使不同過濾器組之間的碰撞不可能,但需要較大的空間進行計算,如果filter_id的範圍很大,則可以達到極限。

+0

這工作得很好,但當表格超過100行時,至少與我的服務器相比,它會變得非常慢。它爲100行做了大約150ms,爲200行做了1.5s。不錯的做法。 – xpy

+0

雖然我沒有想到,但它仍然不夠好,200行下降到400毫秒,300行下降到300毫秒...... @ TechDo的方法對於300行的值爲50毫秒。 – xpy

+0

我不喜歡字符串操作,所以我嘗試了一個稍微不同的方法,看起來一樣快。儘管如此,我還得做一些研究。而且我也在工作,所以對我來說也可能是「以後」。 – xpy