Stored procedure returning result - c#

I am creating a stored procedure to produce a list of items. The stored procedure returns a result and a return value. In my application that I am calling the stored procedures return the return value. How do I make it return the result?
This is my procedure:
CREATE PROCEDURE [AQB_RMS].[p_SO2EmailOverDue]
AS
(SELECT
CONVERT(CHAR(10), CheckDate, 101) AS ZSPDate,
Manufacturer, Model, SerialNumber, LocationName
FROM
[AQB_RMS].[SO2_Zsp] so
INNER JOIN
AQB_MON.[AQB_RMS].[Device] dev ON dev.DeviceID = so.DeviceID
INNER JOIN
AQB_MON.[AQB_RMS].[DeviceLocation] dl ON dev.DeviceID = dl.DeviceID
INNER JOIN
AQB_MON.[AQB_RMS].[Location] loc ON dl.LocationID = loc.LocationID
INNER JOIN
[AQB_RMS].[ManufacturerModel] mm ON dev.ManufacturerModelID = mm.ManufacturerModelID
INNER JOIN
[AQB_RMS].[Manufacturer] man ON mm.ManufacturerID = man.ManufacturerID
WHERE
CheckDate = (SELECT MAX(CheckDate) FROM [AQB_RMS].[SO2_Zsp]
WHERE DeviceID = so.DeviceID)
AND dl.EndDate IS NULL
AND (SELECT DATEDIFF(day, so.CheckDate, GetDate()) AS DayCount) > 14)
ORDER BY
CheckDate
RETURN
GO
The following is the return when I execute the stored procedure in SQL Server 2012
I am using the stored procedure to provide the results for the body of an email. I am using c#
static string Body()
{
//create a connection to the database
string ConnString = ConfigurationManager.ConnectionStrings["avdatauser"].ConnectionString;
StringBuilder sb = new StringBuilder();
using (SqlConnection con = new SqlConnection(ConnString))
{
con.Open();
SqlCommand cmd = new SqlCommand("AQB_RMS.p_SO2EmailNearDue", con);
cmd.CommandType = CommandType.StoredProcedure;
cmd.ExecuteNonQuery();
sb.Append("<strong>SO2 Analyzer ZSP due</strong>");
sb.Append("<br>");
sb.Append("<br>");
sb.Append("What do you want to say here to show these are the ones with a ZSP that are near due");
sb.Append("<br>");
sb.Append("<br>");
sb.Append(" " + cmd + " ");
con.Close();
}
return sb.ToString();
}

Related

How to drop all tables from specific schema in C# SQL Server?

