PostgreSQL stored procedures - c#

I'm new to PostgreSQL. I have a winforms app thats calling to a PostgreSQL db. Instead of passing in the query, id rather use PostgreSQL paramaterised stored procedures. I am able to all and get a return for a parameterless stored procedure but when I add parameters and execute the call, I get an error saying that coloumn userId doesn't exist.
userid is the parameter.
On PostgreSQL, when creating the sp, I also create an IN argument with that thats same rype and name.
What am I missing here?
The sql is a simple:
select * from public.users u where u.userid = userid.

use it to identify a parameter in SQL:
Select * from public.users u where u.userid = #userid

You indicated that you "create an IN argument with that thats same (t)ype and name". That is not quite what you do want to do. While you do want the type to be the same the name must either different or qualified by the function name. If it the same you will get all rows as the intended parameter name will be interpreted as the column name; basically resulting in:
Select * from table_name where column_name = column_name;
Which is true whenever the value isn't null. Now there are 2 approaches, using userid and assuming its unique:
create or replace function get_user(userid_in users.userid%type)
returns setof users
language sql
as $$
select *
from users where userid = userid_in ;
$$;
OR
create or replace function get_user(userid users.userid%type)
returns setof users
language sql
as $$
select *
from users where userid = get_user.userid ;
$$;

Related

Returning values from a SQL Server stored procedure?

I want to know whether there is any way besides the OUT parameter to get data from stored procedure into C# code.
Today my colleague told me that all select queries and the OUT parameters in a stored procedure are returned to the C# code. Is this correct? If yes, then how do I choose which results should be returned?
Is the answer same in case of VB6 code instead of c#?
Yes you can return values back to your application from a SP using either OUT parameters or a SELECT within the SP.
The OUT parameters are generally used for single values. The SELECT can be used for returning rows of results. A combination of both can be used in many different variations, such as the SP will return rows and a status OUT parameter can indicate row count or existence of the requested data.
CREATE PROC usp_MySpecialSP
#conditionValue INT, #SPStatus INT OUT
AS
IF EXISTS(SELECT * FROM TableName WHERE column1=conditionValue)
BEGIN
SELECT #SPStatus=COUNT(*) FROM TableName WHERE column1=conditionValue
SELECT Column2, Column3, Column4 FROM TableName WHERE column1=conditionValue
END
ELSE
BEGIN
SELECT #SPStatus=0
END
GO
Here you can pickup values if the m_SPStatusReturned>0.
Check out below MSDN article how to pick up returned rows from SP
http://msdn.microsoft.com/en-us/library/d7125bke.aspx
or a single value using SELECT
http://msdn.microsoft.com/en-us/library/37hwc7kt.aspx
Yes it is correct - and the way you handle this is:
to get an OUT parameter, you need define a SqlParameter on your SqlCommand with ParameterDirection.Output
to get the result set of the SELECT in a stored procedure, you need to use a SqlDataReader or a SqlDataAdapter to get the results (as if you execute an inline SQL SELECT query)
and there's actually a third way : the RETURN keyword inside a stored procedure - typically used to return a numeric status value. You can capture that by using a SqlParameter with a value of ParameterDirection.ReturnValue

How to create a SQL function using C#

