SQL Server组按结果集

时间:2014-07-08 12:22:57

标签: sql sql-server grouping

我有一个表格,其数据如下所示:

   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

对于每种产品实际上是三个过滤器的组,例如product 4525有过滤器5066,5068和5091.

第二组和第三组是与不同产品(4526和4527)绑定的完全相同的过滤器组(5066,5068和5094)。

我想让每个唯一的过滤器集只有一次(换句话说,我想删除重复的filter_ids集)。我真的不在乎product_id会发生什么,我只希望我的三个filter_ids的唯一集合与一个键组合在一起。

例如,这也将:

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

我希望我解释得很好。

谢谢。

3 个答案:

答案 0 :(得分: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)

答案 1 :(得分:0)

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

答案 2 :(得分:0)

如果我理解这个问题,预期结果只有产品4525,4526和4528的filter_id,因为4526和4527具有相同的filter_id,因此只需要其中一个,在这种情况下,此查询将执行:< / p>

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的第二个相似的查询,在他之后9个小时。即使结果相似,但由于想法不同,我的想法是将filter_id的值与math连接

;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
  • 中的过滤器生成订单号
  • 计算缩小的filter_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的范围很大,它可以达到整数的限制。