I have the following code:
CREATE FUNCTION db_owner.GetComp
(
#CompID bigint,
#ComponentType nvarchar(50)
)
RETURNS TABLE
AS
RETURN /* SELECT ... FROM ... */
IF (#ComponentType = 'WMCOMP') begin
RETURN
SELECT *
FROM WMCOMP
WHERE wmcompid = #CompID
end
ELSE IF (#ComponentType = 'ADECOMP') begin
RETURN
SELECT *
FROM ADECOMP
WHERE adecompid = #CompID
end
When trying to save it in Visual Studio, the following error is displayed:
Incorrect syntax near IF
I simply cannot see what is wrong. Any help will be appreciated.
Try this one -
CREATE FUNCTION db_owner.GetComp
(
#CompID bigint
, #ComponentType nvarchar(50)
)
RETURNS #Result TABLE (col1 INT, ...)
AS
BEGIN
INSERT INTO #Result (col1, ...)
SELECT *
FROM (
SELECT *
FROM dbo.WMCOMP
WHERE wmcompid = #CompID
AND #ComponentType = 'WMCOMP'
UNION ALL
SELECT *
FROM dbo.ADECOMP
WHERE adecompid = #CompID
AND #ComponentType = 'ADECOMP'
) f
RETURN
END
You have a missing comma in param list:
CREATE FUNCTION db_owner.GetComp
(
#CompID bigint, --<--- need a comma here
#ComponentType nvarchar(50)
)
Related
I have 800+ functions in my database. I would need to modify their source databases dynamically and create snapshots.
example of the function:
create function [schema1].[funTest1] (#param1 varchar(50))
returns table as
return
(
select * from [curr_database1].[schema1].[funTest1](#param1)
union
select * from [curr_database2].[schema1].[funTest1](#param1)
)
I want to change the script as:
create or alter function [schema1].[funTest1] (#param1 varchar(50))
returns table as return
(
select * from [new_database2].[schema1].[funTest1](#param1)
union
select * from [new_database3].[schema1].[funTest1](#param1)
)
basically, I got all the functions script using the sys.syscomments. I'm looking for an option to find and replace the database dynamically to create the snapshots.
How can I get it? Thank you!
Here is the sample code that I have developed for sharing. All the database in the functions starts with the same text(for ex. "curr"). Please share your thoughts. Thanks in advance!
create or alter proc test_proc as
begin
set nocount on
-- this piece of code has the new databases
if object_id('tempdb..#dbNames') is not null drop table #dbNames
create table #dbNames (dbName varchar(1000), id int)
insert into #dbNames(dbName, id) values ('new_database2', 1),('new_database3', 2)
insert into #dbNames(dbName, id) values ('new_database8', 3),('new_database9', 4)
-- this one has the sample functions
if object_id('tempdb..#dbFunctions') is not null drop table #dbFunctions
create table #dbFunctions (funText nvarchar(max))
insert into #dbFunctions (funText) values('create function [schema1].[funTest1] (#param1 varchar(50))
returns table as
return
(
select * from [curr_database1].[schema1].[funTest1](#param1)
union
select * from [curr_database2].[schema1].[funTest1](#param1)
)'),
('create function [schema2].[funTest2] (#param1 varchar(50), #param2 varchar(100))
returns table as
return
(
select * from [curr_database4].[schema2].[funTest2](#param1, #param2)
union
select * from [curr_database5].[schema2].[funTest2](#param1, #param2)
)')
-- declare variables and assign value for #frmStr variable (for testing purposes)
declare #str nvarchar(max)
declare #dbName varchar(100)
declare #frmStr varchar(100) = '[curr_database1]'
-- get the total count of the databases and the functions to iterate and replace the string
declare #dbCnt int = (select count(id) from #dbNames)
declare #fnCnt int = (select count(*) from #dbFunctions)
while #dbCnt > 0
begin
set #dbname = (select dbname from #dbnames where id = #dbcnt)
while #fnCnt > 0
begin
-- this is where I would need to replace the code
select #str = replace(funText, #frmStr, #dbName) from #dbFunctions
select #str
set #fnCnt = #fnCnt - 1
end
set #dbCnt = #dbCnt - 1
end
end
Your actual goal isn't clear, but to answer the question you asked, you can use REPLACE functions in the query to syscomments that you used to get the code in the first place:
REPLACE(
REPLACE([FunctionTextColumn],'curr_database1','new_database2')
,'curr_database2','new_database3'
)
I have this one: (updated)
IF OBJECT_ID (N'dbo.fn_getProductCatPurchased', N'IF') IS NOT NULL
DROP FUNCTION [dbo].fn_getProductCatPurchased;
GO
then the function starts:
CREATE FUNCTION [dbo].fn_getProductCatPurchased
(
#Custno varchar(100),
#PriceType varchar(100)
)
RETURNS int
AS
BEGIN
DECLARE #groups int;
SELECT #groups = COUNT(DISTINCT(prodcat))
FROM SALES
WHERE custno = #Custno
AND pricetype=#PriceType
IF (#group IS NULL)
SET #group = 0;
RETURN #group;
END;
GO
When I try to save the function an error was thrown:
Incorrect syntax near fn_getProductCatPurchased
What am I doing wrong?
Not sure if this is the cause of your error, but it's definitely a problem.
You are declaring a variable called #groups:
DECLARE #groups int;
but proceed to use #group without an s instead:
IF (#group IS NULL)
SET #group = 0;
RETURN #group;
is it possible in T SQL to use a function as a while parameter? I have the following code:
create function LoginExists (#p_login char(6))
returns varchar(5)
begin
if exists(select * from Student where student.slogin = #p_login)
return 'true'
return 'false'
end;
and
create procedure AddStudent2
(#p_fname varchar(30), #p_lname varchar(50), #p_tallness int)
as
declare #p_login char(6), #p_email varchar(50), #suffix char(3);
set #p_lname = LOWER(#p_lname);
set #suffix = '000';
begin
set #p_login = substring(#p_lname,1, 3) + #suffix;
while (LoginExists #p_login = 'true')
set #suffix = cast((CAST(#suffix as int) + 1) as char(3));
set #p_login = substring(#p_lname,1, 3) + #suffix;
set #p_email = #p_login + '#vsb.cz';
insert into Student values (#p_login, #p_fname, #p_lname, #p_email, #p_tallness);
end;
and when trying to compile it, an error occurs, saying: "Incorrect syntax near '#p_login'."
Your syntax for calling a function is in fact incorrect:
Replace:
while (LoginExists #p_login = 'true')
with:
while (dbo.LoginExists (#p_login)= 'true')
Replace
if exists(select * from Student where student.slogin = #p_login)
by
if exists(select * from Student where Student.slogin = #p_login)
Upper 'S' in student.slogin and i hope it work
My stored procedure parameter contains more than 2 values (eg: create stored procedure recentAssetList #recentAssetList = (id1,id2,..)) then with these parameter how can I get data from a table?
SQL Server doesn't support that logic. Here are some options:
1. Split them amongst many parameters
create procedure yourProc
#FirstParam varchar(10),
#SecondParam varchar(10)
as
-- etc.
go
If some of these parameters may be null you can do this:
create procedure yourProc
#FirstParam varchar(10) = null,
#SecondParam varchar(10) = null
as
select *
from yourTable
where
((#FirstParam is null) or (SomeCol1 = #FirstParam)) and
((#SecondParam is null) or (SomeCol2 = #SecondParam))
go
2. Pass a read only table
create type yourTableData
as table
(
id int not null
)
go
create procedure yourProc
#yourInput yourTableData readonly
as
select *
from yourTable
where id in
(
select id
from #yourInput
)
go
You can use splittion function like that and pass the values in comcatenated string:
CREATE function [dbo].[csv2tbl](#list nvarchar(max), #delimiter nvarchar(10))
returns #res table ([index] int PRIMARY KEY, col nvarchar(max))
AS BEGIN
with tbl_for_csv as
(
select 0 as [index] ,left(#list + #delimiter+#delimiter,charindex(#delimiter,#list + #delimiter+#delimiter) -1)as col,
right(#list + #delimiter+#delimiter,len(#list + #delimiter+#delimiter) - charindex(#delimiter,#list + #delimiter+#delimiter)) as Str
union all
select [index]+1, left(Str,charindex(#delimiter,Str) - 1)as Col,
right(Str,len(Str) - charindex(#delimiter,Str)) from tbl_for_csv
where len(right(Str,len(Str) - charindex(#delimiter,Str))) > 0
)
INSERT #res
select [index], col from tbl_for_csv option (MAXRECURSION 0);
return;
END
In sql2008+ you can pass values to SP thru user defined table types variable (see #Shark answer)
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
How to best split csv strings in oracle 9i
can you help me convert following T-SQL funcntion into Oracle. The function converts a string like
service|nvretail;language|de;yyyy|2011;
to a table.
The main problem I have is the usage of the temp table. I could not find any equivalent to it in Oracle.
CREATE FUNCTION [dbo].[TF_ConvertPara]
(
#parastringNVARCHAR(max)
)
RETURNS #para TABLE
(
[Key] varchar(max),
[Value] varchar(max)
)
begin
DECLARE #NextString NVARCHAR(40)
DECLARE #Pos1 INT
DECLARE #Pos2 INT
DECLARE #NextPos INT
DECLARE #Delimiter1 NCHAR=';'
DECLARE #Delimiter2 NCHAR='|'
if substring(#paraString, len(#paraString) - 1, 1) <> #Delimiter1
SET #paraString = #paraString + #Delimiter1
SET #Pos1 = charindex(#Delimiter1, #paraString)
WHILE (#pos1 <> 0)
BEGIN
SET #NextString = substring(#paraString, 1, #Pos1 - 1)
SET #paraString = substring(#paraString, #pos1 + 1, len(#paraString))
SET #pos1 = charindex(#Delimiter1, #paraString)
SET #Pos2 = charindex(#Delimiter2, #NextString)
if (#Pos2 > 0)
begin
insert into #para
values
(substring(#NextString, 1, #Pos2 - 1),
substring(#NextString, #Pos2 + 1, len(#NextString)))
end
END
return;
end
Thank you in advance.
If you are looking to return the tokens of your string as rows then you could do it all in a single SQL query:
WITH t AS (SELECT 'service|nvretail;language|de;yyyy|2011;' as val FROM dual)
SELECT row_output
FROM t,
XMLTABLE( '/root/e/text()'
PASSING xmltype( '<root><e>' ||
REGEXP_REPLACE (t.val, '(;|\|)', '</e><e>' ) ||
'</e></root>' )
COLUMNS row_output VARCHAR2( 4000 ) PATH '/');
Returns:
service
nvretail
language
de
yyyy
2011
If you want these rows in a table then wrap the SQL in a simple function to either return the in-memory table or insert the records into a DB table, whichever you need.
Here is an example of a function returning a table (collection) of VARCHAR2 records:
CREATE OR REPLACE
FUNCTION str_to_table (
p_input_str IN VARCHAR2
)
RETURN DBMS_SQL.VARCHAR2_TABLE
IS
CURSOR str_to_rows (
cp_str IN VARCHAR2
)
IS
SELECT row_output
FROM (SELECT cp_str as val FROM dual) t,
XMLTABLE( '/root/e/text()'
PASSING xmltype( '<root><e>' ||
REGEXP_REPLACE(t.val, '(;|\|)', '</e><e>') ||
'</e></root>' )
COLUMNS row_output VARCHAR2( 4000 ) PATH '/');
varchar_tab DBMS_SQL.VARCHAR2_TABLE;
BEGIN
OPEN str_to_rows(p_input_str);
FETCH str_to_rows BULK COLLECT INTO varchar_tab;
CLOSE str_to_rows;
--
RETURN varchar_tab;
EXCEPTION
WHEN others
THEN
IF str_to_rows%ISOPEN
THEN
CLOSE str_to_rows;
END IF;
RAISE;
END str_to_table;
It's untested so there may be a couple of syntax errors but it should be prety close.
To return a ref cursor:
CREATE OR REPLACE
FUNCTION str_to_table (
p_input_str IN VARCHAR2
)
RETURN sys_refcursor
IS
cur SYS_REFCURSOR;
BEGIN
OPEN cur
FOR SELECT row_output
FROM (SELECT p_input_str as val FROM dual) t,
XMLTABLE( '/root/e/text()'
PASSING xmltype( '<root><e>' ||
REGEXP_REPLACE (t.val, '(;|\|)', '</e><e>' ) ||
'</e></root>' )
COLUMNS row_output VARCHAR2( 4000 ) PATH '/');
--
RETURN cur;
END str_to_table;
Hope it helps...
To return the key value pairs, How about this (for Oracle 10g and above):
CREATE OR REPLACE FUNCTION csv_to_rows(mycsv IN VARCHAR2)
RETURN sys_refcursor
AS
c SYS_REFCURSOR;
BEGIN
OPEN c FOR
SELECT SUBSTR(element,1,INSTR(element,'|')-1) as key ,
SUBSTR(element,INSTR(element,'|')+1,99999) as val
FROM (
SELECT REGEXP_SUBSTR(mycsv,'[^;]+',1,LEVEL) element
FROM dual
CONNECT BY LEVEL < LENGTH(REGEXP_REPLACE(mycsv,'[^;]+')) + 1
);
RETURN c;
END;
and to see your results:
DECLARE
c SYS_REFCURSOR;
akey VARCHAR2(100);
aval VARCHAR2(100);
BEGIN
c := csv_to_rows('service|nvretail;language|de;yyyy|2011');
LOOP
FETCH c into akey,aval;
EXIT WHEN c%NOTFOUND;
dbms_output.put_line('Key : '||akey || ' Value : '||aval);
END LOOP;
END;
this should give you
Key : service Value : nvretail
Key : language Value : de
Key : yyyy Value : 2011