简体   繁体   English

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

[英]SQL select MAX to find single record of a group

I have many records that represent the same information, but with different keys to other tables. 我有很多记录代表相同的信息,但是其他表的键不同。 I need to group these records by their common attributes (Att1, Att2, Att3), then select a single RecordID of all the common records to be the masterID for those common records. 我需要按它们的公共属性(Att1,Att2,Att3)对这些记录进行分组,然后从所有公共记录中选择一个RecordID作为这些公共记录的masterID。 That masterID needs to be added to each record that it represents, only if the masterID is null. 仅当masterID为null时,才需要将该masterID添加到它表示的每个记录中。 I cannot change the data structure and all table values are GUID. 我无法更改数据结构,并且所有表值都是GUID。 I have tried MAX, but I dont get the grouping. 我尝试过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

UPDATE: Added expected result. 更新:添加了预期的结果。

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

Yuck, I dislike this setup. uck,我不喜欢这种设置。 You're violating good normalization practices, and there's some inherent assumptions that require 'outside' knowledge. 您违反了良好的规范化实践,并且有一些固有的假设需要“外部”知识。 However, you've said you can't change it so... 但是,您说过不能更改它...

I believe the following should work (vendor neutral): 我认为以下方法应该有效(供应商中立):

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


EDIT: 编辑:

Upon the revelation that GUIDs can be ordered, but cannot be passed for MIN() or MAX() (What?) - 得知可以排序GUID,但不能为MIN()MAX()传递GUID(什么?)-

You have (at least) three options: 您至少有三个选择:

  1. Cast the guid to a passable type (ie - SELECT MIN(CAST(b.recordId as CHAR(36))) ). 将GUID强制转换为可传递的类型(即SELECT MIN(CAST(b.recordId as CHAR(36))) )。 However, this is likely to be poor performing, simply because it's going to cast every row (see, this is why it's preferrable for internal ids to be simple integers). 但是,这可能表现不佳,仅是因为它将强制转换每一行(请参阅这就是为什么内部ID最好是简单整数的原因)。
  2. Attempt this vendor-neutral statement: 尝试以下与供应商无关的声明:

     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. There's also this more idiomatic version for SQL Server: 对于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 SQL Fiddle示例

Try this: 尝试这个:

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

If you want to select only then you can use the following query - 如果只想选择,则可以使用以下查询-

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

You could use a cross apply to make a selection. 您可以使用交叉申请进行选择。 The cross apply basically selects the lowest RecordID that has matching Att1, Att2, and Att3 and joins the RecordID as a column named MasteRID. 交叉应用基本上选择具有匹配的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

The update will update each RecordID entry's MasterID column with the appropriate RecordID. 此更新将使用适当的RecordID更新每个RecordID条目的MasterID列。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM