SQL选择MAX查找组的单个记录

时间:2012-03-21 16:03:53

标签: sql sql-server-2008

我有许多记录代表相同的信息,但与其他表的键不同。我需要按照它们的公共属性(Att1,Att2,Att3)对这些记录进行分组,然后选择所有公共记录的单个RecordID作为这些公共记录的masterID。仅当masterID为null时,才需要将masterID添加到它所代表的每个记录中。我无法更改数据结构,所有表值都是GUID。我试过MAX,但是我没有得到分组。

TableA (Current State)

RecordID          Att1         Att2     Att3     MasterID
1                 A            B        C        
2                 A            B        C
3                 A            B        C
4                 D            E        F
5                 D            E        F
6                 D            E        F
7                 G            H        I         7
8                 G            H        I         7
9                 G            H        I         7

更新:添加了预期结果。

TableA (Expected Result)

RecordID          Att1         Att2     Att3     MasterID
1                 A            B        C        1
2                 A            B        C        1
3                 A            B        C        1
4                 D            E        F        4
5                 D            E        F        4
6                 D            E        F        4
7                 G            H        I        7
8                 G            H        I        7
9                 G            H        I        7

4 个答案:

答案 0 :(得分:3)

哎呀,我不喜欢这个设置。你违反了良好的规范化实践,并且存在一些需要“外部”知识的固有假设。但是,你已经说过你不能改变它......

我相信以下内容应该有效(供应商中立):

UPDATE TableA as a SET masterId = (SELECT MIN(b.recordId) 
                                   FROM TableA as b
                                   WHERE b.att1 = a.att1
                                   AND b.att2 = a.att2
                                   AND b.att3 = a.att3)
WHERE masterId IS NULL

<小时/> 编辑:

一旦发现可以订购GUID,但无法传递MIN()MAX()(什么?) -

你有(至少)三个选择:

  1. 将guid转换为可传递类型(即 - SELECT MIN(CAST(b.recordId as CHAR(36))))。但是,这很可能表现不佳,仅仅是因为它会抛出每一行(参见,这就是为什么内部ID最好是简单的整数)。
  2. 尝试此供应商中立声明:

    UPDATE TableA as a SET masterId = (SELECT b.recordId
                                       FROM TableA as b
                                       LEFT JOIN TableA as c
                                       ON c.att1 = b.att1
                                       AND c.att2 = b.att2
                                       AND c.att3 = b.att3
                                       AND c.recordId < b.recordId
                                       WHERE b.att1 = a.att1
                                       AND b.att2 = a.att2
                                       AND b.att3 = a.att3
                                       AND b.recordId <= a.recordId
                                       AND c.recordId IS NULL)
    WHERE masterId IS NULL
    
  3. SQL Server还有这个更惯用的版本:

    UPDATE Updating
    SET Updating.masterId = Origin.recordId
    FROM TableA Updating
    JOIN (TableA Origin
          LEFT JOIN TableA Exclusion
                 ON Exclusion.att1 = Origin.att1
                    AND Exclusion.att2 = Origin.att2
                    AND Exclusion.att3 = Origin.att3
                    AND Exclusion.recordId < Origin.recordId) 
      ON Exclusion.recordId IS NULL
         AND Origin.att1 = Updating.att1
         AND Origin.att2 = Updating.att2
         AND Origin.att3 = Updating.att3
    WHERE Updating.masterId IS NULL
    

    SQL Fiddle example

答案 1 :(得分:1)

试试这个:

UPDATE m
SET
    MasterID = s.RecordID
FROM TableA AS m
INNER JOIN (
    SELECT Att1, Att2, Att3, MIN(RecordID) AS RecordID          
    FROM TableA 
    GROUP BY Att1, Att2, Att3
) AS s
    ON m.Att1 = s.Att1 AND m.Att2 = s.Att2 AND m.Att3 = s.Att3
WHERE
    MasterID  IS NULL

答案 2 :(得分:1)

如果您只想选择,则可以使用以下查询 -

select recordid ,
       Att1,
       Att2,
       Att3,
       COALESCE( MasterID , (select min(a2.recordid) from tableA a2
                            where a2.Att1 = a1.Att1
                            and a2.Att2= a1.Att2
                            and a1.Att3 = a2.Att3))
from TableA a1

答案 3 :(得分:0)

您可以使用交叉申请进行选择。 cross apply基本上选择匹配Att1,Att2和Att3的最低RecordID,并将RecordID作为名为MasteRID的列加入。

WITH temp as (SELECT RecordID, Att1, Att2, Att3, c.MasterID FROM dbo.TableA b
    CROSS APPLY (SELECT TOP 1 RecordID as MasterID 
    FROM dbo.TableA a 
    WHERE a.Att1=b.Att1 
    AND a.Att2=b.Att2 AND a.Att3=b.Att3 
    ORDER BY RecordID) c)

UPDATE TableA 
SET MasterID=t.MasterID
FROM temp t
WHERE RecordID=t.RecordID

更新将使用适当的RecordID更新每个RecordID条目的MasterID列。