2012-03-21 54 views
0

我有许多记录表示相同的信息,但与其他表的键不同。我需要按照它们的通用属性(Att1,Att2,Att3)对这些记录进行分组,然后选择所有通用记录的单个RecordID作为这些通用记录的主ID。只有当masterID为空时,该masterID才需要添加到它所代表的每个记录中。我无法更改数据结构,并且所有表值都是GUID。我试过MAX,但我没有得到分组。SQL select 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 
+1

这是您当前的数据还是您的预期结果?如果是前者,你能提供一个预期结果的例子吗? – 2012-03-21 16:07:08

+0

您是否试图进行查询以更新MasterID列或预期的结果是选择语句的结果? – ImGreg 2012-03-21 16:18:39

+0

@MostyMostacho抱歉。我已经添加了预期的结果。 – sreeli 2012-03-21 16:19:28

回答

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 
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

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

我认为以下应工作(厂商中立):

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

+0

如果你改正c.att3到b.att3,那么这个工作正常;-) – 2012-03-21 16:28:07

+0

@JanDoggen - D'oh!谢谢。 – 2012-03-21 16:29:28

+0

@ X-Zero Yuck是对的。我继承了这一点,并在我的头上。 recordid是一个guid,所以min不起作用。 – sreeli 2012-03-21 16:54:57

0

你可以使用交叉申请做出选择上。交叉应用基本上选择具有匹配的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列。

+0

感谢您的更新。 SQL不喜欢FROM temp temp,它是指向SET。 – sreeli 2012-03-21 16:57:07

+0

Woops,那是倒退@sreeli。谢谢。请参阅编辑。 – ImGreg 2012-03-21 17:45:02

相关问题