Reputation: 115
The problem is that I have several registers of an specific buy order because, each register is of a different product in the same purchase, first I did this function:
CREATE FUNCTION TOTALORDEN (@id_orden INT)
RETURNS float
AS
BEGIN
DECLARE @total FLOAT
SELECT @total = UnitPrice * Quantity - UnitPrice * Quantity * Discount
FROM [Order Details]
WHERE @id_orden = OrderID
RETURN @total
END
but the problem with that function was that only printed the result of the last register.
Then I decided to use SQL arithmetics on the select instruction, and the function is this:
CREATE FUNCTION TOTALORDEN (@id_orden INT)
RETURNS table
RETURN (SELECT (UnitPrice * Quantity) -
(UnitPrice * Quantity * Discount)
FROM [Order Details]
WHERE @id_orden = OrderID)
And the error it shows is:
Msg 4514, Level 16, State 1, Procedure TOTALORDEN, Line 3
CREATE FUNCTION produced an error because no column name was specified for column 1.
Part of the data in the table:
Upvotes: 0
Views: 2499
Reputation: 9241
SQL Server Scalar functions perform bad in SQL Server, you should try to avoid them as much as possible. An inline table valued function is better, however in this case, I would prefer a view like the following:
CREATE VIEW OrderDetailsSummary
WITH SCHEMABINDING
AS
SELECT od.OrderID, SUM (ISNULL(od.Quantity * od.UnitPrice * (1 - CAST(od.Discount AS money)), 0)) as OrderTotal, COUNT_BIG(*) AS OrderLineCount
FROM
dbo.OrderDetails od
GROUP BY
od.OrderID
GO
This view can be indexed, making it lightning fast:
CREATE UNIQUE CLUSTERED INDEX UX_OrderDetailsSummary
ON OrderDetailsSummary(OrderID)
You can now get order total and order line count with a simple query like this:
SELECT *
FROM OrderDetailsSummary WITH (NOEXPAND)
WHERE OrderID = 10260
It is extremely efficient. I only requires 2 logical reads:
(1 row affected) Table 'OrderDetailsSummary'. Scan count 0, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
This is the execution plan:
Additionally the view can be JOINED with other views and tables. For example you can get the order information along with summary data:
SELECT O.OrderID, O.CustomerID, O.OrderDate, S.OrderTotal, S.OrderLineCount
FROM
dbo.Orders O
LEFT OUTER JOIN dbo.OrderDetailsSummary S WITH (NOEXPAND)
ON O.OrderID = S.OrderID
Upvotes: 0
Reputation: 590
SQL does not like it if you don't tell it what the column returned is named. I have used a column name of FinalPrice , which you can change to what you want to call it.Also if you are planning to use this function to update the table etc, having the orderid returned in the table would be helpful. This should work :
CREATE FUNCTION [TOTALORDEN] ( @id_orden INT )
RETURNS TABLE
RETURN
(
SELECT OrderId, SUM(( [UnitPrice] * [Quantity] ) - ( [UnitPrice] * [Quantity] * [Discount]) ) AS FinalPrice
FROM
[Order Details]
WHERE [OrderID] = @id_orden
Group BY OrderId
)
Also, if you just need the total order sum returned, using a table valued function is an overkill. You should use
CREATE FUNCTION [TOTALORDEN] ( @id_orden INT )
RETURNS FLOAT
AS
BEGIN
DECLARE @total FLOAT
SELECT
@total = SUM (([UnitPrice] * [Quantity]) - ([UnitPrice] * [Quantity] * [Discount]))
FROM
[Order Details]
WHERE [OrderID] = @id_orden
RETURN @total
END
Having spaces in your table names is not recommended either, you should think about refactoring that as well
Upvotes: 1
Reputation: 24803
I guessed you missed the aggregate function SUM()
DECLARE @total float
SELECT @total= SUM (UnitPrice*Quantity-UnitPrice*Quantity*Discount)
FROM [Order Details]
WHERE @id_orden=OrderID
RETURN @total
Upvotes: 1