I need this query inside a select statement in another query, i have tried to put it inside a function and call it from the select, but i get errors maybe because non-scalar statements are not allowed in a function. How can i proceed?
SELECT Tip.NombreTipoMov
INTO #tabla_temp
FROM ut_sgt_Movimientos_t Reg
INNER JOIN ut_sgt_TiposMovimientos_m Tip
ON Reg.id_TipoMov = Tip.id_TipoMov
WHERE Reg.id_Registro = #IdRegistro
DECLARE #data VARCHAR(100)
UPDATE #tabla_temp
SET #data = #data + ' ' + NombreTipoMov
SELECT LTRIM(RTRIM(#data))
DROP TABLE #tabla_temp
This is the function:
CREATE FUNCTION dbo.uf_sgt_ObtieneTiposMovimientosXRegistroVehiculo
(
#IdRegistro INTEGER
)
RETURNS VARCHAR(100)
AS
BEGIN
DECLARE #Retorno VARCHAR(100)
SET #Retorno = ( SELECT Tip.NombreTipoMov
INTO #tabla_temp
FROM ut_sgt_Movimientos_t Reg
INNER JOIN ut_sgt_TiposMovimientos_m Tip
ON Reg.id_TipoMov = Tip.id_TipoMov
WHERE Reg.id_Registro = #IdRegistro
DECLARE #data VARCHAR(100)
UPDATE #tabla_temp
SET #data = #data + ' ' + NombreTipoMov
SELECT LTRIM(RTRIM(#data))
DROP TABLE #tabla_temp
)
RETURN #Retorno END GO
This is the error:
Incorrect syntax near the keyword 'INTO'.
Illegal UPDATE statement within a scalar SQL function.
Illegal SELECT statement within a scalar SQL function.
Illegal DROP TABLE statement within a scalar SQL function.
Incorrect syntax near ')'.
Related
I'm trying to make a function that evaluates the expiration date in a policy and based on that when is called in a Query it returns the text values ('Monthly'..and so on). but i'm getting a few errors of type "Incorrect syntax near Begin, declare expecting (.", "Must declare the scalar variable #policybillid" and in the end of the function "Incorrect syntax near ')'.". Any help would be appreciated.
USE [defaultDB]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE OR ALTER FUNCTION [dbo].[fn_Payment_GetPaymentCoutesByPaymentID]( #policybillid BIGINT, #companyID BIGINT) Returns TABLE
AS
RETURN (
BEGIN( ***Incorrect syntax near 'BEGIN'. Expecting '(', SELECT, or WITH.***
declare #expiresDates as table(expiredOn date) ***Incorrect syntax near 'declare'.*** Expecting '(', or SELECT.
insert into #expiresDates
select top(2) expiredOn from PolicyPaymentPlan
left join PolicyPaymentPlanFee on PolicyPaymentPlan.paymentPlanID= PolicyPaymentPlanFee.paymentPlanID
where PolicyPaymentPlan.policyBillID = #policybillid --Must declare the scalar variable "#policybillid".
order by cuoteID
select * from #expiresDates
declare #diffMonth int
declare #quota varchar(max) = ''
if((select count(*) from #expiresDates) > 1)
BEGIN
set #diffMonth = DATEDIFF(month, (select top(1) expiredOn from #expiresDates), (select top(1) expiredOn from #expiresDates order by expiredOn desc));
set #quota = ( SELECT
CASE
WHEN #diffMonth =1
then
'Monthly'
WHEN #diffMonth =2 THEN
'bimonthly'
WHEN #diffMonth =3 THEN
'trimonthly '
WHEN #diffMonth =4 THEN
'Four-Monthly'
WHEN #diffMonth =6 THEN
'biannual'
ELSE 'Cash'
END
)
END
) ***Incorrect syntax near ')'.***
There are numerous issues and syntax errors on your existing code. The main one is that an inline Table Valued Function can only have a single SELECT statement and nothing else.
So here is what it should look like.
CREATE OR ALTER FUNCTION [dbo].[fn_Payment_GetPaymentCoutesByPaymentID](
#policybillid BIGINT,
#companyID BIGINT
)
RETURNS TABLE
AS RETURN
SELECT Quota =
CASE WHEN COUNT(*) > 1 THEN
CASE DATEDIFF(month, MIN(expiredOn), MAX(expiredOn))
WHEN 1 THEN 'Monthly'
WHEN 2 THEN 'bimonthly'
WHEN 3 THEN 'trimonthly '
WHEN 4 THEN 'Four-Monthly'
WHEN 6 THEN 'biannual'
ELSE 'Cash'
END
END
FROM (
select top (2) expiredOn
from PolicyPaymentPlan pp
join PolicyPaymentPlanFee ppf on pp.paymentPlanID = ppf.paymentPlanID
where pp.policyBillID = #policybillid
order by cuoteID
) pp
;
Here is the requirement:
Find all teachers whose FirstName length is less than 5 and the first 3 characters of their FirstName and LastName are the same
I tried this query (Scalar Function):
CREATE OR ALTER FUNCTION dbo.fn_TeacherFirstName (#TeacherID int)
RETURNS NVARCHAR(20)
AS
BEGIN
DECLARE #Result NVARCHAR(20)
SELECT #Result = LEN(FirstName) < 5 AND LEFT(FirstName,3) = LEFT(LastName,3)
FROM dbo.Teacher
WHERE #TeacherID = ID
RETURN #Result
END
To call function:
--CALL FUNCTION
select *, dbo.fn_TeacherFirstName (ID) AS Result
from dbo.Teacher t
But, when I execute first query, it shows error:
Incorrect syntax near '<'.
Can anyone help me with this?
Just use a normal query, not a function. Also there is no boolean type in SQL Server, use bit instead.
SELECT *,
Result = CAST(CASE WHEN LEN(t.FirstName) < 5 AND LEFT(t.FirstName, 3) = LEFT(t.LastName, 3) THEN 1 END AS bit)
FROM dbo.Teacher t
My question is similar to this.
I made a scalar function like follows:
CREATE FUNCTION [dbo].[MyFunction](#table [TableModel] READONLY)
RETURNS DECIMAL(18, 6) AS
BEGIN
DECLARE #sql NVARCHAR(MAX), #params NVARHCAR(MAX), #value DECIMAL(16, 8);
SELECT #sql = formula, #params = params FROM formulas WHERE id = (SELECT TOP 1 id_formula FROM #table)
EXEC sp_executesql #sql, #params, #table=#table, #value=#value OUTPUT;
RETURN #value;
END
Where a formula SQL could be something like:
SELECT #value = SUM(value) / AVG(value) FROM #table
And it could have more columns if needed.
The model table looks like so:
CREATE TYPE [dbo].[TableModel] AS TABLE(
[formula] INT NOT NULL,
[value] DECIMAL(16, 8) NOT NULL
)
And I want to use it like so:
SELECT od.id, od.col1, od.col2,
dbo.MyFunction((SELECT id.formula, id.value FROM #raw_data id WHERE id.id = od.id)) as result
FROM #data od
GROUP BY od.id, od.col1, od.col2
Where the ID unique and multiple rows will have the same id.
Basically, what I'm trying to do in a single query I want to call a function that has a table parameter. But I want this table to be a subquery.
I'm aware that you can call the function with a table variable as mentioned in this answer.
Is this possible in any way? I'm having this error at executing:
Msg 116, Level 16, State 1, Line 30
Only one expression can be specified in the select list when the subquery is not introduced with EXISTS.
ALTER FUNCTION [dbo].[UDF_GetExpenseDetails](#EmpID nvarchar(50))
RETURNS NVARCHAR(MAX)
AS
BEGIN
DECLARE #ExpAmount nvarchar(MAX)
DECLARE #ExpName nvarchar(MAX)
IF (#EmpID <> '')
BEGIN
SELECT distinct
#ExpAmount = SE.ExpenseAmount, #ExpName = ME.ExpenseName
FROM
tbl_admin_supplierempexpense SE, tbl_master_expense ME
WHERE
SE.EmpID = #EmpID
AND SE.ExpenseName = ME.ExpenseID
AND SE.Status = 'P'
END
RETURN #ExpAmount,#ExpName
END
ERROR : Incorrect syntax near ','.
You can not return more than 1 values from a FUNCTION. If you want multiple values, create a table-valued function.
See it here http://technet.microsoft.com/en-us/library/ms191165.aspx , example included
What if you try this?
CREATE FUNCTION [owner].[UDF_GetExpenseDetails](#EmpID nvarchar(50))
RETURNS TABLE
AS
RETURN
(
SELECT <column1, column2>
FROM <table>
WHERE <condition>
);
Try this
ALTER FUNCTION [dbo].[UDF_GetExpenseDetails](#EmpID nvarchar(50))
RETURNS #table( #ExpAmount money,#ExpName varchar(100))
As
begin
IF (#EmpID <> '')
BEGIN
insert into #ExpAmount
SELECT distinct SE.ExpenseAmount,ME.ExpenseName
from tbl_admin_supplierempexpense SE, tbl_master_expense ME
where SE.EmpID = #EmpID and SE.ExpenseName=ME.ExpenseID and SE.Status='P'
END
return
END
Say I had a query like this:
SELECT X FROM Table WHERE Y = 'Z'
How could I execute a Stored Procedure using each X from the above query as the parameter?
UPDATE
I have changed the SP to be a Table-valued function instead. So for each call to the function it will return a table. What I need to do is store all these results in perhaps a temp table and have my SP return this table.
SOLUTION
Finally managed to get this to work with some help from #cyberkiwi. Here is my final solution:
DECLARE #Fields TABLE (
Field int)
INSERT INTO #Fields (X) SELECT * FROM tvf_GetFields(#SomeIdentifier)
SELECT * FROM #Fields
CROSS APPLY dbo.tvf_DoSomethingWithEachField([#Fields].Field)
You can generate a batch statement out of it and then EXEC it
DECLARE #sql nvarchar(max)
SELECT #sql = coalesce(#sql + ';', '')
+ 'exec sprocname ' + QuoteName(AField, '''')
FROM Table
WHERE AField2 = 'SomeIdentifier'
AND AField is not null
EXEC (#sql)
Before the edit (to TVF), you could have changed the SP to continue to populate a temp table.
Post-edit to TVF, you can use a cross apply:
SELECT F.*
FROM Tbl CROSS APPLY dbo.TVFName(Tbl.AField) F
WHERE Tbl.AField2 = 'SomeIdentifier'
Which returns all the "table results" from each invocation of Tbl.AField into a single result set