I'm working on a database migration where I need to drop all the tables in a specific schema and then run another script to recreate them from another database.
I'm running into issues with trying to delete specific tables in the proper order.
Is there a SQL query that will order the tables in the correct order so they can be dropped properly?
Here is the code I am trying so far, but the tables are not in the proper order:
private void CreateDropStatementsAndRun(string schema)
{
string sql = string.Format(#"SELECT table_name
FROM information_schema.tables
WHERE table_schema = '{0}';", schema);
var connectionString = ConfigurationManager.ConnectionStrings["TARGET_DefaultConnection"];
StringBuilder sb = new StringBuilder();
var listOfTables = new List<string>();
using (SqlConnection conn = new SqlConnection(connectionString.ConnectionString))
{
conn.Open();
using (var command = new SqlCommand(sql, conn))
{
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
listOfTables.Add(reader.GetString(0));
}
}
}
foreach (var item in listOfTables)
{
sb.AppendFormat("alter table {0}.{1} nocheck constraint all;", schema, item).AppendLine();
sb.AppendFormat("DROP TABLE IF EXISTS {0}.{1};", schema, item).AppendLine();
}
using (var cmd = new SqlCommand(sb.ToString(), conn))
{
cmd.CommandType = CommandType.Text;
cmd.ExecuteNonQuery();
}
}
}
Remember that there might be circular references between tables. There might be foreign key constraints from A -> B -> C -> A, for example.
Have a look at the approach in How to drop all tables in a SQL Server database? - but you will have to alter it to work with just your schema.
Here is my answer:
Focus on the ORDER BY dependency_level desc and then the where schema_Name = '{0}'
Here is where I found my answer: How to list tables in their dependency order (based on foreign keys)?
private void CreateDropStatementsAndRun(string schema)
{
string sql = string.Format(#"WITH cte (lvl, object_id, name, schema_Name) AS
(SELECT 1, object_id, sys.tables.name, sys.schemas.name as schema_Name
FROM sys.tables Inner Join sys.schemas on sys.tables.schema_id = sys.schemas.schema_id
WHERE type_desc = 'USER_TABLE'
AND is_ms_shipped = 0
UNION ALL SELECT cte.lvl + 1, t.object_id, t.name, S.name as schema_Name
FROM cte
JOIN sys.tables AS t ON EXISTS
(SELECT NULL FROM sys.foreign_keys AS fk
WHERE fk.parent_object_id = t.object_id
AND fk.referenced_object_id = cte.object_id )
JOIN sys.schemas as S on t.schema_id = S.schema_id
AND t.object_id <> cte.object_id
AND cte.lvl < 30
WHERE t.type_desc = 'USER_TABLE'
AND t.is_ms_shipped = 0 )
SELECT schema_Name, name, MAX (lvl) AS dependency_level
FROM cte
where schema_Name = '{0}'
GROUP BY schema_Name, name
ORDER BY dependency_level desc,schema_Name, name;", schema);
var connectionString = ConfigurationManager.ConnectionStrings["TARGET_DefaultConnection"];
StringBuilder sb = new StringBuilder();
var listOfTables = new List<string>();
using (SqlConnection conn = new SqlConnection(connectionString.ConnectionString))
{
conn.Open();
using (var command = new SqlCommand(sql, conn))
{
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
listOfTables.Add(reader.GetString(1));
}
}
}
if (listOfTables.Count > 0)
{
foreach (var item in listOfTables)
{
sb.AppendFormat("DROP TABLE IF EXISTS {0}.{1};", schema, item).AppendLine();
}
using (var cmd = new SqlCommand(sb.ToString(), conn))
{
cmd.CommandType = CommandType.Text;
cmd.ExecuteNonQuery();
}
}
}
}

Select Query Parameter from C# in a stored procedure

