在SQL Server中,如何对表中的匹配数据集进行编号?

时间:2018-04-25 20:03:43

标签: sql sql-server tsql

鉴于下面显示的数据集,我需要能够根据optionGroupNumber&中的值,在右侧的optionType中得出值。 optionValue列。因此,对于订单1,为细节键1和1选择的选项。 2是相同的(绿色阴影),因此它们得到optionGroup值1.细节键3(蓝色阴影)具有与1& 1不同的选项集。 2,因此它optionGroupNumber得到2。

Optionvalues由用户任意输入,因此它们可以是任何内容。

如何使用T-SQL完成?

enter image description here

3 个答案:

答案 0 :(得分:1)

要求很难理解,所以我的答案基于此:

  

鉴于下面显示的数据集,我需要能够推导出   右侧的optionGroupNumber中的值,基于值中的值   optionType& optionValue columns。

假设我们有一张动物和颜色的桌子,我们想要根据相同类型和颜色的动物创建一个组号。我们会这样使用RANK():

-- sample data
DECLARE @sometable TABLE (someId int identity, pet varchar(20), color varchar(20));
INSERT @sometable (pet, color)
VALUES ('cat','blue'),('pig','green'),('cat','yellow'),('pig','green'),('cat','yellow'),
('cat','blue'),('dog','black'),('dog','white'),('pig','green'),('dog','black');

-- group by pet and color
SELECT *, OptionGroupNumber = DENSE_RANK() OVER (ORDER BY pet, color)
FROM @sometable;

结果:

someId      pet                  color                OptionGroupNumber
----------- -------------------- -------------------- --------------------
1           cat                  blue                 1
6           cat                  blue                 1
3           cat                  yellow               2
5           cat                  yellow               2
10          dog                  black                3
7           dog                  black                3
8           dog                  white                4
9           pig                  green                5
4           pig                  green                5
2           pig                  green                5

请注意分组的工作原理:

enter image description here

要更新和现有列,您将采用此逻辑并将其应用于UPDATE语句,如下所示:

-- sample data
DECLARE @sometable TABLE 
  (someId int identity, pet varchar(20), color varchar(20), OptionGroupNumber int);

INSERT @sometable (pet, color)
VALUES ('cat','blue'),('pig','green'),('cat','yellow'),('pig','green'),('cat','yellow'),
('cat','blue'),('dog','black'),('dog','white'),('pig','green'),('dog','black');

WITH generateOptionGroupNumber AS
(
  SELECT *, newOptionGroupNumber = DENSE_RANK() OVER (ORDER BY pet, color)
  FROM @sometable
)
UPDATE generateOptionGroupNumber
SET OptionGroupNumber = newOptionGroupNumber

SELECT * 
FROM @sometable
ORDER BY OptionGroupNumber;

答案 1 :(得分:0)

尝试此查询...

WITH cte (detailkey, alloptionvalues) 
     AS (SELECT detailkey, 
                allOptionValues = Stuff((SELECT N', ' + optionvalue 
                                         FROM   tablename AS subTbl 
                                         WHERE  subTbl.detailkey = mainTbl.detailkey 
                                         FOR xml path(N'')), 1, 2, N'') 
         FROM   tablename AS mainTbl 
         GROUP  BY detailkey) 

SELECT tablename.orderno, 
       tablename.detailkey, 
       tablename.style, 
       tablename.[format], 
       tablename.leather, 
       tablename.optiontype, 
       tablename.optionvalue, 
       tablename.optionadditionalinfo, 
       tmpQueryTbl.optionGroupNumber 
FROM   tablename 
       INNER JOIN (SELECT *, 
                          Dense_rank() OVER(ORDER BY alloptionvalues) AS optionGroupNumber 
                   FROM   cte) tmpQueryTbl 
               ON tablename.detailkey = tmpQueryTbl.detailkey 

结果

