【问题标题】:How to update one row that has max value in column (SQL Server)如何更新列中具有最大值的一行(SQL Server)
【发布时间】:2021-06-19 05:36:31
【问题描述】:

我正在尝试使用 Text1 列中的“是”值更新具有最高分数的行。

这很简单,除非有多行具有最高分数。

如果他们的分数相同,我只想选择顶行以具有值“是”。只有具有相同供应商 ID 的一行应具有“是”值。

    UPDATE Suppliers
        SET Text1='Yes'
        --SELECT DISTINCT *
        FROM Suppliers INNER JOIN
            (
            SELECT Vendor, MAX(VCScore) as MaxVCScore
            FROM Suppliers 
            GROUP BY Vendor
            ) maxTable
        ON Suppliers.Vendor=maxTable.Vendor
        AND Suppliers.VCScore=maxTable.MaxVCScore

我不想使用 TOP 1,因为这只会更新整个表中的一行。相反,我希望每个供应商只更新一行。 (供应商可以是相同的,这是我要解决的问题。)我无法在 Update 语句中添加 Group By 子句,因为我想按供应商分组,但这是不正确的语法。

【问题讨论】:

    标签: sql sql-server


    【解决方案1】:
    with t as (
    select * , row_number() over (partition by Vendor order by VCScore desc) rn
    from Suppliers
    )
    
    update s
    set Text1 = 'Yes'
    from supplier s
    join t on s.pkey = t.pkey and t.rn = 1  
    

    【讨论】:

    • 谢谢!我之前尝试过 Row_Number,但我试图在 Over 子句中使用 Group By 而不是 Partition By。
    【解决方案2】:

    这是您可以使用公用表表达式 (CTE) 解决此问题的一种方法。以下可能会在 SSMS 中运行:

    DECLARE @Suppliers table ( Vendor varchar(20), VCScore int, Text1 varchar(3), SupplierPK int IDENTITY (1,1) );
    INSERT INTO @Suppliers ( Vendor, VCScore ) VALUES
        ( 'Vendor1', 85 ), ( 'Vendor1', 85 ), ( 'Vendor1', 85 ), ( 'Vendor2', 65 ), ( 'Vendor2', 65 );
    
    DECLARE @Vendor table ( Vendor varchar(20), VCScore int );
    INSERT INTO @Vendor VALUES
        ( 'Vendor1', 85 ), ( 'Vendor1', 25 ), ( 'Vendor1', 45 ), ( 'Vendor2', 45 ), ( 'Vendor2', 65 );
    
    WITH cte AS (
    
        SELECT
            Vendor,
            Text1,
            SupplierPK,
            ROW_NUMBER() OVER ( PARTITION BY Vendor ORDER BY SupplierPK ) AS RowNo
        FROM @Suppliers AS s
        OUTER APPLY (
            SELECT MAX ( VCScore ) AS MaxVCScore FROM @Vendor AS v WHERE v.Vendor = s.Vendor 
        ) AS x
        WHERE
            s.VCScore = x.MaxVCScore
    
    )
    UPDATE cte
    SET
        Text1 = 'Yes'
    WHERE
        cte.RowNo = 1;
    
    SELECT * FROM @Suppliers ORDER BY Vendor, SupplierPK;
    

    返回

    +---------+---------+-------+------------+
    | Vendor  | VCScore | Text1 | SupplierPK |
    +---------+---------+-------+------------+
    | Vendor1 |      85 | Yes   |          1 |
    | Vendor1 |      85 | NULL  |          2 |
    | Vendor1 |      85 | NULL  |          3 |
    | Vendor2 |      65 | Yes   |          4 |
    | Vendor2 |      65 | NULL  |          5 |
    +---------+---------+-------+------------+
    

    我假设您有一个可以在您的供应商表中排序的主键值。

    【讨论】:

      【解决方案3】:

      我建议使用可更新的 CTE:

      with toupdate as (
            select s.* ,
                   row_number() over (partition by Vendor order by VCScore desc) as seqnum
            from Suppliers s
           )
      update toupdate
          set Text1 = 'Yes'
          where seqnum = 1;
      

      请注意,不需要JOIN

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-02-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-04-03
        • 1970-01-01
        相关资源
        最近更新 更多