Transaction in function sql server 2012 - sql-server

I have question. That I can use transaction in function in SQL Server 2012? Because now I have error:
Invalid use of a side-effecting operator 'BEGIN TRANSACTION' within a function.

if you are writing the function to better structure a script, you can call it "procedure" instead of "function", and pass it one or more OUTPUT parameters to receive the computed result.
a "function" cannot have side effects, like inserting/updating/deleting rows or creating/altering/dropping of structures.
i had the same problem and found the solution at the sqlservertutorial , and i heartly recommend you that reading.
CREATE PROCEDURE uspFindProductByModel (
#model_year SMALLINT,
#product_count INT OUTPUT
) AS
BEGIN
SELECT
product_name,
list_price
FROM
production.products
WHERE
model_year = #model_year;
SELECT #product_count = ##ROWCOUNT;
END;
to invoke the procedure and receive the result:
DECLARE #count INT;
EXEC uspFindProductByModel
#model_year = 2018,
#product_count = #count OUTPUT;
i have to mention, that the procedure in this example does not have any side effects, as changing data in the db, so that it could be built as a function as well.
anyway, a procedure seems more versatile, and may support many output parameters, instead of only one return value.
yes i know, a function may return an aggregate.
good luck,

Related

update table with SQL function

I would like to update data in a table (for sqlserver and oralce version).
I created a stored procedure as below, but i would like to convert it to SQL function, is it possible to update data within SQL function please?
CREATE PROCEDURE updatetable (#A1 INTEGER, #A2 VARCHAR(4000) )
AS
BEGIN
BEGIN
UPDATE table SET column1= column1+ #A1 WHERE column2= #A2 ;
END
END
For SQL Server.
Simply put:
No.
A function can't change the system (really gross and dangerous hacks aside). From the documentation (emphasis mine):
Specifies that a series of Transact-SQL statements, which together do not produce a side effect such as modifying a table
If you can explain what you're trying to accomplish with a function that you can't accomplish with a stored procedure, you might be asking a question that has more than a yes/no answer, and you might get useful alternatives.

Better way to use SQL Server function?

Hey guys I want to use SQL Server function,
I never use function in SQL Server and I only know that function must return a value so I have two stored procedure (1 for insert and 1 for select)
My stored procedures look like this
For insert:
create proc INS_tblteststud
#stdtid int=null,
#name varchar(50) =null,
#fullname varchar(50)=null,
#address varchar(50)=null,
#city varchar(50)=null,
#country varchar(50)=null,
#contno varchar(50)=null
as
begin
insert into tbl_student_test(name,fullname,address,city,country,contno)
values
(#name,#fullname,#address,#city,#country,#contno)
end
And for select:
Create proc SEL_tblteststud
as
begin
select * from tbl_student_test
end
Now I want to know, how can I convert these statements(Insert, Select) into functions? And which is better to use stored procedure or function?
You are mixing procedure and function...
A procedure is meant for doing something
A function is meant for reading only
It is not allowed to place data changing commands within a function.
What you are trying is just not possible...
UPDATE Some insight about functions and procedures
There are three types of functions
scalar functions: Return one scalar value and are very bad performing
multi statement table valued functions (with BEGIN ... END): Return a resultset, but are bad performing too
inline table valued functions: They are great, but restricted. Think of them like of a VIEW with pre-compiled parameters
A procedure has a return value too, which is of tpye INT and is not used to return the SP's result, but kind of execution status.
A SP might just do something and return no procedure result at all. If you want to return procedural results you must either use
output parameters
or you must call a SELECT within your SP. It is possible to grab the result of an internal SELECT from outside, but this is very cumbersome...

SQL Server Stored Procedure - Executing different queries by CASE

I have two parameters for my stored procedure. Based on what the value of Searching_Condition is, the proper column must be searched. In a pseudo code format, it should be something like this
//CASE #Search_Condition
// WHEN 'UserID' THEN SELECT * FROM user_table WHERE UserID LIKE '#Keywords'
// WHEN 'UserName' THEN SELECT * FROM user_table WHERE UserName LIKE '#Keywords'
// WHEN 'UserAddress' THEN SELECT * FROM user_table WHERE UserAddress LIKE '#Keywords'
The following is the code I was working on and where got stuck. It should be simple but man... for being not familiar with SQL Server, I'm so struggling with it and CASE in SQL Server doesn't work the way I thought it would.
Thanks !
CREATE PROCEDURE [dbo].[USP_SP_NAME]
#Searching_Condition NVARCHAR(100),
#Keywords NVARCHAR(100)
AS
SET NOCOUNT ON
SET LOCK_TIMEOUT 3000
SET XACT_ABORT ON
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
BEGIN TRY
SELECT
CASE WHEN
#Searching_Condition = 'user_id' THEN
(select count(*) from user_table)
WHEN
#Searching_Condition = 'user_name' THEN
(select * from user_table)
END
END TRY
The key concept that will help you get this right is the difference between expressions and statements.
A statement is procedural and directs the flow of control. You can think of an instruction pointer proceeding from statement to statement, and every statement is isolated from other statements (although they can select which statements after them are executed or not). They can be thought of as verbs.
An expression is something that reduces to a value--a scalar value, a string, or even a rowset--but the expression doesn't command to DO anything. They can be thought of as nouns. These nouns can't exist by themselves, they must be in the context of a statement.
The CASE statement in SQL Server is an expression. It isn't a procedural statement like Select Case is in, for example, Visual Basic. And the trick is, when the language expects an expression, you cannot substitute a statement--and furthermore, except in some special usages, you can't put procedural statements in the middle of expressions (except rowsets that can be evaluated as an expression, such as a single-column and single-row SELECT, or an EXISTS). An expression can contain expressions which contain expressions. They're like a tree, that is collapsed in order all the way down.
Think of the parts in EXECUTE dbo.MyStoredProcedure (8 + ##SPID) / 2: this is a single statement, with one parameter expression, consisting of three sub-expressions, evaluated in a certain order, that resolve to a single value, which is used as an argument to the stored procedure. You could not execute (8 + ##SPID) / 2 by itself, because it isn't a statement. (Never mind that the expression is silly, it is just for example.)
I did say that in some cases rowsets can be values, but the expected type of almost all expressions is a single value--not a rowset. That's the problem that's happening here--your outer SELECT statement is expecting a single value for the definition of the first column in a single row (since you have no FROM clause), but you're trying to provide a whole rowset when your searching condition is 'user_name'.
You can solve this by abandoning CASE entirely and using IF--because IF is a procedural statement.
CREATE PROCEDURE [dbo].[USP_SP_NAME]
#Searching_Condition NVARCHAR(100),
#Keywords NVARCHAR(100)
AS
SET NOCOUNT ON;
SET LOCK_TIMEOUT 3000;
SET XACT_ABORT ON;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
BEGIN TRY
IF #Searching_Condition = 'user_id' BEGIN
select count(*) from user_table;
END
ELSE IF #Searching_Condition = 'user_name' BEGIN
select * from user_table;
END;
END TRY;
I advocate avoiding the version of the IF that doesn't use BEGIN and END and accepts a single statement--this form leads to confusion and bugs. I use BEGIN and END every time, which seems like a pain, until you discover how much time and effort doing so saves you down the road...
You can try this, no need to give cases, where condition will change depending on the value of #Searching_Condition:
CREATE PROCEDURE [dbo].[USP_SP_NAME]
#Searching_Condition NVARCHAR(100),
#Keywords NVARCHAR(100)
AS
SET NOCOUNT ON
SET LOCK_TIMEOUT 3000
SET XACT_ABORT ON
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
BEGIN TRY
exec('Select * from user_table WHERE'+ #Searching_Condition+' LIKE '+ #Keywords);
END TRY

How do I declare and use variables in PL/SQL like I do in T-SQL?

In Sql Server, often times when I'm testing the body of a stored procedure, I copy the body into SSMS, DECLARE the variables at the top of the page, set them to some sample values, and execute the body as-is.
For Example, if my proc is
CREATE PROC MySampleProc
#Name VARCHAR(20)
AS
SELECT #Name
Then my test sql would be
DECLARE #Name VARCHAR(20)
SET #Name = 'Tom'
SELECT #Name
What is the Oracle PL/SQL equivalent to this?
This is the closest that I've come up with, but I'm getting "PLS-00428: an INTO clause is expected in this SELECT statement"
DECLARE
myname varchar2(20);
BEGIN
myname := 'Tom';
select myname from DUAL;
END;
This is a better example of what I'm really trying to do:
DECLARE
myname varchar2(20);
BEGIN
myname := 'Tom';
SELECT *
FROM Customers
WHERE Name = myname;
END;
But again, it wants an 'INTO' when really I just want the records printed on the screen, not stored in another table....
RESOLVED:
Thanks to #Allan, I've got it working well enough. Oracle SQL Developer apparently remembers the parameter values you supply it with. PL/SQL Developer, however, wants nothing to do with this....
If you "Run As Script", it will abide by your defaults, but it will only return results as ASCI text, not in a grid/spreadsheet
Revised Answer
If you're not calling this code from another program, an option is to skip PL/SQL and do it strictly in SQL using bind variables:
var myname varchar2(20);
exec :myname := 'Tom';
SELECT *
FROM Customers
WHERE Name = :myname;
In many tools (such as Toad and SQL Developer), omitting the var and exec statements will cause the program to prompt you for the value.
Original Answer
A big difference between T-SQL and PL/SQL is that Oracle doesn't let you implicitly return the result of a query. The result always has to be explicitly returned in some fashion. The simplest way is to use DBMS_OUTPUT (roughly equivalent to print) to output the variable:
DECLARE
myname varchar2(20);
BEGIN
myname := 'Tom';
dbms_output.print_line(myname);
END;
This isn't terribly helpful if you're trying to return a result set, however. In that case, you'll either want to return a collection or a refcursor. However, using either of those solutions would require wrapping your code in a function or procedure and running the function/procedure from something that's capable of consuming the results. A function that worked in this way might look something like this:
CREATE FUNCTION my_function (myname in varchar2)
my_refcursor out sys_refcursor
BEGIN
open my_refcursor for
SELECT *
FROM Customers
WHERE Name = myname;
return my_refcursor;
END my_function;
In Oracle PL/SQL, if you are running a query that may return multiple rows, you need a cursor to iterate over the results. The simplest way is with a for loop, e.g.:
declare
myname varchar2(20) := 'tom';
begin
for result_cursor in (select * from mytable where first_name = myname) loop
dbms_output.put_line(result_cursor.first_name);
dbms_output.put_line(result_cursor.other_field);
end loop;
end;
If you have a query that returns exactly one row, then you can use the select...into... syntax, e.g.:
declare
myname varchar2(20);
begin
select first_name into myname
from mytable
where person_id = 123;
end;
Variables are not defined, but declared.
This is possible duplicate of declare variables in a pl/sql block
But you can look here :
http://docs.oracle.com/cd/B19306_01/appdev.102/b14261/fundamentals.htm#i27306
http://docs.oracle.com/cd/B19306_01/appdev.102/b14261/overview.htm
UPDATE:
Refer here : How to return a resultset / cursor from a Oracle PL/SQL anonymous block that executes Dynamic SQL?

Dynamically return table with different columns in a User Defined Table Function.

There are several limitations between a SQL Server stored procedure and a user defined function.
UDF's Can't
use nondeterministic functions
change the state of the database
Return messages to the caller
have any side effects
A stored procedure can return multiple record sets and they are not required to return the same fields each time.
create proc custom.sproc_CrazyFields
#ThisItem int
as
begin
if #ThisItem < 10
begin
select 'this' as ThisField, 'that' as ThatField, 'theOther' as theOtherField;
end
else
begin
Select 'theOther' as theOtherField, 'that' as thatField, 'this' as thisField;
end
end
go
exec custom.sproc_CrazyFields 4
exec custom.sproc_CrazyFields 40
An inline function is only going to return a single select statement.
A multistatement function has to declare the returned table.
Is there a way to dynamically return a result with changing columns with a UDF or is this one of the differences?
Sorry, you can't use dynamic SQL in a function. Maybe what you can do is write a stored procedure that creates a function in dynamic SQL, calls the function, then drops it. But then why not just build the query inline at that point.

Resources