How does a SQL Server query select from parameter? I just want to make it simple set select column based on my C# code. Is it possible?
Here is my stored procedure:
ALTER PROCEDURE [dbo].[GetMembersDetailGenerateChanceTop10000]
#EventId nvarchar(255),
#PeriodId nvarchar(255),
#QueryParam nvarchar(1000)
AS
BEGIN
SET NOCOUNT ON;
SELECT DISTINCT TOP 10000 #QueryParam
FROM ign..Chance_Generated cg
INNER JOIN ign..Contact c ON cg.ContactID = c.ContactId
LEFT JOIN ign..CustomerAddress ca ON ca.parentid = cg.contactid
LEFT JOIN ign..new_cardlevelconfig cl ON cl.new_cardlevelconfigid = c.new_cardlevel
LEFT JOIN ign..new_country co ON co.new_countryid = c.new_country
LEFT JOIN ign..new_province po ON po.new_provinceId = c.new_Province
LEFT JOIN ign..StringMap sm ON sm.AttributeValue = c.new_IDType
LEFT JOIN ign..new_city cy ON cy.new_cityId = c.new_CityCounty
LEFT JOIN ign..new_transactionheader th ON cg.New_Name COLLATE DATABASE_DEFAULT = th.new_name COLLATE DATABASE_DEFAULT
WHERE cg.EventId = #EventId
AND (ca.AddressNumber = '1' OR ca.AddressNumber IS NULL)
AND (sm.AttributeName IS NULL OR sm.AttributeName = 'new_idtype')
AND cg.periodId = #PeriodId
QueryParam, EventId, PeriodId will be filled from C# code.
Here is my C# code:
private List<GenerateModel> getDataTopFromStoreProcedure(string EventId, string PeriodId)
{
// query select parameter
string QueryParam = #"cg.Chance_Number, th.new_name as [th name], dateadd(HOUR,7,th.createdon) as [th createdon],
c.new_Initial, c.FirstName, c.LastName";
string ConnString = GenerateChance.Properties.Settings.Default["DB_ConnectionString"].ToString();
using (SqlConnection conn = new SqlConnection(ConnString))
{
SqlCommand cmd = new SqlCommand();
cmd.CommandText = GetMembersDetailGenerateChanceTop10000;
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandTimeout = 0; //no limit
cmd.Parameters.Clear();
cmd.Parameters.Add(new SqlParameter("QueryParam", QueryParam));
cmd.Parameters.Add(new SqlParameter("EventId", EventId));
cmd.Parameters.Add(new SqlParameter("PeriodId", PeriodId));
cmd.Connection = conn;
if (conn.State == ConnectionState.Open)
conn.Close();
conn.Open();
using (SqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
list.Add(new GenerateModel
{
ChanceNumber = reader["Chance_Number"].ToString(), //System.IndexOutOfRangeException Error
Receipt = reader["th name"].ToString(),
Date = reader["th createdon"].ToString(),
Initial = reader["new_Initial"].ToString(),
FirstName = reader["FirstName"].ToString(),
LastName = reader["LastName"].ToString(),
});
}
reader.Close();
}
}
return list;
}
I am confused as to how to implement his method because I want to get return of all select results in object model but I always get error
System.IndexOutOfRangeException : Chance_Number.
Honestly why do I use query select parameter is because I want to get value from checkedListBox1 that already I defined before by using this code get all checkedListBox1 value to determine select query.
string QueryParam = "cg.Chance_Number";//auto get chance_number as select mandatory
for (int i = 0; i < checkedListBox1.CheckedItems.Count; i++)
{
QueryParam += ", " + ((clsItemList)checkedListBox1.CheckedItems[i]).Value;
}
You have to use constructor with proper length for parameters as given below, to avoid the issue.Read more on SQLParameter
public SqlParameter (string parameterName, System.Data.SqlDbType dbType, int size);
cmd.Parameters.Add(new SqlParameter("QueryParam", SqlDbType.NVarChar,1000)).Value = QueryParam;
You need to make few more changes:
The way you have defined the procedure is wrong. You have to define the procedure as dynamic sql for the #queryparam to get concatenated to the SELECT query as given below:
DECLARE #selectStmt NVARCHAR(MAX) = ''
DECLARE #sqldefinition NVARCHAR(4000) = '#EventId nvarchar(255), #PeriodId nvarchar(255)'
SET #selectStmt += 'select distinct top 10000 ' + #QueryParam +
'from ign..Chance_Generated cg
inner join ign..Contact c on cg.ContactID = c.ContactId
left join ign..CustomerAddress ca on ca.parentid = cg.contactid
left join ign..new_cardlevelconfig cl on cl.new_cardlevelconfigid = c.new_cardlevel
left join ign..new_country co on co.new_countryid = c.new_country
left join ign..new_province po on po.new_provinceId = c.new_Province
left join ign..StringMap sm on sm.AttributeValue = c.new_IDType
left join ign..new_city cy on cy.new_cityId = c.new_CityCounty
left join ign..new_transactionheader th on cg.New_Name COLLATE DATABASE_DEFAULT = th.new_name COLLATE DATABASE_DEFAULT
where cg.EventId= '''+ #EventId +''' and (ca.AddressNumber = ''1'' or ca.AddressNumber is null) and (sm.AttributeName is null or sm.AttributeName = ''new_idtype'')
and cg.periodId = ''' + #PeriodId + ''';'
EXEC #sp_executesql #selectStmt, #sqldefinition, #EventId , #PeriodId
``
- Always refer the tables with proper schema in the query
ign.SchemaName.new_country
ign.SchemaName.new_province

