I am looking to have live data on UI table, I want to get the data from a SQL Server stored procedure that uses a table valued function but I get an invalid subscription error when the dependency change is called.
SqlConnection co = new SqlConnection(_connectionStringTest);
var messages = new List<WorkToListHeaderModel>();
SqlDependency.Stop(_connectionStringTest);
SqlDependency.Start(_connectionStringTest);
using (var cmd = new SqlCommand(#"[DBO].[spTest]", co))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Notification = null;
SqlDataAdapter da = new SqlDataAdapter(cmd);
var dependency = new SqlDependency(cmd);
dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);
DataSet ds = new DataSet();
da.Fill(ds);
for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
{
messages.Add(item: new WorkToListHeaderModel
{
SalesOrderNumber = ds.Tables[0].Rows[i][0].ToString(),
});
}
}
return messages;
private void dependency_OnChange(object sender, SqlNotificationEventArgs e)
{
if (e.Type == SqlNotificationType.Change)
{
MyHub.SendMessages();
}
}
The SQL
ALTER PROCEDURE [dbo].[spTest]
AS
BEGIN
SELECT SalesOrderNumber, Test
FROM dbo.[TableTest]('z')
END
Function
ALTER FUNCTION [dbo].[TableTest]
(#SalesOrderNumber NVARCHAR(100))
RETURNS
#Table TABLE
(
SalesOrderNumber NVARCHAR(100),
Test NVARCHAR(150)
)
AS
BEGIN
;WITH Selects AS
(
SELECT
AdamTest.SalesOrderNumber,
TEST AS CustomerName
FROM
[dbo].[Test]
LEFT JOIN
DBO.Test2 ON Test2.SALESORDERNUMBER = Test.SalesOrderNumber
)
INSERT INTO #Table
SELECT DISTINCT s.SalesOrderNumber, s.CustomerName
FROM Selects AS S
RETURN
Related
I have this stored procedure that selects the top 10 results from its inner join
CREATE PROCEDURE SP_SELECT_DOCS_WHERE_JOBID_STATUS
#JobID INT,
#BatchID INT
AS
BEGIN
SELECT top(10) i.*
FROM jobtable AS j
INNER JOIN batchtable AS b ON j.JobID = b.JobID
INNER JOIN imgtable AS i ON i.BatchID = b.BatchID
END
What I donĀ“t know why it's not working is when I run the app the datagrid is just empty.
This next code is on my dataAccess class
public DataTable SP_SELECT_DOCS_WHERE_JOBID_STATUS_IBML1(int JobID, int BatchID)
{
try
{
ManageConnectionStateIbml1();
SqlCommand command = new
SqlCommand("SP_SELECT_DOCS_WHERE_JOBID_STATUS", connectionIBML1);
command.CommandType = CommandType.StoredProcedure;
command.Parameters.AddWithValue("#JobId", JobID);
command.Parameters.AddWithValue("#BatchId", BatchID);
SqlDataAdapter adapter = new SqlDataAdapter(command);
DataSet ds = new DataSet();
adapter.Fill(ds);
return ds.Tables[0];
}
catch (Exception ex)
{
throw ex;
}
finally
{
ManageConnectionStateIbml1();
connectionIBML1.Close();
}
}
And finally there is my Form file that I am trying to fill the dgv
private void FillDGVDocs(int JobID, int BatchID)
{
dataGridViewDocumentos.DataSource = null;
dataGridViewDocumentos.Columns.Clear();
dataGridViewDocumentos.Refresh();
DataTable dt = da.SP_SELECT_DOCS_WHERE_JOBID_STATUS_IBML1 (JobID, BatchID);
dataGridViewDocumentos.DataSource = dt;
dataGridViewDocumentos.Columns[1].HeaderText = "Caixa";
dataGridViewDocumentos.Columns[2].HeaderText = "DOC";
dataGridViewDocumentos.Columns[3].HeaderText = "ID";
dataGridViewDocumentos.Columns[4].HeaderText = "PROC";
}
Thanks in advance guys.
I have found numerous posts on this but I haven't been able to make any
of them work. The code below is the closest I have come to
making it work. I read out the values for the ddlSIPA listbox below and
the result looks correct but it seems SQL server isn't handling the
IN statement for the listbox items.
public void LoadChecklist(Object sender, EventArgs e)
{
System.Data.DataTable SearchResultsTable = new System.Data.DataTable();
SqlCommand cmd = new SqlCommand("sp_get_QUADRA_CHECKLIST", conn);
cmd.CommandType = CommandType.StoredProcedure;
//create sql adapter by passing command object
SqlDataAdapter adapter = new SqlDataAdapter(cmd);
SearchResultsTable.Clear();
string strYourIDs = "";
int[] yourSelectedIndexes = ddlSIPA.GetSelectedIndices();
for (int i = yourSelectedIndexes.Length - 1; i >= 0; i--)
{
strYourIDs += "'" + ddlSIPA.Items[yourSelectedIndexes[i]].Value + "',";
}
if (strYourIDs != "")
strYourIDs = strYourIDs.TrimEnd(",".ToCharArray());
try
{
cmd.Parameters.AddWithValue("#SIPA", strYourIDs);
Response.Write(strYourIDs);
cmd.Parameters.AddWithValue("#AP_DEV", CbAPDev.Checked);
cmd.Parameters.AddWithValue("#PROD_DEV", cbProdDev.Checked);
cmd.Parameters.AddWithValue("#ROTYPE", ddlROTYPE.SelectedItem.Value);
adapter.Fill(SearchResultsTable);
if (SearchResultsTable.Rows.Count > 0)
{
//SearchResultsTable.ToString();
GV1.DataSource = SearchResultsTable;
GV1.DataBind();
}
else if (SearchResultsTable.Rows.Count == 0)
{
//Response.Write("No records found!");
ScriptManager.RegisterStartupScript(this, GetType(), "showalert", "alert('No records found!');", true);
GV1.DataBind();
}
}
catch (System.Data.SqlClient.SqlException ex)
{
Response.Write(ex);
}
finally
{
conn.Close();
}
}
SQL Query:
USE [VISIBILITY_BOARD]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER OFF
GO
ALTER PROCEDURE [dbo].[sp_get_QUADRA_CHECKLIST] (
#AP_DEV bit ''
,#PROD_DEV bit = ''
,#ROTYPE nvarchar(255) = ''
,#SIPA nvarchar(255) = '') AS
--,#RO nvarchar(255) = '') AS
SELECT h.QUES_ANSWER
, h.COMMENTS
, cl.RO_TYPE
, cl.RO
, cl.QUES_ID
, cl.DFQRO AS QDRO
, cl.QUADRA_QUES
FROM Tbl_QUADRA_CL cl
LEFT JOIN TBL_QUADRA_ASSMNT_HIST h
ON cl.QUES_ID = h.QUES_ID
WHERE (cl.RO_TYPE = #ROTYPE OR #ROTYPE IS NULL)
AND (cl.SIPA IN (#SIPA) OR #SIPA IS NULL)
AND (cl.AP_DEV = #AP_DEV OR #AP_DEV IS NULL)
AND (cl.PROD_DEV = #PROD_DEV or #PROD_DEV IS NULL)
GROUP BY h.QUES_ANSWER
, h.COMMENTS
, cl.RO_TYPE
, cl.RO
, cl.QUES_ID
, cl.DFQRO
, cl.QUADRA_QUES
SET QUOTED_IDENTIFIER On
GO
Here is your problem: AND (cl.SIPA IN (#SIPA) OR #SIPA IS NULL)
You are making a very common mistake - The IN operator expects a list of values separated by a comma, but you are giving it a single value that happens to contain a comma-separated list.
Since you are using c# and sql-server, I would advise to use a table valued parameter instead.
Please note that there are also some other problems in your code:
Using a class level SQLConnection - That's a mistake. A correct use of SQLConnection would be as a local variable inside a using statement.
Using instances of classes that implements the IDisposable interface and not disposing them - SQLCommand and SQLDataAdapter in your case.
Using AddWithValue - Read Can we stop using AddWithValue() already? for details.
A better c# code would look more like this:
public void LoadChecklist(Object sender, EventArgs e)
{
var SearchResultsTable = new DataTable();
using (var con = new SqlConnection("<ConnectionStringGoesHere>"))
{
using (var cmd = new SqlCommand("sp_get_QUADRA_CHECKLIST", con))
{
cmd.CommandType = CommandType.StoredProcedure;
using(var adapter = new SqlDataAdapter(cmd))
{
using(var dtSIPA = new DataTable())
{
dtSIPA.Columns.Add("Id", typeof(int)); -- assuming you are looking for a list of int values
int[] yourSelectedIndexes = ddlSIPA.GetSelectedIndices();
for (int i = yourSelectedIndexes.Length - 1; i >= 0; i--)
{
dtSIPA.Rows.Add(ddlSIPA.Items[yourSelectedIndexes[i]].Value);
}
cmd.Parameters.Add("#AP_DEV", SqlDbType.Bit).Value = CbAPDev.Checked;
cmd.Parameters.Add("#PROD_DEV", SqlDbType.Bit).Value = cbProdDev.Checked;
cmd.Parameters.Add("#ROTYPE", SqlDbType.NVarChar, 255).Value = ddlROTYPE.SelectedItem.Value;
cmd.Parameters.Add("#SIPA", SqlDbType.Structured).Value = dtSIPA;
}
try
{
adapter.Fill(SearchResultsTable);
}
catch (System.Data.SqlClient.SqlException ex)
{
Response.Write(ex);
}
}
}
}
}
As for your stored procedure, you need to create a user defined table type for the #SIPA parameter:
CREATE TYPE SIPA AS TABLE
(
Id int
)
and change the condition to AND (cl.SIPA IN (SELECT Id FROM #SIPA) OR (SELECT COUNT(*) FROM #SIPA) = 0)
I have this stored procedure that gets the product table with provided parameter
CREATE PROCEDURE DisplayProductParameter #id nvarchar(100)
AS
BEGIN
SET NOCOUNT ON;
SELECT P.product_id, P.product_name, P.product_price, T.[type_name], T.[type_fee], T.[type_id]
FROM Product P
INNER JOIN [Product Type] T ON P.[type_id] = T.[type_id]
WHERE P.product_id = #id
END;
GO
I call it with this function in C#
public SqlCommand InitSqlCommand(string query, CommandType commandType)
{
var Sqlcommand = new SqlCommand(query, con);
Sqlcommand.CommandType = commandType;
return Sqlcommand;
}
Then I store it in a DataTable
public DataTable GetData(SqlCommand command)
{
var dataTable = new DataTable();
var dataSet = new DataSet();
var dataAdapter = new SqlDataAdapter { SelectCommand = command };
dataAdapter.Fill(dataTable);
return dataTable;
}
Then this is how I get the DataTable
public DataTable DisplayProductParameter()
{
string getProductIdParam = "DisplayProductParameter";
var command = Connection.InitSqlCommand(getProductIdParam, CommandType.StoredProcedure);
command.Parameters.AddWithValue("#id", P.Id);
return Connection.GetData(command);
}
This is how I should autofill textboxes whenever I click on the combobox
private void cmbProductId_SelectedIndexChanged(object sender, EventArgs e)
{
try
{
p.Id = cmbProductId.SelectedItem.ToString();
dtbProduct = po.DisplayProductParameter();
for (int i = 0; i < dtbProduct.Rows.Count; i++)
{
txtProductType.Text = dtbProduct.Rows[i]["type_name"].ToString();
txtPrice.Text = dtbProduct.Rows[i]["product_price"].ToString();
txtProductName.Text = dtbProduct.Rows[i]["product_name"].ToString();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
But I get this error message at the start of the form
Procedure or function 'DisplayProductParameter' expects parameter
'#id', which was not supplied.
Logically your code seems correct.
In order to get more information on where and why this is happening, could you add a breakpoint on this line:
public DataTable DisplayProductParameter()
{
string getProductIdParam = "DisplayProductParameter";
var command = Connection.InitSqlCommand(getProductIdParam, CommandType.StoredProcedure);
-->command.Parameters.AddWithValue("#id", P.Id);
return Connection.GetData(command);
}
and run in debugging mode to see what the value of P.Id is. It could be passing a null or empty string value into the procedure.
I have a list with two columns in it: ID; int, Score: Double.
In addition, I have a table in SQL SERVER with several columns.One of them is id:int.
I want to have a query like below:
select * from tbl where id = id s in my list.
My codes are below:
protected void btnfind_Click(object sender, EventArgs e)
{
List<KeyValuePair<int, double>> candidatelist = CalculateScores();
FinalMatch(candidatelist);
BindGrid(cmd2);//Contains codes for filling grid view with cmd2 , sql data reader
}
protected void FinalMatch(List<KeyValuePair<int, double>> finallist)
{
DataTable tvp = new DataTable();
tvp = ConvertToDatatable(finallist);
cmd2.CommandType = CommandType.StoredProcedure;
cmd2.CommandText = "dbo.DoSomethingWithCandidates";
SqlParameter tvparam = cmd2.Parameters.AddWithValue("#List", tvp);
tvparam.SqlDbType = SqlDbType.Structured;
cmd2.Connection = ClsDataBase.con;
}
protected DataTable ConvertToDatatable(List<KeyValuePair<int, double>> finallist)
{
DataTable dt = new DataTable();
dt.Columns.Add("ID");
dt.Columns.Add("Score");
foreach (var item in finallist)
{
var row = dt.NewRow();
row["ID"] = item.Key;
row["Score"] = item.Value;
dt.Rows.Add(row);
}
return dt;
}
protected void BindGrid(SqlCommand cmd)
{
if (ClsDataBase.con.State == ConnectionState.Closed)
ClsDataBase.con.Open();
SqlDataReader dr1 = cmd.ExecuteReader();
try
{
if (dr1.HasRows)
{
gv_allresults.DataSource = dr1;
gv_allresults.DataBind();
}
else
{
Response.Write("<script LANGUAGE='JavaScript' >alert('No Match')</script>");
}
if (dr1.IsClosed == false) dr1.Close();
}
catch (SqlException ex)
{
Response.Write("<script language='javascript'>alert(\"" + ex.ToString() + "\")</script>");
}
catch (Exception ex)
{
Response.Write("<script language='javascript'>alert(\"" + ex.ToString() + "\")</script>");
}
finally
{
ClsDataBase.con.Close();
}
}
And my codes in SQL server are:
CREATE TYPE dbo.CandidateList
AS TABLE
(
ID INT,
Score FLOAT
);
GO
CREATE PROCEDURE dbo.DoSomethingWithCandidates
#List AS dbo.CandidateList READONLY
AS
BEGIN
SET NOCOUNT ON;
SELECT ID FROM #List;
END
GO
I don't get the result. My procedure's codes are not complete. I don`t know what to do. Please help me.
Thanks so much.
Edited codes according to given suggestion:
protected void FinalMatch(List<KeyValuePair<int, double>> finallist)
{
int[] canArr = finallist.Select(x => x.Key).ToArray();
string csv = string.Join(",", canArr);
cmd2.CommandType = CommandType.StoredProcedure;
cmd2.CommandText = "dbo.ReturnCandidates";
cmd2.Parameters.AddWithValue("#LIST", csv);
cmd2.Connection = ClsDataBase.con;
}
And new codes in Sql server are:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [dbo].[CSVToTable] (#InStr VARCHAR(MAX))
RETURNS #TempTab TABLE
(id int not null)
AS
BEGIN
;-- Ensure input ends with comma
SET #InStr = REPLACE(#InStr + ',', ',,', ',')
DECLARE #SP INT
DECLARE #VALUE VARCHAR(1000)
WHILE PATINDEX('%,%', #INSTR ) <> 0
BEGIN
SELECT #SP = PATINDEX('%,%',#INSTR)
SELECT #VALUE = LEFT(#INSTR , #SP - 1)
SELECT #INSTR = STUFF(#INSTR, 1, #SP, '')
INSERT INTO #TempTab(id) VALUES (#VALUE)
END
RETURN
END
GO
CREATE PROCEDURE dbo.ReturnCandidates
(
#LIST VARCHAR(200)
)
AS
BEGIN
SELECT *
FROM tblspecifications
WHERE id IN ( SELECT * FROM dbo.CSVToTable(#LIST) )
END
I get this error: "Procedure or function ReturnCandidates has too many arguments specified",
In below line:
SqlDataReader dr1 = cmd.ExecuteReader();
Please help me. Thanks a lot
I see cmd2.ExecuteNonQuery() missing.
Also, why not make a comma separated list of ID's and then send it to the SQL function. Example
int[] canArr= candidatelist.Select(x => x.Key).ToArray();
string csv = string.Join(",", canArr);
EDIT:
I created a SQL Fiddle for your query. It works.
http://sqlfiddle.com/#!6/c3d013/1/1
I am trying to pass a datatable as a parameter into a sql stored procedure.
I have a helper class that executes the code for me:
Helper class method I am using:
public int ExecNonQueryProc(string proc, params object[] args)
{
using (SqlCommand cmd = CreateCommand(proc, CommandType.StoredProcedure, args))
{
return cmd.ExecuteNonQuery();
}
}
public SqlCommand CreateCommand(string qry, CommandType type, params object[] args)
{
SqlCommand cmd = new SqlCommand(qry, _conn);
// Associate with current transaction, if any
if (_trans != null)
cmd.Transaction = _trans;
// Set command type
cmd.CommandType = type;
// Construct SQL parameters
for (int i = 0; i < args.Length; i++)
{
if (args[i] is string && i < (args.Length - 1))
{
SqlParameter parm = new SqlParameter();
parm.ParameterName = (string)args[i];
parm.Value = args[++i];
cmd.Parameters.Add(parm);
}
else if (args[i] is SqlParameter)
{
cmd.Parameters.Add((SqlParameter)args[i]);
}
else throw new ArgumentException("Invalid number or type of arguments supplied");
}
return cmd;
}
My SQL Stored Procedure:
ALTER PROCEDURE [dbo].[sp_insert_input_portfolio_metrics]
#TYPE_INPUT_PORTFOLIO_METRICS TYPE_INPUT_PORTFOLIO_METRICS readonly
-- Add the parameters for the stored procedure here
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
delete from dbo.INPUT_PORTFOLIO_METRICS
where ID in (select ID from dbo.INPUT_PORTFOLIO_METRICS a
inner join #TYPE_INPUT_PORTFOLIO_METRICS b
on a.Portfolio = b.portfolio and a.Portfolio_Val_date = b.portfolio_val_date)
END
How I am executing:
private void simpleButton_UploadAll_Click(object sender, EventArgs e)
{
AdoHelper adocommand = new AdoHelper();
var dt = new DataTable();
dt = wizard_tables.PerformanceDetail.Copy();
adocommand.ExecNonQueryProc("sp_insert_input_portfolio_metrics",
"#TYPE_INPUT_PORTFOLIO_METRICS", dt);
}
The error that I receive:
No mapping exists from object type
Risk_Performance_Platform.Datasets.DS_Wizard_Tables+PerformanceDetailDataTable
to a known managed provider native type.
I was trying to follow the example by Navid Farhadi on
How to insert a data table into SQL Server database table?