I want to define a function to get "order number" parameter and return "last name" of the customer.these two parameters are in different tables i am using inner join.
the errors i am getting are: Incorrect syntax near (.
Incorrect syntax near the keyword RETURN.
Must declare the scalar variable #FindingLastName.
my code:
com.CommandText = "Create function Sales.FindingLastName (#OrderNumber varchar(10)) Returns nvarchar(50) As Begin Declare #FindingLastName(Select LastName from Sales.OrderDetails INNER JOIN Sales.Customers RETURN #FindingLastName END GO)";
com.Connection = con;
MessageBox.Show(com.ExecuteNonQuery().ToString());
You have lot of things missed in your SQL Syntax. Have a look at below SQL Syntax Change the ColumnNameto actual columnnames in join statement. May be you want to modify the select condition accordingly by adding WHERE clause.
Create function Sales.FindingLastName
(#OrderNumber varchar(10))
Returns nvarchar(50) As
Begin
Declare #FindingLastName varchar(50) =
(Select LastName from Sales.OrderDetails O INNER JOIN Sales.Customers C ON C.ColumnName =O.ColumnName)
RETURN #FindingLastName
END
One more question You can run this only once. Once the function is created, you can't create same function again. So i doubt are you sure you want to do it this way via c#?? !!
For more details on User Defined function in SQL Refer THIS LINK
What stands out there is the GO. Firstly, GO is not SQL. It only exists to tools like SSMS (etc), which use it to split a long script into separate commands. Inside an actual command, it is simply a syntax error. Consequently, GO can never appear inside nesting such as parenthesis, or a BEGIN / END block.
Basically, remove the GO.
However, it is pretty rare to use DDL inside ADO.NET, unless part of an automated schema migration tool etc.
I'm no hero with SQL, but i think this should work
Create function Sales.FindingLastName (#OrderNumber varchar(10))
RETURNS nvarchar(50)
As
RETURN
(
Select LastName
from Sales.OrderDetails INNER JOIN Sales.Customers
);

using sqlcommand with multiple ids

So this works great:
select name from users where id = #id
However, that only selects 1 guy. Say I have 3 IDs instead, normally the SQL would look something like this (without using parameters)
select name from users where id in (4,6,9)
However, it doesn't seem to work when I write
select name from users where id in (#IDs)
and insert a list into #IDs, like this
cmd.Parameters.AddWithValue("#IDs", userIDs);
Is there any way to do what I'm trying to? It's important to note that the sql I'm calling is (and has to be) a stored procedure.
There are two ways to do this. The first is by passing a string to a stored procedure and then adding it to a dynamic query:
-- #IDs = '4,6,9'
DECLARE #MyQuery nvarchar(max)
SET #MyQuery = N'SELECT name FROM users WHERE id IN (' + #IDs + ')'
EXEC(#MyQuery)
On the other hand, if you are using SQL Server 2008 or later, you can use a table-valued parameter (this is my preference).
First, create a user-defined table type:
CREATE TYPE IDList AS TABLE (
id int
)
THEN, use the user defined type as the type for your parameter:
DECLARE #IDs IDList
INSERT INTO #IDs (ID) VALUES (4),(6),(9)
SELECT name FROM users u INNER JOIN #IDs i WHERE u.id = i.id
If you are using .NET to consume a stored procedure, you can find sample code for user-defined SQL types on MSDN.
You can create a dynamic SQL query inside your stored procedure:
DECLARE #SQLQuery AS NVARCHAR(500)
SET #SQLQuery = 'select name from users where id in ( ' + #userIDs + ')'
EXECUTE(#SQLQuery)
You'll have to be careful and sanitize the contents of #userIDs though to prevent SQL injection attacks.
On our side we are using iBatis.Net to manage this. Execute query sounds quite ugly but it still does the trick.
We were mostly using string split in SQL. See [question]How do I split a string so I can access item x?

Passing an array/table to stored procedure through Entity Framework

I am using Entity Framework with C# to make a Silverlight application. I have written some stored procedures which perform database intensive operations and I need to call them from Entity Framework after passing some parameters. In one of the steps, the users select a list of items for which they would need more details. This list of items (in the form of an array of integer IDs) need to be passed to the stored procedure to retrieve more information about those IDs. How do I pass this parameter to the stored procedure?
You can't pass table-valued parameters to SQL with the Entity Framework.
What you can do is create a delimited string like "1|2|3|4" and create a Split function in SQL that will return a table.
CREATE FUNCTION dbo.Split
(
#RowData nvarchar(2000),
#SplitOn nvarchar(5)
)
RETURNS #RtnValue table
(
Id int identity(1,1),
Data nvarchar(100)
)
AS
BEGIN
Declare #Cnt int
Set #Cnt = 1
While (Charindex(#SplitOn,#RowData)>0)
Begin
Insert Into #RtnValue (data)
Select
Data = ltrim(rtrim(Substring(#RowData,1,Charindex(#SplitOn,#RowData)-1)))
Set #RowData = Substring(#RowData,Charindex(#SplitOn,#RowData)+1,len(#RowData))
Set #Cnt = #Cnt + 1
End
Insert Into #RtnValue (data)
Select Data = ltrim(rtrim(#RowData))
Return
END
Then if you need to do something like select all items from a table based on what is in the delimited string passed to your proc:
SELECT * FROM SomeTable WHERE Id IN (SELECT Id FROM dbo.Split(#DelStr, '|'))
If you are using SQL Server, which I assume is the case, you can create use a table valued parameter to do what you wish. Using a table valued parameter prevents you from parsing an input parameter within the stored procedure and removes the threat of a SQL injection attack by eliminating the use of dynamic SQL.
Here is a great blog article that covers how to do what you wish to do.
Using Table-Valued Parameters in SQL Server 2008 and C#
Is this what you were looking for?

How does MSLinqToSqlGenerator determine the return type of a stored procedure?

I have a stored procudre (SP) as follows:
CREATE PROCEDURE [dbo].[UDSPSelectMissing]
-- paramters omitted
AS
BEGIN
-- Code Omitted
SELECT
c.MemberID,
c.FirstName,
c.MiddleName,
c.LastName,
c.Suffix,
c.PhoneHome,
c.PhoneCell,
c.Email
FROM [dbo].[Members] c
WHERE c.MemberID IN (SELECT MemberID FROM #PeopleCameMissing)
ORDER BY c.LastName,c.FirstName
END
When I added the SP to the SP pane of "dbml" designer, I was expecting MSLinqToSqlGenerator to create "ISingleResult" as return value type. To my surprise, the return value type is "int". Clearly, the generator is using certain criteria to determine the return value type. I have other similar SPs that returns "ISingleResult" type.
Does anybody know what would cause the generator to behave this way?
By the way, somebody on this site suggested recreating the SP, removing the reference from "dbml", restarting Visual Studio (VS) and adding to it to "dbml" again. I went through all that to no avail.
My suspicion lies with the temporary table "#PeopleCameMissing".
Any comments or suggestions are most welcome!
Thanks,
Cullen
I mentioned in my original post that I suspected the temp table. The temp table was created by "SELECT INTO #PeopleCameMissing" command therefore its definition is dynamic so when the stored procedure is added to "dbml" designer, the generator has no clue about the table's definition. What if I let the table definition known to the generator, maybe I'd be able to get the desired return type. Based on this conjecture, I ran a test. I declared a table as follows:
DECLARE #PeopleCameMissing TABLE(
MemberID int,
FirstName nchar(20),
MiddleName nchar(20),
LastName nchar(20),
Suffix nchar(10),
PhoneHome nchar(20),
PhoneCell nchar(20),
Email nchar(80)
);
And changed the original statement as follows:
INSERT INTO #PeopleCameMissing (
MemberID,
FirstName,
MiddleName,
LastName,
Suffix,
PhoneHome,
PhoneCell,
Email)
SELECT
c.MemberID,
c.FirstName,
c.MiddleName,
c.LastName,
c.Suffix,
c.PhoneHome,
c.PhoneCell,
c.Email
FROM [dbo].[Members] c
WHERE c.MemberID IN (SELECT a.MemberID FROM #PeopleCameMissing a)
ORDER BY c.LastName,c.FirstName;
DROP TABLE #PeopleCameMissing;
SELECT *
FROM #PeopleCameMissing
ORDER BY LastName,FirstName;
And then I added the stored procedure to "dbml" designer again. This time the generator created the desired return type: "ISingleResult". It seems to prove my conjecture.
It's quite simple (under special conditions).
SQL allows you to interrogate the resultset schema without calling a procedure.
Under the not so special conditions*, SQL will give you alternate answers on every invocation.
* Those with IF statements. This may be intentional. I dont know SQL well enough to answer that.

Categories

Resources