User Defined function SQL 2008 - sql-server-2005

I'm trying to create a calculated column that returns an INT value, I ve created a function and need to pass the ndx number to the function and having issues with returning multiple values within the sub query.
how do I pass the ndx number to the function, I'm assuming that the calculated column looks at values from the same row!?
Msg 512, Level 16, State 1, Line 1
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
function
CREATE FUNCTION dbo.Nat_Weight(#me38_cycle_data_ndx INT)
RETURNS INT
AS
BEGIN
DECLARE #nat_weight INT =0;
DECLARE #mattype1 INT;
DECLARE #mattype2 INT;
DECLARE #mattype3 INT;
--DECLARE #me38_cycle_data_ndx INT;
-- get material type, need only hoppers 1-3, hopper 4,5,6 material type will never = 2
SET #mattype1 = (SELECT typehopper_01 FROM mm_Cycle_Data);
SET #mattype2 = (SELECT typehopper_02 FROM mm_Cycle_Data );
SET #mattype3 = (SELECT typehopper_03 FROM mm_Cycle_Data );
-- if material type=2 then add to #nat_weight ,
IF #mattype1 = 2
set #nat_weight = (SELECT cyclehopper_01 FROM mm_Cycle_Data WHERE me38_cycle_data_ndx=#me38_cycle_data_ndx );
IF #mattype2 = 2
set #nat_weight =#nat_weight+ (SELECT cyclehopper_02 FROM mm_Cycle_Data WHERE me38_cycle_data_ndx=#me38_cycle_data_ndx );
IF #mattype3 = 2
set #nat_weight =#nat_weight+ (SELECT cyclehopper_03 FROM mm_Cycle_Data WHERE me38_cycle_data_ndx=#me38_cycle_data_ndx )
RETURN #nat_weight
END

I think SQL Server is complaining about these lines:
SET #mattype1 = (SELECT typehopper_01 FROM mm_Cycle_Data);
SET #mattype2 = (SELECT typehopper_02 FROM mm_Cycle_Data);
SET #mattype3 = (SELECT typehopper_03 FROM mm_Cycle_Data);
It sounds like there are multiple rows in mm_Cycle_Data. If you assign a value using a sub-query, the sub-query can return only 1 row.
You will need to add a WHERE clause to these sub-queries to return a single row. Also, you can combine them like this:
SELECT #mattype1 = typehopper_01,
#mattype2 = typehopper_02,
#mattype3 = typehopper_03
FROM mm_Cycle_Data
WHERE me38_cycle_data_ndx=#me38_cycle_data_ndx

Related

SQL - slow While loop

I have the following T-SQL code that is either adding or updating 1 record at a time to a temp table. Does anyone have any suggestions to speed this process up?
DECLARE #Total AS INT
SELECT #Total = count(AgentsID) from #TempAgentsConcat
DECLARE #counter AS INT
SET #counter = 1
DECLARE #CurrentVal AS NVARCHAR(1024)
DECLARE #RowCount AS INT
DECLARE #OBJ_ID AS INT
while (#counter <= #Total)
begin
SELECT #OBJ_ID = Id FROM #TempAgentsConcat WHERE AgentsId = #counter
SELECT #CurrentVal = SVRMachine FROM #TempAgentsConcat WHERE ID = #OBJ_ID
IF EXISTS (SELECT * FROM #TempEndpoints WHERE ID = #OBJ_ID)
BEGIN
UPDATE #TempEndpoints SET SVRMachine = #CurrentVal WHERE ID = #OBJ_ID
END
ELSE
BEGIN
INSERT INTO #TempEndpoints (SVRMachine, IPPort, ID)
VALUES (#CurrentVal, NULL, #OBJ_ID)
END
--END
SET #counter = #counter + 1
end
It looks like, you are trying to merge one table into other. First lets talk of couple of issues in your query-
1. Avoid using loops unless it's extremely necessary.
2. You are assigning two different variables by reading same row in 2 queries.
You can do this in single query like
SELECT #OBJ_ID = Id,#CurrentVal = SVRMachine FROM #TempAgentsConcat WHERE AgentsId = #counter
instead of 2 queries
SELECT #OBJ_ID = Id FROM #TempAgentsConcat WHERE AgentsId = #counter
SELECT #CurrentVal = SVRMachine FROM #TempAgentsConcat WHERE ID = #OBJ_ID
Let's rewrite the query without using loops. The answer by #Cetin is one of the solutions. Your requirement looks classic example of merging tables, so you may use SQL MERGE (SQL server 2008 and above). You can read more about MERGE, here, checkout the example 'C'.
Using MERGE, your query will look like below.
MERGE INTO #TempEndpoints AS Target
USING (SELECT SVRMachine , Id from #TempAgentsConcat)
AS Source (SVRMachine, ID)
ON Target.ID = Source.ID
WHEN MATCHED THEN
UPDATE SET SVRMachine = Source.SVRMachine
WHEN NOT MATCHED BY TARGET THEN
INSERT (ID, IPPort, SVRMachine) VALUES (Id, NULL,SVRMachine)
Why would you use a lot of variables and loop. SQL server (any SQL series database as well) works best with sets, rather than loops:
UPDATE #TempEndpoints
SET SVRMachine = ac.SVRMachine
FROM #TempAgentsConcat ac
WHERE #TempEndpoints.Id = ac.ID;
INSERT INTO #TempEndpoints
(
SVRMachine,
ID
)
SELECT SVRMachine,
ID
FROM #TempAgentsConcat ac
WHERE NOT EXISTS
(
SELECT * FROM #TempEndpoints ep WHERE ep.ID = ac.ID
);

Sql procedure with two input parameters

I need to make a SQL stored procedure that will take two input parameters ( id from table ‘users’ and id from table ‘sales’ ) and then if value of column ‘coupons’ (table ‘users’) is greater then 0, it increases value for 1 in column ‘numOfSales’(table ‘sales’) and decreases value for 1 in column ‘coupons’.
I tried this :
CREATE PROCEDURE usp_makesale
#id_sales int NOT NULL,
#id_users int NOT NULL
AS
BEGIN
SET NOCOUNT ON;
SELECT users.coupons, sales.numOfSales
IF (coupons > 0)
BEGIN
SET coupons - 1;
SET numOfSales + 1;
END
How to declare those variables properly ?
You should declare the variables like so:
DECLARE #coupons AS INT
SELECT #coupons = coupons FROM users WHERE users.id = #id_users
DECLARE #numOfSales AS INT
SELECT #numOfSales = numOfSales FROM sales WHERE sales.id = #id_sales
However you also haven't correctly written an update statement to update the values in your columns. You require something like:
UPDATE users
SET coupons = coupons - 1
WHERE users.id = #id_users
UPDATE sales
SET numOfSales = numOfSales + 1
WHERE sales .id = #id_sales

How to store result of a select statement into a variable?

I tried with the below code:
DECLARE #rec_count int
Set #rec_count= select 1
but it shows error
"Incorrect syntax near Select".
Either:
set #rec_count = (select 1)
or
select #rec_count = 1
An example assigning the count from a table to variable:
set #rec_count = (select COUNT(*) from master..spt_values)
select #rec_count = COUNT(*) from master..spt_values
However, if you just want to assign a value to a variable you don't need any select statement:
set #rec_count = 1
or
declare #rec_count int = 1
To store the result of a select statement into a variable, see below
DECLARE #rec_count INT
SELECT #rec_count = 1
We can get more than one value from select statement as below
DECLARE #rec_count INT
DECLARE #date DATETIME
SELECT #rec_count = 1, #date = GETDATE()
If you're trying to get a record count, which looks like what you're trying to do, you can do this:
declare #rec_count int
select #rec_count = count(1) from [your_table] -- where some condition is met
Note: Use count(1) instead of count(*) as it's quicker to simply select a single column than all when getting a count.
Or if this count is the result of some inserts/updates/selects/deletes, you can use the ##ROWCOUNT, which:
Returns the number of rows affected by the last statement.
So if for example you are performing an update or select and want to know how many rows were affected, it will automatically be stored by SQL Server in the ##ROWCOUNT.
declare #rec_count int
-- some table change
update your_table
set col1 = 1
where col1 = 0
set #rec_count = ##ROWCOUNT
-- select ##ROWCOUNT <-- this would return the number of rows updated
DECLARE #rec_count int;
Set #rec_count = 1;

Aggregate Value in UDF Always Zero, Affecting Local Variable

The following UDF returns an integer based on different conditions executed after a query. The variables, #recCount, is always a zero despite the fact that it can also be greater than zero. It should contain the value of inline query using COUNT(*).
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER FUNCTION [dbo].[fnGetConfID] (#eventID INT,
#conferenceID INT,
#companyID VARCHAR(32))
RETURNS INT
AS
BEGIN
-- Declare the return variable here
DECLARE #confID INT; -- Conference ID we're passing back
DECLARE #curAtt INT; -- Current attendance
DECLARE #maxAtt INT; -- Max attendance
DECLARE #waitConfID INT; --Waitlist value of current conference
DECLARE #recCount INT; -- Total number of employees who selected same conference
SELECT #confID = ec.conferenceID,
#recCount = (SELECT count(*)
FROM tblRegistration r
INNER JOIN tblRegConferences rc
ON r.ID = rc.regID
WHERE r.optfield2 = #companyID
AND r.eventID = #eventID
AND rc.conferenceID = #conferenceID),
#curAtt = ec.currentAttendance,
#maxAtt = ec.maxAttendance,
#waitConfID = ec.waitListProdID
FROM tblEventConferences ec
WHERE ec.conferenceID = #conferenceID
AND ec.isWaitList = 0
-- If no records were found (waitlist item)
IF ##ROWCOUNT = 0
BEGIN
SET #confID = #conferenceID -- use same value we passed in
END
-- records found
ELSE
BEGIN
--Max attendance not reached, return main conference ID
IF #curAtt < #maxAtt
BEGIN
SET #confID = #conferenceID
END
--Max attendance reached, return waitlist ID
IF #curAtt >= #maxAtt
BEGIN
SET #confID = #waitConfID
END
--Company cap reached, return waitlist ID
IF #recCount > 1
BEGIN
SET #confID = #waitConfID
END
END
RETURN #confID
END
Running it as a query, I get values greater than zero for the field companyCnt, which is #recCount's equivalent.
SELECT ec.conferenceID, (
SELECT count(*)
FROM tblRegistration r
INNER JOIN tblRegConferences rc ON r.ID = rc.regID
WHERE
r.optfield2 = '83b90acc-42af-4de2-9279-76e80eb8b73a'
AND
r.eventID = 624
AND
rc.conferenceID = 8848
) AS companyCnt, ec.currentAttendance, ec.maxAttendance, ec.waitListProdID
FROM
tblEventConferences ec
WHERE
ec.conferenceID = 8848
AND
ec.isWaitList = 0
Change #companyid from varchar(32) to varchar(50).
You are experiencing this problem because the length of company in your query is 36 characters where as the variable is declared only for 32 characters SQL server don't give a warning it just truncates the last characters.

SQL Stored Procedure set variables using SELECT

I have a stored procedure in SQL Server 2005 with multiple variables and I want to set the values of these variables using a select statement. All three variables come from a same table and there should be a way to set them using one select statement instead of the way I currently have as shown below. Please help me to figure it out.
DECLARE #currentTerm nvarchar(max)
DECLARE #termID int
DECLARE #endDate datetime
SET #currentTerm =
(
Select CurrentTerm from table1 where IsCurrent = 1
)
SET #termID =
(
Select TermID from table1 where IsCurrent = 1
)
SET #endDate =
(
Select EndDate from table1 where IsCurrent = 1
)
select #currentTerm = CurrentTerm, #termID = TermID, #endDate = EndDate
from table1
where IsCurrent = 1
One advantage your current approach does have is that it will raise an error if multiple rows are returned by the predicate. To reproduce that you can use.
SELECT #currentTerm = currentterm,
#termID = termid,
#endDate = enddate
FROM table1
WHERE iscurrent = 1
IF( ##ROWCOUNT <> 1 )
BEGIN
RAISERROR ('Unexpected number of matching rows',
16,
1)
RETURN
END