simplifying non-parametrized mysql queries

I have a problem with mySql query below
SELECT name, hospitalID, currentAvgRating, rank
FROM ( SELECT name,hospitalID,currentAvgRating,city,
#curRank := #curRank + 1 AS rank
FROM hospitals h, ( SELECT #curRank := 0) r
ORDER BY currentAvgRating DESC
) toplist
WHERE toplist.hospitalID = #hospitalID
and city = #city
This query I am using to find the rank of particular item & it is working properly. But while runining in program I get Fatal errors of Parameter '#curRank' must be defined. But that is mysql syntax then how can I get it's parameters?
UPDATE
string str = "SELECT name, hospitalID, currentAvgRating, rank FROM (SELECT name,hospitalID,currentAvgRating,city,#curRank := #curRank + 1 AS rank FROM hospitals h, (SELECT #curRank := 0) r ORDER BY currentAvgRating DESC) toplist WHERE toplist.hospitalID = #hospitalID and city = #city";
con.Open();
MySqlCommand cmd = new MySqlCommand(str, con);
cmd.Parameters.AddWithValue("#hospitalID", generalID.Text);
cmd.Parameters.AddWithValue("#city", cityName.Text);
MySqlDataAdapter da = new MySqlDataAdapter(cmd);
DataTable dt = new DataTable();
da.Fill(dt);
con.Close();
You can get the rank for a particular hospital/city pair without a rank. Here is a close approximation to your query:
select count(*) + 1 as ranking
from hospitals h cross join
(select h.currentAvgRating
from hospitals h
where h.hospitalID = #hospitalID and h.city = #city
) hh
where h.currentAvgRating > hh.currentAvgRating;
Unlike your code, this gives all hospitals with the same rating, the same ranking.
If you don't want to change the code, then refer to this answer. Actually, I'll quote the relevant part:
I have to add
;Allow User Variables=True
to the connection string
Your SQL is correct I think there are conflect with C# command parameter and mySQL parameter
try this modification of SQL code like this
SELECT name, hospitalID, currentAvgRating, rank
FROM ( SELECT name,hospitalID,currentAvgRating,city,
#curRank := #curRank + 1 AS rank
FROM hospitals h, ( SELECT #curRank := 0) r
ORDER BY currentAvgRating DESC
) toplist
WHERE toplist.hospitalID = ?hospitalID
and city = ?city
you c# like this
string str = <Example Above>;
con.Open();
MySqlCommand cmd = new MySqlCommand(str, con);
cmd.Parameters.AddWithValue("?hospitalID", generalID.Text);
cmd.Parameters.AddWithValue("?city", cityName.Text);
MySqlDataAdapter da = new MySqlDataAdapter(cmd);
DataTable dt = new DataTable();
da.Fill(dt);
con.Close();
Just changeing the C# command parameter using ? than using #

How to declare sql variable in C#

My requirement is to remove all record but one from a table. For this I am executing a series of two different sql commands. Seems like on ssms it works fine but with C# is not
--This is what I run on ssms without any issue
DECLARE #int INT;
SELECT #int = COUNT(*)
FROM [Table]
WHERE STATE = 'CO';
--Delete statement
DELETE TOP (#int - 1 )
FROM [Table] ;
public static void ClearData(string state)
{
const string queryToExec = #"DECLARE #int INT;" +
"SELECT #int = COUNT(*) " +
"FROM [Table] " +
"WHERE STATE = #State;" +
"DELETE TOP (#int - 1 ) " + //NOTICE THIS LINE
"FROM [Table] ";
List<SqlParameter> param = new List<SqlParameter>()
{
new SqlParameter {ParameterName = "#State", SqlDbType = SqlDbType.VarChar, Value = state},
};
ExecQuery(queryToExec, param);
}
public static void ExecQuery(string query, List<SqlParameter> paramCollection = null)
{
using (SqlConnection conn = new SqlConnection(ConnString))
{
using (SqlCommand mySqlCom = new SqlCommand())
{
mySqlCom.CommandText = query;
if (paramCollection != null) mySqlCom.Parameters.AddRange(paramCollection.ToArray());
mySqlCom.Connection = conn;
conn.Open();
mySqlCom.ExecuteNonQuery();
}
}
}
My qsns
How can I declare a sql variable correctly in C# (see ClearData method)
And, how to execute multiple queries in a single query string?(if I am doing this right)
EDIT
I came up with this to accomplish this. But still now luck. Please advise me to what to do:
IF OBJECT_ID ( 'uspWageDataByState', 'P' ) IS NOT NULL
DROP PROCEDURE uspWageDataByState;
GO
CREATE PROCEDURE uspWageDataByState
#State NVARCHAR(2)
AS
DECLARE #int INT
SET #int = (SELECT COUNT(*)
FROM [Test]
WHERE [STATE] = #State)
DELETE TOP (#int - 1 )
FROM [Test]
WHERE [STATE] = #State;
GO
exec uspWageDataByState 'CO'
I have run exactly this code in my environment and it is working as expected.
My framework version is 4.5.51641 and my SQL Version is SQL Server 11.0.2100
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data.SqlClient;
using System.Data;
namespace PruebasSQL
{
class Program
{
const string ConnString = #"";
static void Main(string[] args)
{
ClearData("A");
}
public static void ClearData(string state)
{
const string queryToExec = #"DECLARE #int INT;" +
"SELECT #int = COUNT(*) " +
"FROM [Table] " +
"WHERE STATE = #State;" +
"DELETE TOP (#int - 1 ) " + //NOTICE THIS LINE
"FROM [Table] ";
List<SqlParameter> param = new List<SqlParameter>()
{
new SqlParameter {ParameterName = "#State", SqlDbType = SqlDbType.VarChar, Value = state},
};
ExecQuery(queryToExec, param);
}
public static void ExecQuery(string query, List<SqlParameter> paramCollection = null)
{
using (SqlConnection conn = new SqlConnection(ConnString))
{
using (SqlCommand mySqlCom = new SqlCommand())
{
mySqlCom.CommandText = query;
if (paramCollection != null) mySqlCom.Parameters.AddRange(paramCollection.ToArray());
mySqlCom.Connection = conn;
conn.Open();
mySqlCom.ExecuteNonQuery();
}
}
}
}
}
Try changing your query (queryToExec) to:
ALTER PROCEDURE uspWageDataByState
#State NVARCHAR(2)
AS
DELETE TOP
(CASE
(SELECT COUNT(*) FROM [Test] WHERE [STATE] = #State)
WHEN 0 THEN 1
ELSE (SELECT COUNT(*) FROM [Test] WHERE [STATE] = #State) END -1)
FROM [Test]
WHERE [STATE] = #State;
If the declared variable is the problem you can troubleshoot with this. It's not the best query, but your form wasn't either :P
I'm adding a 0 rows validation. In the previous implementation the stored procedure crashed when no data was found.
execute multiple queries in a single string statement :
string querystring = "select [yourcolumns] from [yourtable];select [yourvalues] from [yourtables]";
sqlcommand cmd = new sqlcommand(querystring,yourconnection);
sqlDataReader reader = cmd.executeReader();
do
{
while(reader.Read())
{
//get your values here
}
}while(reader.NextResult());
DECLARE #PageSize INT = 5, #PageNum INT = 1
SELECT tickets.ID, tickets.userID FROM tickets WHERE tickets.isActive = 1
OFFSET (#PageNum-1)*#PageSize ROWS FETCH NEXT #PageSize ROWS ONLY
in that way works in aspnet sqlcommand and datareader

stored procedure returns many records but datareader sees only one

I created a SQL Server stored procedure in which I use a cursor and I created an ASP.NET method to execute that procedure. I'm using a SqlDataReader and while(reader.Read()) to read the values. The problem is that the cursor in the stored procedure returns many rows, but the method reads the first record only. Anyone can help?
stored procedure:
create procedure [dbo].[GetMenusUserGroupCanView]
(
#UserGroupID int
,#LanguageID int
) as begin
declare #MenuID int
declare #Title varchar(255)
declare db_cursor cursor for
(
select MenuID
from TrioGate.dbo.Sys_UserGroupMenus
where UserGroupID=#UserGroupID and ViewFlag='true'
)
open db_cursor
fetch next from db_cursor into #MenuID
while ##fetch_status = 0 begin
select
Sys_Menus.MenuID
,Sys_Menus.ParentMenuID
,Sys_Menus.DescriptionLabelID
,Sys_Menus.TitleLabelID
,Sys_Menus.TooltipLabelID
,Sys_Menus.[Icon]
,Sys_Menus.[MenuName]
,Sys_Menus.[MenuTypeID] as MenuType
,[dbo].[Get_ParentMenu_Name](Sys_Menus.ParentMenuID) as ParentMenuName
,[dbo].[Get_Label_Description](Sys_Menus.TitleLabelID,1) as Title
,[dbo].[Get_Label_Description](Sys_Menus.TooltipLabelID,1) as Tooltip
,[dbo].[Get_Label_Description](Sys_Menus.DescriptionLabelID,1) as [Description]
,Sys_Menus.[MainTableName] as [Table]
,Sys_Menus.[Seq],Sys_Menus.[MenuPath],Sys_Menus.ActivateLog,Sys_Menus.MenuID
from Sys_Menus
left join Sys_LabelDetails
on Sys_Menus[TitleLabelID] = Sys_LabelDetails[LabelID]
where Sys_LabelDetails.LanguageID = #LanguageID
and MenuID = #MenuID
fetch next from db_cursor into #MenuID
end
close db_cursor
deallocate db_cursor
end
Method:
public List<Menu> GetMenusUserGroupCanView(int UserGroupID, int LanguageID)
{
List<Menu> list = new List<Menu>();
SqlCommand cmd = new SqlCommand("GetMenusUserGroupCanView ", Connection);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#UserGroupID", UserGroupID);
cmd.Parameters.AddWithValue("#LanguageID", LanguageID);
try
{
Connection.Open();
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
Menu entry = new Menu();
entry.MenuID = (int)reader["MenuID"];
entry.ParentMenuID = (int)reader["ParentMenuID"];
entry.ActivateLog = (bool)reader["ActivateLog"];
entry.Description = reader["Description"].ToString();
entry.DescriptionLabelID = (int)reader["DescriptionLabelID"];
entry.Icon = (byte[])reader["Icon"];
entry.MainTableName = reader["Table"].ToString();
entry.MenuName = reader["MenuName"].ToString();
entry.MenuPath = reader["MenuPath"].ToString();
entry.MenuTypeID = reader["MenuType"].ToString();
entry.ParentMenuName = reader["ParentMenuName"].ToString();
entry.Seq = (int)reader["Seq"];
entry.Title = reader["Title"].ToString();
entry.TitleLabelID = (int)reader["TitleLabelID"];
entry.Tooltip = reader["Tooltip"].ToString();
entry.ToolTipLabelID = (int)reader["ToolTipLabelID"];
list.Add(entry);
}
}
catch { }
finally
{
Connection.Close();
}
return list;
}
Each iteration of your loop performs a select. So, instead of one set of multiple records, you're getting multiple sets.
Choose your destiny:
A. (treat the symptom): advance your reader between resultsets with IDataReader.NextResult()
or B. (fix the problem): There's no need for that cursor; use a join instead:
select
* /* dump your columns back in here */
from Sys_UserGroupMenus as g
join Sys_Menus as m
join Sys_LabelDetails as d
on d.LabelID = m.TitleLabelID
and d.LanguageID = #LanguageID
on m.MenuID = g.MenuID
where g.UserGroupID = #UserGroupID
and g.ViewFlag = 'true'

Categories

Resources