SQL Server - 使用SubQuery的结果更新每个组的所有记录

时间:2017-08-08 21:51:43

标签: sql-server

如果有人甚至可以帮助我更好地表达这个问题,我会很感激。

我有一个SQL Server表,我们称之为汽车,其中包含表示项目的条目和有关其所有者的信息,包括car_id,owner_accountNumber,owner_numCars。

我们正在使用一种系统来对所有者的重要性进行排序'根据拥有的汽车数量,并依靠owner_numCars列来实现。如果合理可能的话,我宁愿不调整它。

有没有办法可以使用存储过程为owner_accountNumber更新owner_numCars?也许其他一些更有效的方法我可以完成每个owner_numCars包含每个owner_accountNumber的条目数?

现在我能想到的唯一方法就是(来自c#应用程序):

SELECT owner_accountNumber, COUNT(*)
FROM mytable
GROUP BY owner_accountNumber;

然后由该查询返回的foreach行

UPDATE mytable 
SET owner_numCars = <count result> 
WHERE owner_accountNumber = <accountNumber result>

但与服务器处理逻辑和更新相比,这似乎效率极低。

编辑 - 感谢所有帮助。我知道这不是一个设置良好的数据库,但这是我必须要做的事情。我感谢大家的意见和建议。

4 个答案:

答案 0 :(得分:1)

有很多方法可以做到这一点。这是使用2147483648窗口函数和可更新long int的一种方法。您不必担心将数据关联回来,ID等。

COUNT() OVER

但是,从设计的角度来看,我会提出这个值(owner_numCars)是应该在这个表上还是我认为是所有者表的问题。

如果您希望数据始终反映当前值,Rominus确实很好地使用了视图。您还可以使用表值函数来执行此操作,该函数可能比视图更高效。但如果你只是展示它,那么你可以简单地做这样的事情:

Common Table Expression [CTE]

通过向CTE或SELECT语句添加where子句,您将有效地限制数据集,并且解决方案应保持快速。 E.g。

;WITH cteCarCounts AS (
    SELECT
       owner_accountNumber
       ,owner_numCars
       ,NewNumberOfCars = COUNT(*) OVER (PARTITION BY owner_accountNumber)
    FROM
       MyTable
)

UPDATE cteCarCounts
SET owner_numCars =  NewNumberOfCars

答案 1 :(得分:1)

我认为你需要的是一个视图。如果您不知道,View是一个虚拟表,它显示/计算真实表中的数据,该表随表数据更新而不断更新。因此,如果您希望看到添加了owner_numCars的表格,您可以执行以下操作:

SELECT a.*, b.owner_numCars
from mytable as a
inner join
    (SELECT owner_accountNumber, COUNT(*) as owner_numCars 
    FROM mytable
    GROUP BY owner_accountNumber) as b
on a.owner_accountNumber = b.owner_accountNumber

您需要从真实表中删除owner_numCars列,因为您不需要在每行上实际存储该数据。如果您无法将其删除,则可以使用a.*以外的所有字段的明确列表替换owner_numCars

答案 2 :(得分:1)

此解决方案考虑到您希望将owner_numCars列保留在CARs表中,并且该列应始终准确实时。

我将表CARS定义为一个表格,其中包含有关汽车的属性,包括它的当前所有者。当前所有者拥有的汽车数量被归一化到此表中。说我,LAS,拥有三辆车,然后表CARS中有三个条目,如下:

    car_id    owner_accountNumber    owner_numCars
      1         LAS1                     3
      2         LAS1                     3
      3         LAS1                     3

要将owner_numCars用作实时界面中的重要性因素,每次LAS1销售或购买汽车或从行中删除或添加到行中时,您都需要为每辆汽车更新owner_numCars。

请注意,您需要为新老用户更新CARS。如果Sam购买了car1,Sam和LAS都会购买。总计需要更新。

您可以使用此过程更新行。此SP对上下文非常敏感。在删除或插入已删除或插入的所有者的行之后,需要调用它。更新所有者后,需要为新老所有者调用它。

在帐户更改所有者时更新实时:

create procedure update_car_count 
@p_acct nvarchar(50)  -- use your actual datatype here

AS

    update CARS 
    set owner_numCars = (select count(*) from CARS where owner_accountNumber = @p_acct)
    where owner_accountNumber = @p_acct;

GO

更新所有account_owners:

create procedure update_car_count_all
AS

    update C
    set owner_numCars = (select count(*) from CARS where owner_acctNumber = C.owner_acctNumber)
    from CARS C
GO

答案 3 :(得分:1)

您不希望运行SQL来更新此值。如果它不运行很长时间怎么办?如果某人加载大量数据然后运行得分并发现一个拥有100辆汽车的人计为零b / c,那么更新就不会运行。数据应该只存在于1个位置,更新它应该存在于2中。您需要一个根据需要从表中提取此值的视图。

CREATE VIEW vOwnersInfo
AS
SELECT o.*, 
ISNULL(c.Cnt,0) AS Cnt
FROM OWNERS o
LEFT JOIN 
      (SELECT OwnerId, 
       COUNT(1) AS Cnt
       FROM Cars
       GROUP BY OwnerId) AS c
ON o.OwnerId = c.OwnerId