+---------+-----------+-------+--------+---------+-----------------------------------+-------------+----------------------+-------------------+
| orderno | detailkey | style | format | leather |            optiontype             | optionvalue | optionadditionalinfo | optionGroupNumber |
+---------+-----------+-------+--------+---------+-----------------------------------+-------------+----------------------+-------------------+
|       1 |         1 | WJ7   | MRBL   | PYT     | ADDITIONAL STAMPING               | BLIND       | NULL                 |                 1 |
|       1 |         1 | WJ7   | MRBL   | PYT     | ADDITIONAL STAMPING FOIL          | BLIND       | NULL                 |                 1 |
|       1 |         1 | WJ7   | MRBL   | PYT     | ADDITIONAL STAMPING FOIL POSITION | BLC         | NULL                 |                 1 |
|       1 |         1 | WJ7   | MRBL   | PYT     | ETA FOR MATERIALS                 | 4/25/2018   | NULL                 |                 1 |
|       1 |         2 | WJ7   | MRBL   | PYT     | ADDITIONAL STAMPING               | BLIND       | NULL                 |                 1 |
|       1 |         2 | WJ7   | MRBL   | PYT     | ADDITIONAL STAMPING FOIL          | BLIND       | NULL                 |                 1 |
|       1 |         2 | WJ7   | MRBL   | PYT     | ADDITIONAL STAMPING FOIL POSITION | BLC         | NULL                 |                 1 |
|       1 |         2 | WJ7   | MRBL   | PYT     | ETA FOR MATERIALS                 | 4/25/2018   | NULL                 |                 1 |
|       1 |         3 | WJ7   | MRBL   | PYT     | ADDITIONAL STAMPING               | SILVER      | NULL                 |                 2 |
|       1 |         3 | WJ7   | MRBL   | PYT     | ADDITIONAL STAMPING FOIL          | SILVER      | NULL                 |                 2 |
|       1 |         3 | WJ7   | MRBL   | PYT     | ADDITIONAL STAMPING FOIL POSITION | FLR         | NULL                 |                 2 |
|       1 |         3 | WJ7   | MRBL   | PYT     | ETA FOR MATERIALS                 | 4/25/2018   | NULL                 |                 2 |
+---------+-----------+-------+--------+---------+-----------------------------------+-------------+----------------------+-------------------+

演示:http://sqlfiddle.com/#!18/0b419/1/0

要更新数据,请使用此SQL查询

WITH cte (detailkey, alloptionvalues) 
     AS (SELECT detailkey, 
                allOptionValues = Stuff((SELECT N', ' + optionvalue 
                                         FROM   tablename AS subTbl 
                                         WHERE  subTbl.detailkey = mainTbl.detailkey 
                                         FOR xml path(N'')), 1, 2, N'') 
         FROM   tablename AS mainTbl 
         GROUP  BY detailkey) 

UPDATE tablename 
SET    tablename.optiongroupnumber = resultSet.optiongroupnumber 

FROM   (SELECT tablename.orderno, 
               tablename.detailkey, 
               tablename.style, 
               tablename.[format], 
               tablename.leather, 
               tablename.optiontype, 
               tablename.optionvalue, 
               tablename.optionadditionalinfo, 
               tmpQueryTbl.optiongroupnumber 
        FROM   tablename 
               INNER JOIN (SELECT *, 
                                  Dense_rank() 
                                    OVER( 
                                      ORDER BY alloptionvalues) AS 
                                  optionGroupNumber 
                           FROM   cte) tmpQueryTbl 
                       ON tablename.detailkey = tmpQueryTbl.detailkey) resultSet 
-- use where with PK columns  
WHERE  tablename.orderno = resultSet.orderno 
       AND tablename.detailkey = resultSet.detailkey 
       AND tablename.optiontype = resultSet.optiontype 
       AND tablename.optionvalue = resultSet.optionvalue 
       AND tablename.style = resultSet.style 
       AND tablename.[format] = resultSet.[format] 
       AND tablename.leather = resultSet.leather 

答案 2 :(得分:0)

我不知道这会有多高效。它似乎可以处理少量的测试数据。

with X as (
    select
        orderNo, detailKey, optionType, optionValue,
        count(*) over (partition by orderNo, detailKey) as optionCnt,
        dense_rank() over (partition by orderNo order by optionType, optionValue) as tag
    from O
), Y as (
    select
        coalesce(x1.orderNo, x2.orderNo) as orderNo,
        x1.detailKey as detailKey1, x2.detailKey as detailKey2,
        row_number() over (partition by coalesce(x1.orderNo, x2.orderNo) 
                           order by x1.detailKey, x2.detailKey) as rnk
    from X x1 full outer join X x2
        on x2.orderNo = x1.orderNo and x2.detailKey > x1.detailKey and x2.tag = x1.tag
    group by coalesce(x1.orderNo, x2.orderNo), x1.detailKey, x2.detailKey
    having count(x1.orderNo) = min(x1.optionCnt) and count(x2.orderNo) = min(x2.optionCnt)
), Z as (
    select orderNo, detailKey,
        coalesce('Merge with ' + cast(mergeKey as varchar(4)), 'Cannot merge') as note,
        dense_rank() over (partition by orderNo
                           order by coalesce(mergeKey, detailKey)) as optionGroupNumber
    from
        (select distinct orderNo, detailKey from O) o
        outer apply (
            select min(y.detailKey1) as mergeKey from Y y
            where y.orderNo = o.orderNo and o.detailKey in (y.detailKey1, y.detailKey2)
        ) as m
)
select * from Z;

以下是一个快速概述:

  1. 获取每detailKey个选项的数量。为每对选项设置编号。
  2. 加入选项集,看看它们是否完全匹配。
  3. 将一组匹配减少到一个规范的代表。
  4. http://rextester.com/GEUD41256