Passing parameter to IN SQL statement - asp.net

I collected some values to be looked up from a DB column inside a string variable and was trying to pass this as a parameter in the SQL StoredProcedure.
ALTER PROCEDURE [dbo].[InkDB]
(
#ser nvarchar(255),
#svt nvarchar(255)
)
AS
SELECT DISTINCT Details from tbData WHERE (Name IN #svt AND Address=#ser)
This gives me a syntax error near #svt message while trying to run the query.
From my webpage, the parameter has value something like ('PersonA', 'Person B', 'Person C') that is being passed. How do I use the IN statement in this case?

I would do it with XML. Could not find this solution in the duplicate question so I add it here.
Your SP could look like this:
alter procedure InkDB
#ser nvarchar(255),
#svt xml
as
declare #T table
(
Name nvarchar(50)
)
insert into #T
select T.N.value('.', 'nvarchar(50)')
from #svt.nodes('/N') as T(N)
select distinct Details
from tbData
where Name in (select Name from #T) and
Address=#ser
And you would call it like this.
exec InkDB '', '<N>PersonA</N><N>PersonB</N>'

Dynamic Query
Alter procedure test
(
#ser nvarchar(255),
#svt nvarchar(255)
)
AS
BEGIN
declare #sql nvarchar(Max)
Set #sql='SELECT DISTINCT semester_code from mst_paper WHERE course_code IN ('+#svt+') AND branch_code='+#ser+''
exec sp_executesql #sql
END

Its a common mistake - you are passing a single value (expression) of type string to IN operator but IN expects a comma delimited list of values (expressions) and not a single string variable.
What you need to do here is to have a function that would split the given parameter into a multiple values based on given delimiter and then use that list with IN keyword. For example,
SELECT DISTINCT Details from tbData WHERE Name IN (SELECT Val FROM dbo.efn_Split(#svt, ',')) AND Address=#ser
where efn_Split is a table value function that will split comma-separated values into a table. See these various SO questions for implementation of such function:
Split function equivalent in T-SQL?
How to split string using delimiter char using T-SQL?
Yet another alternative is to construct the SQL statement and execute with sp_executesql.

IN needs to be as follows:
... IN (#param1, #param2, ...)
So, you should do:
SELECT DISTINCT Details from tbData WHERE Name IN (#svt) AND Address=#ser
Update:
The alter procedure statement you provided in your question is syntactically incorrect. My answer provides the correct syntax for writing the statement and it compiles.
Reading your question over again, I see you have in fact have two issues. The first was a syntax error and the second passing in a comma delimited list in a single parameter.
The answer is you simply cannot provided a comma delimited list of values at runtime into a single string type parameter that is used in the IN (...) clause. Now, on this second point, I would argue that this is not a good design/programming approach to the problem, but it can be done using dynamic SQL or parsing out each value from the string parameter, store them into a temp table then revise your query to join to that, or use a (or use a table valued function and store the parsed items there, where it can be queried from.
Below is the corrected syntax for your code, but it would not solve the second aspect of passing in a string containing a comma delimited list of values. That could be solved as I described above.
For the syntax error, first, you can create a dummy table to test your code. Note, a typical database table should have a primary key. This is strictly a dummy table to test the statement:
CREATE TABLE TbData(
Name nvarchar(255),
Details nvarchar(255),
Address nvarchar(255)
);
Then, you can create the initial stored procedure:
CREATE PROCEDURE Test
(
#ser nvarchar(255),
#svt nvarchar(255)
)
AS
BEGIN
SELECT DISTINCT Details FROM tbData WHERE Name IN (#ser) AND Address = #svt
END
And finally, execute the alter stored procedure statement you had asked about:
ALTER PROCEDURE Test
(
#ser nvarchar(255),
#svt nvarchar(255)
)
AS
BEGIN
SELECT DISTINCT Details FROM tbData WHERE Name IN (#ser) AND Address = #svt
END

Related

Inserting from an object into another object

From table abc i am inserting values in the object abc_type now i'm trying
to insert form abc_type to abc_second object on some condition.While doing
his i'm getting error that this is not a table.Is it even possible to fetch
data from an object and insert into another one.
create table abc(id number,name varchar2(50));
create or replace type abc_obj as object(id number,name varchar2(50) ) ;
create or replace type abc_ref as table of abc_obj;
declare
abc_type abc_ref := abc_ref();
abc_second abc_ref := abc_ref();
begin
select abc_obj(id ,name)
bulk collect into abc_type
from abc;
insert into table(abc_second) select * from abc_type where id=1;
end;
Unfortunately, Oracle user the term "table" in 3, or more, totally different contexts. When you "create table ...' you build the definition of an object in which to persist data, this is the normal use for the term. However, when you use the form "... table of ...' you define an pl/sql collection (array) for holding data inside pl/sql. In this case you have created a "nested table" (3rd use of table). (Note: Some collection types can be declared as column attributes on tables.)
While not identical there are multiple issues with your object definitions as well.
You did not explain the intended use for "second_table" but it seems you merely a
copy of the data from "abc". This can be achieved in multiple ways. If it is basically a one time process then just
create table second_table as select * from abc;
If this is an ongoing action then
create table second_table as select * from abc where 1=0;
-- then when ever needed
insert into second_table select * from abc;
If neither of these satisfy your intended use please expand your question to explain the intended use.

Function returning varchar inside select

Trying to generalize the SQL what splits a string/varchar into records. Here is the working SQL:
SELECT test.* FROM test JOIN (
SELECT level nbr, REGEXP_SUBSTR('1,3', '(.*?)(,|$)', 1, level, NULL, 1) value
FROM dual CONNECT BY level <= REGEXP_COUNT('1,3', ',')+1 ORDER BY level
) requested ON test.id=requested.value
What I mean by generalizing is; moving the recurring SQL (in this case the bit between the parenthesis's from the working SQL above) to a procedure/function so it can be reused. In this case I'm trying to find a way to insert a generated inner select statement. This is how the generalized SQL may look like:
SELECT t.* FROM table t JOIN (<GENERATED_INNER_SELECT>) my ON t.x=my.x;
However I didn't succeed yet, I tried tho but calling my function to generate the inner select statement directly resulted in:
ORA-00900: invalid SQL statement
And using the function in the generalized SQL resulted in:
ORA-00907: missing right parenthesis
None of these errors make any sense to me in this context.
Perhaps you can help? check out the full case on dbfiddle.
If you generate a SQL fragment to use as a subquery then the overall statement that embeds that as a subquery would have to be executed dynamically too.
It would be simpler to have the function actually doing the split itself, and returning a collection - as a schema-level collection type:
CREATE TYPE T_NUMBERS AS TABLE OF NUMBER
/
CREATE OR REPLACE FUNCTION split(p_string VARCHAR2, p_seperator VARCHAR2 DEFAULT ',')
RETURN T_NUMBERS AS
L_NUMBERS T_NUMBERS;
BEGIN
SELECT REGEXP_SUBSTR(p_string, '(.*?)(,|$)', 1, level, NULL, 1)
BULK COLLECT INTO L_NUMBERS
FROM dual
CONNECT BY level <= REGEXP_COUNT(p_string, ',')+1;
RETURN L_NUMBERS;
END split;
/
SELECT * FROM TEST
WHERE id MEMBER OF (split('1,3'))
/
ID NAM
---------- ---
1 foo
3 foe
or if you prefer the table collection expression approach:
SELECT t.*
FROM TABLE(split('1,3')) tmp
JOIN test t ON t.id = tmp.column_value;
It would be even simpler if the query could be called with a collection of numbers in the first place, but without seeing how the call is being made - and the string generated - it's hard to say exactly how you'd need to change that. You could even use a built-in collection type then, instead of having to define your own:
SELECT t.*
FROM TABLE(SYS.ODCINUMBERLIST(1,3)) tmp
JOIN test t ON t.id = tmp.column_value;
but it relies on the caller being able to pass the numbers in rather than a string (note the lack of single quotes...)

Casting a String to a Symbol in PLSQL

I've created an anonymous PLSQL block to test and I'm running into an issue with the formatting.
set serveroutput ON
BEGIN
FOR I IN (SELECT DISTINCT do.SUBOBJECT_NAME from dba_objects do WHERE do.object_name='MY_TABLE' AND do.OBJECT_TYPE='TABLE PARTITION') LOOP
dbms_output.put_line(I.subobject_name);
SELECT
t.field
INTO
some_var
FROM
MY_TABLE PARTITION(I.subobject_name) t;
END LOOP;
END;
However I get several compilation errors, which I believe are related to the fact that I.subobject_name is a string. I believe the PARTITION function wants an actual partition symbol(proper term for this?), but I can't give it in this loop.
Is there any kind of casting function that can perform what I'm looking for?
Partition IS NOT A FUNCTION. Partition is keyword
In your context your whole statement is static , thus you CANNOT pass partition name into it; partition name must be specified at compile time.
You can re-create your statement dynamically and then pass partition name in the loop -
a-la you are doing it. Just make sure you will concatenate string and not use bind variables, or your statement at run time won't be parsed and won't run.
Name for the symbol is table partition

Stored procedure - Multiple string parameters with IN clause sql

i want to filter the rows using Stored procedure. below is my query
Create PROCEDURE [dbo].[Test]
#SearchTerm VARCHAR(100)
AS
BEGIN
Select * from master where name in (#SearchTerm)
END
In code behind,
cmd.Parameters.AddWithValue("#SearchTerm", "peter")
when i run with above parameter, it's work fine.
but when i pass like this
cmd.Parameters.AddWithValue("#SearchTerm", "'peter','rahul'")
this time no rows fetching.
i tried manually then also it's not working.
exec Test ''peter','rahul''
Please help me, how to pass muliple string Using IN clause?
One method is
Create PROCEDURE [dbo].[Test]
#SearchTerm VARCHAR(100)
AS
BEGIN
Select * from master where ','+#SearchTerm+',' like '%,'+name+',%'
You can find more methods at http://www.sommarskog.se/arrays-in-sql-2008.html

In Oracle Stored Procedure I am passing parameter as String to check the IN condition. This is not yielding results

pInCon I am passing as ('1','2')
create or replace
PROCEDURE proc1
(
pInCon in Varchar2,
P_RECORDSET OUT SYS_REFCURSOR
) AS
BEGIN
open P_RECORDSET for
SELECT col1,col2
FROM table1
WHERE col1 IN pInCon;
END proc1;
But when I do a select, I am seeing values. Pls help
Assuming that your intention is to pass in multiple values rather than a single string that contains single quotes, commas, etc. the best option would be to pass in an actual collection. Something like
CREATE TYPE num_table
AS TABLE OF NUMBER;
CREATE OR REPLACE PROCEDURE proc1( p_in IN num_table,
p_recordset OUT sys_refcursor )
AS
BEGIN
OPEN p_recordset
FOR SELECT col1, col2
FROM table1
WHERE col1 IN (SELECT column_value FROM TABLE( p_in ));
END;
If you really need to pass in a string of comma-separated values rather than a collection, you could parse the string that is passed in into a collection in your stored procedure. Tom Kyte has the canonical post on handling variable IN lists that walks through that approach.
It is also possible to use dynamic SQL. That has numerous downsides, though. It is slower, it likely makes other things running in this database slower by flooding the shared pool with non-sharable statements, it introduces the potential for SQL injection attacks, etc.

Resources