如果有人甚至可以帮助我更好地表达这个问题,我会很感激。
我有一个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>
但与服务器处理逻辑和更新相比,这似乎效率极低。
编辑 - 感谢所有帮助。我知道这不是一个设置良好的数据库,但这是我必须要做的事情。我感谢大家的意见和建议。
答案 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