10

I have a requirement to run a query against a database that will return either a zero or one (Checking for existance of specific criteria). The Tech specs I've been given for review state that I should be creating a stored procedure, that will return a single row, with a single column called "result" that will contain a bit value of 0 or 1. However, I'm not sure that a stored procedure would be the best approach, but am a little unsure so thought I'd ask for you opinions. The two options I can think of are:

1: Create a SQL scalar-valued function that performs the query and returns a bit. This could then be called directly from within the .Net client application using a "TEXT" SqlCommand object, and it would return a bool from the "ExecuteScalar()" method.

2: Create a stored procedure as described in the tech specs. This would then be called from the .Net Client app in the normal manner, and would return a DataTable with a single row and single column, that contains the bit value.

To me, option one seems the best. However, something in the back of my head is saying this isn't such a good idea.

Please could you give your opinions and help relieve my concerns? :)

Cheers, Ian

Sk93
  • 3,676
  • 3
  • 37
  • 67
  • For a single result like this, using a DataReader or DataAdapter is overkill. Go with the ExecuteScalar() approach. – Jeff Schumacher Jun 10 '10 at 09:41
  • Thanks Jeff - I wasn't actually aware you could do this against a stored procedure until one of the answers below came in :) – Sk93 Jun 10 '10 at 09:42

6 Answers6

14

Execute the Stored Procedure using the ExecuteScalar() method. You can then cast the result of this to a boolean.

e.g

   SqlConnection con = new SqlConnection(connectionString);
    SqlCommand com = new SqlCommand("Execute dbo.usp_MyStoredProc", con);
    return (Boolean)com.ExecuteScalar();
codingbadger
  • 42,678
  • 13
  • 95
  • 110
  • Whilst I like this method, TcKs' comments on his answer have convinced me that, in this scenario, I shouldn't be using a stored procedure as a function, but rather a function as a function. But thanks anyway - I've learned something new from your answer regardless :) – Sk93 Jun 10 '10 at 14:17
9

This works for me and is based on this answer https://stackoverflow.com/a/3232556/1591831 using a SqlDataAdapter (note that you do not need to use one) and ExecuteScalar (can use ExecuteNonQuery as shown here):

bool res = false;
using (SqlConnection conn = new SqlConnection(GetConnectionString()))
{
    using (SqlCommand comm = new SqlCommand("dbo.MyFunction", conn))
    {
        comm.CommandType = CommandType.StoredProcedure;

        SqlParameter p1 = new SqlParameter("@MyParam", SqlDbType.Int);
        // You can call the return value parameter anything, .e.g. "@Result".
        SqlParameter p2 = new SqlParameter("@Result", SqlDbType.Bit);

        p1.Direction = ParameterDirection.Input;
        p2.Direction = ParameterDirection.ReturnValue;

        p1.Value = myParamVal;

        comm.Parameters.Add(p1);
        comm.Parameters.Add(p2);

        conn.Open();
        comm.ExecuteNonQuery();

        if (p2.Value != DBNull.Value)
            res = (bool)p2.Value;
    }
}
return res;
Community
  • 1
  • 1
rasika
  • 131
  • 1
  • 6
7

The calling scalar-valued function is absolutely correct solution.

TcKs
  • 25,849
  • 11
  • 66
  • 104
  • 1
    Because, you have limited options how to get any result from database engine. Basicaly you have only "SELECT" command. The method "ExecuteScalar" is smart and can retrieve value from scalar-valued function or constant ("SELECT @@SERVERNAME") or value of first column in first row ("SELECT A, B, C FROM MyTable"). – TcKs Jun 10 '10 at 09:57
  • So, to just double-check what you're saying, executing a stored-procedure with the "sqlCommand.ExecuteScalar()" method (as shown by Barry) is the correct solution? Sorry - just want to ensure I understand precisely :) – Sk93 Jun 10 '10 at 10:04
  • Commonly is better use a scalar-valued function than stored procedure. It's because scalar-valued function has strongly typed result. The one procedure can has multiple results (multiple table results and one scalar result and multiple output parameters). The stored procedures can not be used in "WHERE" clausule for example. And so on. However the procedure has more options what can do. The decision of function/procedure is depended on scenario, you want solve. – TcKs Jun 10 '10 at 12:06
  • Then I believe that a scalar-valued function is the correct answer, as this task is effectively a "FileExists" function. Thank you. – Sk93 Jun 10 '10 at 14:16
1

I suppose it depends on the logic the corresponding db function (sp/udf) has to execute.

If for e.g. we are interested in the number of times the particular db function has executed we'd definitely need to do some data manipulation and updates on various tables. Hence we'd have to go for stored procs here. If its a simple retrieval a udf will do.

deostroll
  • 11,661
  • 21
  • 90
  • 161
0

solving it with a stored procedure is better in the long run because it´s more flexible and adaptable

kamahl
  • 931
  • 1
  • 8
  • 20
  • 4
    Better and more flexible are purely subjective based upon the logic to determine the result. Without knowing the logic, one cannot make that assertion with accuracy. – Jeff Schumacher Jun 10 '10 at 09:39
  • That´s true. I just thought if you implement it as a stored procedure, you can update the logic in multiple ways, for example you can use a scalar value function in it I see the stored procedure in this case more as a kind of wrapper – kamahl Jun 10 '10 at 11:27
0

i use this sql scalar function

CREATE FUNCTION DAYSADDNOWK(@addDate AS DATE, @numDays AS INT)
RETURNS DATETIME
AS
BEGIN
    SET @addDate = DATEADD(d, @numDays, @addDate)
    IF DATENAME(DW, @addDate) = 'sunday'   SET @addDate = DATEADD(d, 1, @addDate)
    IF DATENAME(DW, @addDate) = 'saturday' SET @addDate = DATEADD(d, 2, @addDate)

    RETURN CAST(@addDate AS DATETIME)
END
GO

then this is my c# code

using (SqlCommand cmd3 = new SqlCommand("SELECT dbo.DAYSADDNOWK", ClassV.con))
                    ClassV.con.Open();
                    SqlCommand brecord = ClassV.con.CreateCommand();
                    brecord.CommandText = "INSERT INTO TblBorrowRecords VALUES ('" + DGStudents.CurrentRow.Cells[1].Value.ToString() + "','" + DGStudents.CurrentRow.Cells[2].Value.ToString() + "','" + DGStudents.CurrentRow.Cells[4].Value.ToString() + "','" + DGStudents.CurrentRow.Cells[3].Value.ToString() + "','" + DG.CurrentRow.Cells[4].Value.ToString() + "','" + DG.CurrentRow.Cells[5].Value.ToString() + "','" + DG.CurrentRow.Cells[6].Value.ToString() + "','" +System.DateTime.Now.Date.ToShortDateString() + "' , dbo.DAYSADDNOWK(GETDATE(),5) ,null , '" + ClassV.lname.ToString() + ", " + ClassV.fname.ToString() + " " + ClassV.mname.ToString() + "', null, 'Good',null)";
                    var DAYSADDNOWK = brecord.ExecuteScalar();

my C# code skips the function

Sk93
  • 3,676
  • 3
  • 37
  • 67
  • 1
    I wouldn't use that code, especially for production, it is not safe because of SQL Injection – pawciu Dec 12 '19 at 11:16