November 2, 2005 at 1:25 pm
I have a table that has about 500,000 records, each record has four different cost fields that are already populated(List, Itemfile, bluebook, mfr). I would like to populate a fifth cost field (best cost) with the lowest of the four costs in the other fields. Is there an easy/quick way to do this? I wrote a Cursor that does it, but it took over a half hour to run, which is unacceptable. The table layout looks like this...Thanks...
Item - MFR - Itemfile - List - bluebook - BestCost
November 2, 2005 at 2:41 pm
do a simple case, it's wordy but it works
update table
set col = CASE WHEN A< B AND A< C AND A< D AND A < E THEN A
WHEN B < A AND B< C AND....
you get the idea
Or write a MIN function that accepts as many columns (parms) as you need.
But never, never ever use a cursor. If you ever think you have to, you're 99.99% of the time wrong. And I do not know of any example where it would be quicker than set processing.
November 2, 2005 at 2:48 pm
And I know only one... which ain't the case here.
Why can't you add a computed column that will contain the lowest price? Also why isn't the price in its own table??
November 2, 2005 at 2:57 pm
What's involved with a computed column?
The CASE worked like a champ, but sometimes one of the four cost columns is null and it's updating the best cost field to null, which I don't want. I would want it to be the lowest of what ever has a value.
November 2, 2005 at 3:23 pm
Make a function with 4 parameters. Then use this function in the formula for the column (becoming a calculated field).
The function would look something like this :
SET @ReturnValue = @Cost1
IF @Cost2 < @ReturnValue
BEGIN
SET @ReturnValue = @Cost2
END
IF @Cost3 < @ReturnValue
BEGIN
SET @ReturnValue = @Cost3
END
IF @Cost4 < @ReturnValue
BEGIN
SET @ReturnValue = @Cost4
END
RETURN @ReturnValue
You didn't answer my question as to why there were more than 1 price field in the table??
November 2, 2005 at 3:44 pm
Remi, if Cost1 is NULL you function will always return NULL.
IF @Cost2 < @ReturnValue OR @ReturnValue IS NULL
will fix it.
_____________
Code for TallyGenerator
November 2, 2005 at 4:05 pm
I never set returnvalue to null... I don't see how that would help, if the Costx is null, then the condition will not be true so the status shouldn't change.
November 2, 2005 at 4:16 pm
If Cost1 is null, @ReturnValue becomes null in first statement, and all conditions will not be be true, so no further statements to execute. @ReturnValue will stay NULL till the end of the function.
My fix will let further statements to execute, and if there is at least one cost not null @ReturnValue will pick it up.
_____________
Code for TallyGenerator
November 2, 2005 at 4:21 pm
Oops, I thaugth sometimes the 4th was null... but anyone can be null so that's another problem altogether. Thanx for pointing it out.
November 3, 2005 at 5:01 am
But as Remi said, you might as well make your 5th cost a computed column. This saves you from updating it all the time - it will always be up to date! If you then need to index it, you still can, although then you can get messy with having all of the ANSI SET options enabled... Look up indexed view in SQL Server Books Online and you'll see what I mean you can set defaults for the SET option at the server & database level though, so it's not such a problem
November 3, 2005 at 6:34 am
Although the least cost can be determined with the CASE statement, since there are nulls and the least cost algorithm must handle nulls, the case statement would be very complicated. This is a situation where a user defined function would be easier to code, maintain and debug.
CREATE Function udf_LeastCost
(@MFRCost integer , @ItemfileCost integer, @ListCost integer, @bluebookCost integer)
returns integer
as
begin
IF @MFRCost is null and @ItemfileCost is null and @List is null and @bluebookCost is null
return null
-- Replace null with largest possible value for the integer data type
set @MFRCost= COALESCE(@MFRCost, 2147483647 )
set @ItemfileCost= COALESCE(@ItemfileCost, 2147483647 )
set @ListCost = COALESCE(@ListCost , 2147483647 )
set @bluebookCost= COALESCE(@bluebookCost, 2147483647 )
Declare @LeastCost integer
Set @LeastCost = 2147483647
IF @MFRCost < @LeastCost set @LeastCost = @MFRCost
IF @ItemfileCost< @LeastCost set @LeastCost = @ItemfileCost
IF @ListCost < @LeastCost set @LeastCost = @ListCost
IF @bluebookCost< @LeastCost set @LeastCost = @bluebookCost
return @LeastCost
end
go
Alter table Cars
add LeastCost as
dbo.udf_LeastCost
(MFRCost,ItemfileCost,ListCost,bluebookCost)
SQL = Scarcely Qualifies as a Language
November 3, 2005 at 6:48 am
What about this??
update bestcost set lowestcost = coalesce(itemfilecost, listcost, bluebookcost, mfrcost)
update bestcost set lowestcost = listcost where listcost < lowestcost
update bestcost set lowestcost = bluebookcost where bluebookcost < lowestcost
update bestcost set lowestcost = mfrcost where mfrcost < lowestcost
November 3, 2005 at 9:29 am
Are you gonna run that statement everytime the rows are inserted/updated?? That's why I suggested the use of a computed column.
November 3, 2005 at 10:14 am
The way it's working now is I update the four costs first then I ran the code in the previous post to get lowestcost and it seems to be working out pretty well.
November 3, 2005 at 3:20 pm
Are you going to update whole table 4 times every time any single row is updated?
Hard drives on your server not gonna stay long.
_____________
Code for TallyGenerator
Viewing 15 posts - 1 through 15 (of 17 total)
You must be logged in to reply to this topic. Login to reply