I am new to interfacing DB's with applications and am trying to pull a couple of fields from a database where the parameter I specified should filter out the results. I keep receiving a no parameters or arguments were supplied. Can anyone shed a little insight on this? Thanks.
below is the stored procedure:
ALTER PROC dbo.PassParamUserID
AS
set nocount on
DECLARE #UserID int;
SELECT f_Name, l_Name
FROM tb_User
WHERE tb_User.ID = #UserID;
And here is my code
class StoredProcedureDemo
{
static void Main()
{
StoredProcedureDemo spd = new StoredProcedureDemo();
//run a simple stored procedure that takes a parameter
spd.RunStoredProcParams();
}
public void RunStoredProcParams()
{
SqlConnection conn = null;
SqlDataReader rdr = null;
string ID = "2";
Console.WriteLine("\n the customer full name is:");
try
{
//create a new connection object
conn = new SqlConnection("Data Source=.\\SQLEXPRESS;AttachDbFilename=c:\\Program Files\\Microsoft SQL Server\\MSSQL10.SQLEXPRESS\\MSSQL\\DATA\\UserDB.mdf;Integrated Security=True;Connect Timeout=30;User Instance=True; Integrated Security=SSPI");
conn.Open();
//create command objects identifying the stored procedure
SqlCommand cmd = new SqlCommand("PassParamUserID", conn);
//Set the command object so it know to execute the stored procedure
cmd.CommandType = CommandType.StoredProcedure;
//ADD PARAMETERS TO COMMAND WHICH WILL BE PASSED TO STORED PROCEDURE
cmd.Parameters.Add(new SqlParameter("#UserID", 2));
//execute the command
rdr = cmd.ExecuteReader();
//iterate through results, printing each to console
while (rdr.Read())
{
Console.WriteLine("First Name: {0,25} Last Name: {0,20}", rdr["f_Name"], rdr["l_Name"]);
}
}
You need to modify your SQL stored proc to:
ALTER PROC dbo.PassParamUserID
#UserID int
AS set nocount on
SELECT f_Name, l_Name FROM tb_User WHERE tb_User.ID = #UserID;
At the moment you are just declaring it as a variable within the procedure.
Here are some MSDN articles that may help you going forward:
Creating and Altering Stored procedures
Declaring Local Variables
ALTER PROC dbo.PassParamUserID (#UserID int)
AS
set nocount on
SELECT f_Name, l_Name FROM tb_User WHERE tb_User.ID = #UserID;
If you want to pass a parameter in you need to define it before the AS statement as shown above.
Related
I want the date and the name from the select query which if I run as normal query I get the results but i when I try to get the results in C# all I get is count=0. Can anyone tell me what wrong am I doing?
Here is the C# code
private List<CertificationSummary> GetLastAccessData (string taskOwner)
{
List<CertificationSummary> lastAccessedResult = new List<CertificationSummary>();
string connectionString = SqlPlusHelper.GetConnectionStringByName("MetricRepositoryDefault");
using (SqlConnection connection = new SqlConnection(connectionString))
{
SqlParameter[] sqlParams = new SqlParameter[1];
sqlParams[0] = new SqlParameter("#taskOwner", SqlDbType.NVarChar);
sqlParams[0].Value = taskOwner;
connection.Open();
SqlCommand cmd = connection.CreateCommand();
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "GetLastAccessedCertificationData";
cmd.Parameters.AddRange(sqlParams);
cmd.ExecuteNonQuery();
}
return lastAccessedResult;
}
And here is the stored procedure:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[GetLastAccessedCertificationData]
(#taskOwner nvarchar(255))
AS
BEGIN
DECLARE #name nvarchar(100)
DECLARE #lastAccessedDate [datetime]
SELECT #name = Name
FROM CertificationReviewCycles
INNER JOIN UserReviewCycleAccess ON CertificationReviewCycles.CertificationReviewCycleID = UserReviewCycleAccess.LastAccessedReviewCycleID
WHERE USERID = #taskOwner
SELECT #lastAccessedDate = LastAccessedDate
FROM UserReviewCycleAccess
WHERE UserID = #taskOwner
CREATE TABLE #tempTable
(
name [nvarchar](255) NULL,
[LastAccessedDate] [datetime] NULL,
)
INSERT INTO #tempTable VALUES (#name, #lastAccessedDate)
SELECT TOP(1) name, LastAccessedDate
FROM #tempTable
END
GO
You are returning lastAccessedResult which is has just been set to new List<CertificationSummary>(). This list has no items, so it has a count of 0.
Use ExecuteReader instead of ExecuteNonQuery and you can then read the data returned and store them into your lastAccessedResult list.
Read here for more info.
ExecuteNonQuery will not return results, and should only be used when you don't expect rows back. This is common for UPDATE statements.
Since you're interested in reading the rows returned by the stored procedure, use ExecuteReader, e.g var reader = cmd.ExecuteReader();
See here for more:
https://learn.microsoft.com/en-us/dotnet/api/system.data.sqlclient.sqldatareader?view=dotnet-plat-ext-3.1
You're using ExecuteNonQuery, which discards any grids from the query. You need to use ExecuteReader to consume grids, but it is a lot of mess and ceremony - the API is verbose. Frankly, I'd recommend a tool like "Dapper" (freely available on NuGet), then this becomes just
private List<CertificationSummary> GetLastAccessData (string taskOwner)
{
string connectionString = SqlPlusHelper.GetConnectionStringByName("MetricRepositoryDefault");
using var connection = new SqlConnection(connectionString);
return connection.Query<CertificationSummary>(
"GetLastAccessedCertificationData",
new { taskOwner }, // <== parameters
commandType: CommandType.StoredProcedure).AsList();
}
I am executing a SQL Server stored procedure in C#, but both my output parameters are returned blank. But when I run this stored procedure directly in SSMS, then I get values for both parameters. I used same input order no.
Can anyone tell me what's wrong in my code? Thank you
using (SqlConnection con = new SqlConnection(CS))
{
SqlCommand cmd = new SqlCommand("wt_find_open_pick_ticket_count", con);
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#input_order_no", order_no);
cmd.Parameters.Add("#status", SqlDbType.Int).Direction = ParameterDirection.Output;
cmd.Parameters.Add("#results", SqlDbType.VarChar, 1000).Direction = ParameterDirection.Output;
con.Open();
cmd.ExecuteNonQuery();
MessageBox.Show(cmd.Parameters["#status"].Value.ToString());
MessageBox.Show(cmd.Parameters["#results"].Value.ToString());
}
ALTER procedure wt_find_open_pick_ticket_count
#input_order_no varchar(20),
#results varchar(1000) OUTPUT,
#status int OUTPUT
AS
SELECT
status =
CASE
WHEN COUNT(oe_pick_ticket.pick_ticket_no)>0 THEN 0
ELSE 1
END,
results =
CASE
WHEN COUNT(oe_pick_ticket.pick_ticket_no)> 0 THEN 'Message'
ELSE ''
END
FROM oe_pick_ticket with (nolock)
WHERE
oe_pick_ticket.order_no = #input_order_no
AND oe_pick_ticket.invoice_no IS NULL
AND oe_pick_ticket.delete_flag = 'N'
AND oe_pick_ticket.print_date > '2014-01-01'
GROUP BY oe_pick_ticket.order_no
This stored procedure returns a resultset. It does not return output parameters. In order to return output paramters, SP has to change to something like:
select
#paramout1 = val1,
#paramout2 = val2
Notice "#" that is preceding parameter names.
I have a stored procedure that correctly returns records when I call it from a SSMS query.
Here is the stored procedure:
CREATE PROCEDURE [dbo].[q_CheckRecords]
#ItemIDS AS VARCHAR(40)
AS
BEGIN
SET NOCOUNT ON
SELECT *
FROM q_Warehouse80_OOS_ItemsNeedingNotification
WHERE item_id = #ItemIDS
END
Calling this from a SSMS query like this:
exec [q_CheckOOSWarehouse80ItemsNeedingNotification] 'B30-R10000-B001'
It correctly returns a row, however when I use this C# code to call the stored procedure, I never get any rows returned.
SqlCommand cmd = null;
SqlDataReader myReader = null;
System.Data.SqlClient.SqlConnection conn = null;
conn = new System.Data.SqlClient.SqlConnection("Data Source=" + sSessionServer + ";database=" + sSessionDatabase + "; Integrated Security=SSPI");
String SQL = "[q_CheckOOSWarehouse80ItemsNeedingNotification]";
cmd = new SqlCommand();
cmd.CommandText = SQL;
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.Connection = conn;
cmd.Parameters.Add("#ItemIDS", SqlDbType.VarChar).Value = ItemsToBeChecked;
conn.Open();
myReader = cmd.ExecuteReader();
// check to see if any rows were returned.
if (myReader.HasRows)
{
while (myReader.Read())
{
// code to read fields in returned rows here
}
}
conn.Close();
It appears to be a problem with how C# defines the datatype being passed to the stored procedure, but I haven't found any information online on how to solve this problem.
If I were to changed the stored procedure so it's "hard coded"
#ItemIDS AS VARCHAR(40)
AS
BEGIN
SET NOCOUNT ON
select * from q_Warehouse80_OOS_ItemsNeedingNotification where item_id = 'B30-R10000-B001'
END
then the C# call to it correctly indicates that a row was "found".
Any help would be greatly appreciated.
When you don't specify the length of a varChar sql treats it as length 1.
cmd.Parameters.Add("#ItemIDS", SqlDbType.VarChar).Value = ItemsToBeChecked;
Your variable ItemsToBeChecked will be truncated, and I suspect there is nothing matching in your database with just the first character of that value.
Specify the length of the varchar
cmd.Parameters.Add("#ItemIDS", SqlDbType.VarChar, 40).Value = ItemsToBeChecked;
You can verify this is the case by putting a profiler on sql, and executing your c#. You will see the value passed to the #ItemIDS parameter is only 1 character long.
The issue you are facing is because you are not calling your stored procedure in your C# Code.
I am trying to query services on a remote server and insert them into SQL. I know I am missing something that will actually write this back but I cannot figure out what it is. Everything works until I try to write the data to SQL.
static void Main(string[] args)
{
string username = ConfigurationManager.AppSettings["UserName"].ToString();
string password = ConfigurationManager.AppSettings["Password"].ToString();
string domain = ConfigurationManager.AppSettings["Domain"].ToString();
var logonType = SimpleImpersonation.LogonType.NewCredentials;
using (SimpleImpersonation.Impersonation.LogonUser(domain, username, password, logonType))
{
var connection = ConfigurationManager.ConnectionStrings["Connection"].ConnectionString;
using (SqlConnection conn = new SqlConnection(connection))
{
conn.Open();
using (SqlCommand command = new SqlCommand("SELECT ServerName, ServerIP FROM Server", conn))
{
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
string serverIP = reader["ServerIP"].ToString();
string serverName = reader["ServerName"].ToString();
ServiceController[] services = ServiceController.GetServices(serverIP);
foreach (ServiceController service in services)
{
using (SqlCommand cmd = new SqlCommand("sp_InsertServices", conn))
{
cmd.CommandType = System.Data.CommandType.StoredProcedure;
SqlParameter ID = new SqlParameter();
ID.ParameterName = "#ID";
ID.Direction = System.Data.ParameterDirection.Output;
cmd.Parameters.AddWithValue("#ID", ID);
cmd.Parameters.AddWithValue("#Display", service.DisplayName);
cmd.Parameters.AddWithValue("#Service", service.ServiceName);
cmd.Parameters.AddWithValue("#Status", service.Status);
cmd.Parameters.AddWithValue("#Server", serverName);
}
}
}
}
}
}
}
Here is the Stored Proc
PROCEDURE [dbo].[sp_InsertServices]
#ID int,
#Display nvarchar(50),
#Service nvarchar(50),
#Status nvarchar(50),
#Server nvarchar(50)
AS
BEGIN
SET NOCOUNT ON
INSERT INTO Services
(ID,
DisplayName,
ServiceName,
Status,
Server)
VALUES
(#ID,
#Display,
#Service,
#Status,
#Server)
SET #ID = SCOPE_IDENTITY()
END
EDIT: Sorry some more info. I have added an execute at the end after the param adds and I get this error.
An unhandled exception of type 'System.InvalidOperationException' occurred in System.Data.dll
Additional information: There is already an open DataReader associated with this Command which must be closed first.
Looks like I need to close the first reader but I still use it in the second command. Don't now where I can safely close it.
You never execute your SqlCommand. After you add your parameters, try adding cmd.ExecuteNonQuery();
The 2nd problem is that you are trying to reuse the same SqlConnection. You'll need to create a new SqlConnection since you are using your existing connection to loop through the list of servers.
You've built up the Command object (cmd), now you just need to save it, like cmd.ExecuteNonQuery();
First this you need to change the stored procedure declaration as
ALTER PROCEDURE [dbo].[sp_InsertServices]
#Display nvarchar(50),
#Service nvarchar(50),
#Status nvarchar(50),
#Server nvarchar(50)
AS
BEGIN
SET NOCOUNT ON
INSERT INTO Services
(DisplayName, ServiceName, Status, Server)
VALUES
(#Display,#Service,#Status,#Server)
SELECT SCOPE_IDENTITY()
END
And now change the calling code to
using (SqlCommand cmd = new SqlCommand("sp_InsertServices", conn))
{
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#Display", service.DisplayName);
cmd.Parameters.AddWithValue("#Service", service.ServiceName);
cmd.Parameters.AddWithValue("#Status", service.Status);
cmd.Parameters.AddWithValue("#Server", serverName);
int serviceID = (int)cmd.ExecuteScalar();
// What you want to do with the ID returned?
}
The ID parameter is not needed if your ID field is an IDENTITY column, it is automatically calculated by the database and you could return it using a simple select. If your stored procedure ends with a SELECT SCOPE_IDENTITY() the result can be retrieved on the C# code using a simple ExecuteScalar without the need of an output parameter.
Finally, if you try to ExecuteXXX an SqlCommand using the same connection in use by a SqlDataReader you get an exception because the connection is busy serving the SqlDataReader and cannot execute the command.
The simple solution is to add this to your connection string
....;MultipleActiveResultSets=True;....
See MSDN for MultipleActiveResultSets
I'm trying to call the below stored procedure but I am unsure on what to pass through one of the parameters (#UnsubscribeTypes) I've tried passing in a list but got a compile error. I'm using c#, Visual Studio 2010, web forms. Any ideas on what I should pass in when calling the stored procedure in my c# code (ado.net)?
Here is my stored procedure:
ALTER PROCEDURE [czone].[SetAccountEmailPreference]
(
#EmailAddress VARCHAR(255),
#UnsubscribeTypes dbo.ListOfIDs READONLY,
#SentEmailID INT = NULL
)
AS
SET NOCOUNT ON;
EXEC dbo.LogObjectExecution ##PROCID;
DECLARE #UnsubscribeID INT = (SELECT TOP 1 UnsubscribeID
FROM Email.dbo.Unsubscribe
WHERE EmailAddress = #EmailAddress
ORDER BY UnsubscribeID DESC);
-- Unsubscribe
IF ((SELECT COUNT(*) FROM #UnsubscribeTypes) > 0)
BEGIN
IF(#UnsubscribeID IS NULL)
BEGIN
-- ADD UNSUBSCRIBE
INSERT INTO Email.dbo.Unsubscribe (EmailAddress, CreatedDate)
VALUES (#EmailAddress, CURRENT_TIMESTAMP)
SET #UnsubscribeID = ##IDENTITY;
END
-- Remove current mappings
DELETE FROM Email.dbo.UnsubscribeTypeMapping
WHERE UnsubscribeFK = #UnsubscribeID;
-- Add new mappings
INSERT INTO Email.dbo.UnsubscribeTypeMapping (UnsubscribeFK, UnsubscribeTypeFK, SentEmailFK)
SELECT
#UnsubscribeID, ID, #SentEmailID
FROM
#UnsubscribeTypes;
END
-- Subscribe
ELSE IF (#UnsubscribeID IS NOT NULL)
BEGIN
DELETE FROM Email.dbo.Unsubscribe
WHERE UnsubscribeID = #UnsubscribeID;
END
dbo.ListOfIDs is a table type. First, find out the type in your database, then check columns. generate a datatable with rows containing the UnsubscribeTypeFK ids.
The ADO.net code (not compiled)
Creating table
DataTable dt = new DataTable("Items");
dt.Columns.Add("ID", typeof(int));
dt.Rows.Add(4);
Calling proc
con = new SqlConnection(conStr);
con.Open();
using (con) {
// Configure the SqlCommand and SqlParameter.
SqlCommand sqlCmd = new SqlCommand("czone.SetAccountEmailPreference", con);
sqlCmd.CommandType = CommandType.StoredProcedure;
SqlParameter tvpParam = sqlCmd.Parameters.AddWithValue("#UnsubscribeTypes", _dt); // TVP
tvpParam.SqlDbType = SqlDbType.Structured; //tells ADO.NET we are passing TVP
//pass other parameters
sqlCmd.ExecuteNonQuery();
}
con.Close();
You will find more about Table-Valued parameters here