SQL 服务器如何使用 SELECT 和 GROUP BY 子句进行更新

SQL Server How to UPDATE with SELECT and GROUP BY clause

我们的团队使用 SQL 服务器,我想使用聚合函数为正在插入的新值更新其中一列,现有 table。

下面是现有的 table 和其中的值。

CREATE TABLE CARS 
(
   ID INT NOT NULL,
   carCompany VARCHAR(100) NOT NULL,
   feature VARCHAR(100) NOT NULL,
   sequence INT NOT NULL
);

INSERT INTO CARS VALUES (1, 'Toyota', 'Auto transmission', 1); 
INSERT INTO CARS VALUES (2, 'BMW', 'Keyless Entry system', 1);
INSERT INTO CARS VALUES (3, 'Toyota', 'Power Steering', 2); 
INSERT INTO CARS VALUES (4, 'Tesla', 'Auto transmission', 1); 
INSERT INTO CARS VALUES (5, 'BMW', 'Auto transmission', 2);
INSERT INTO CARS VALUES (6, 'Tesla', 'Keyless Entry system', 2);
INSERT INTO CARS VALUES (7, 'BMW', 'Power Steering', 3); 

对于 BMW 和 Tesla 的 'Auto Pilot' 要求仅在同一个 carCompany 组中递增序列列。由于 Insert 语句更容易,我只是插入记录并努力使 Update 语句正确。

INSERT INTO CARS VALUES (8, 'Tesla', 'Auto Pilot', 0);
INSERT INTO CARS VALUES (9, 'BMW', 'Auto Pilot', 0);

以下 UPDATE 语句不正确。请在这里帮忙。

UPDATE c1 
SET c1.sequence = d.sq
FROM 
    (SELECT MAX(c2.sequence) + 1 AS sq 
     FROM CARS c2 
     WHERE c2.carCompany = c1.carCompany 
     GROUP BY c2.carCompany) d
WHERE c1.sequence = 0

大功告成,只需将相关子查询移动到 SET 语句中即可:

UPDATE c1 
    SET c1.sequence = (SELECT max(fc2.sequence) + 1 as sq FROM CARS c2 WHERE c2.carCompany = c1.carCompany GROUP BY c2.carCompany)
FROM CARS c1
WHERE c1.sequence = 0

但请注意,这仅适用于该汽车公司只有一项新记录的情况。即,如果您有两个新的 Tesla 功能,它们都将设置为 2。您可以使用带有 RANK 函数的 CTE 来允许任意数量的新值:

WITH NewSequences
AS (
SELECT id, RANK()OVER(PARTITION BY c1.carCompany ORDER BY id) + (SELECT max(fc2.sequence) + 1 as sq FROM CARS c2 WHERE c2.carCompany = c1.carCompany GROUP BY c2.carCompany) AS NewSeq
FROM CARS
WHERE c1.[sequence] = 0
)
UPDATE c1 
    SET c1.sequence = n.NewSeq
FROM CARS c1
    INNER JOIN NewSequences n
        ON c1.id = NewSequences.id

如果您只想要下一个序列号,您的查询就非常接近了:

UPDATE cars 
    SET sequence = d.sq
FROM (SELECT max(c2.sequence) + 1 as sq
      FROM CARS c2 
      GROUP BY c2.carCompany
     ) c2
     ON c2.carCompany = c1.carCompany
WHERE sequence = 0;

注意:如果您插入了同一家公司的多行,我认为这不会满足您的要求。据推测,您希望它们具有不同的值,因此您可以使用:

with toupdate as (
      select c.*,
             max(c.sequence) over (partition by carcompany) as max_sequence,
             row_number() over (partition by carcompany order by id) as seqnum
      from cars c
     )
update toupdate
    set sequence = max_sequence + seqnum
    where sequence = 0;

然而,当你可以使用时,预先计算这个值似乎是完全没有必要的:

select c.*,
       row_number() over (partition by carCompany order by id) as seq
from cars c;

我没有理由存储这个值。