I was creating a query for the Table Adapter that looked like this
SELECT COUNT(*) FROM Trip WHERE ShipCode = #ShipCode
AND Date < #TodayPlusWeek
The thing is this method will expect (string, string) as parameter where I need it to accept int for the (ShipCode) and Date for the (Date)
Any ideas how to do that?
Very much appreciated!
The first part will be to set up a pair of variables of the proper type to hold the correct values for the Sql Parameters:
int iShipCode;
DateTime dtTodayPlusWeek;
Once you have that, we are going to run a TryParse method on your current string variables to convert into our new variables. As I did not know the variable names within your method, I generic'd them to (strShipCode, strTodayPlusWeek). If the TryParse method fails, you can set up default values for the query; I used 0 and Today + 1 week.
if (!int.TryParse(strShipCode, out iShipCode)) {
iShipCode = 0;
}
if (!DateTime.TryParse(strTodayPlusWeek, out dtTodayPlusWeek)) {
dtTodayPlusWeek = DateTime.Now.AddDays(7);
}
Now that we have correct types for the data, we can add that to our existing query as parameters.
StringBuilder sbCmd = new StringBuilder();
sbCmd.Append("SELECT COUNT(*) ");
sbCmd.Append("FROM Trip ");
sbCmd.Append("WHERE (ShipCode = #ShipCode) ");
sbCmd.Append("AND Date < #TodayPlusWeek");
string txtCmd = sbCmd.ToString();
int iQryReturn;
using (SqlCommand cmd = new SqlCommand(txtCmd, conn)) {
cmd.CommandType = CommandType .Text;
cmd.Parameters.AddWithValue("#ShipCode", iShipCode;);
cmd.Parameters.AddWithValue("#TodayPlusWeek", dtTodayPlusWeek);
try {
conn.Open();
iQryReturn = (int)cmd.ExecuteScalar();
}
catch(Exception ex) {
iQryReturn = -1;
// Your Exception handling here
}
finally {
conn.Close();
// Your cleanup code if any
}
}
Not knowing what type of DB setup you have in use, I have written this in ADO for Sql Server. Ad there will only be value returned; the count(*), I have added an integer variable for a return. If there is an error, that value will be set to -1.
It is up to you on implementation and syntactical changes that may be needed for your particular application.
Related
This question already has answers here:
Converting the date time to display milliseconds in C#
(3 answers)
Closed 1 year ago.
The following query works as expected in MSSSMS version 18.1 on an Azure hosted SQL database table:
select Name, cast(MAX(DTStamp) as Datetime) AS Last_Seen FROM dbo.MyTable GROUP BY Name
Example output:
Fairyflosser29 2021-11-11 19:26:00.323
GoofballAnticz 2021-11-25 14:43:57.443
WeirdAlJankyVic 2021-12-01 19:30:20.341
However, the same SQL command in C# run through the following methods always cuts the milliseconds from the DateTime field, despite the cast and despite the way I write the cast. This is critical for me as my follow-up queries depend on the accuracy of the DateTime field being correct to the millisecond, otherwise the subsequent queries return nothing.
The process calls GetLastSeenList() which returns a comma-delimited list of records that represent the most recent (by date time stamp) records for each Name in the table. With the populated list, another method is called later on that uses these results to pull the full row for each item.
Because the datetime stamps include milliseconds, those subsequent queries must include the millisecond values otherwise the query fails even though there is a record.
First, get the list of names and when they were last seen. Next, pull the full row for each record in the last-seen list (not included here as the first query is not providing date-times as they are in the table - with milliseconds intact).
I'm not very adept with SQL, so please help me understand what I'm missing here.
Notes
1: The DTStamp column is defined as datetime
2: I've tried the cast inside and out, going to ridiculous lengths like: cast(MAX(cast(GPS_DTStamp as Datetime)) as Datetime) ...
[EDIT]: Just in case it's not clear, the sql command sqlcmd_GetLastSeenList is the same as the SSMS query at the top:
private static readonly string sqlcmd_GetLastSeenList =
#"select Name, cast(MAX(DTStamp) as Datetime) AS Last_Seen FROM dbo.MyTable GROUP BY Name;";
GetLastSeen:
internal static async Task<string> GetLastSeenList()
{
StringBuilder sb = new StringBuilder();
var list = await ReadSQL(sqlcmd_GetLastSeenList, false);
if(list != null && list.Count > 0)
{
// Just return a CSV list of ID's with last seen timestamps
foreach(var record in list)
sb.Append($"{record[0]} {record[1]},");
}
return sb.ToString().Trim(',');
}
ReadSQL:
private static async Task<List<object[]>> ReadSQL(string cmdText, bool isProd)
{
List<object[]> response = new List<object[]>();
string connect = string.Empty;
if (isProd)
connect = await SetConnectionProd(_uidProd, _p_pwd);
else
connect = await SetConnectionTest(_uidTest, _t_pwd);
try
{
using (SqlConnection conn = new SqlConnection(connect))
{
using (SqlCommand cmd = new SqlCommand(cmdText, conn))
{
response = await ExecuteQuery2(cmd, conn);
}
}
}
catch (Exception ex)
{
//TODO: log it
throw ex;
}
return response;
}
ExecuteQuery2:
private static async Task<List<object[]>> ExecuteQuery2(SqlCommand cmd, SqlConnection conn)
{
List<object[]> retval = new List<object[]>();
try
{
object[] myVals = new object[MAXCOLUMNCOUNT];
object[] myRow = null;
cmd.Connection.Open();
using(SqlDataReader sqlreader = cmd.ExecuteReader())
{
if(sqlreader.HasRows)
{
while(sqlreader.Read())
{
var count = sqlreader.GetValues(myVals);
myRow = new object[count];
Array.Copy(myVals, myRow, count);
retval.Add(myRow);
}
}
}
}
catch(Exception ex)
{
throw ex;
}
finally
{
cmd.Connection.Close();
}
return retval;
}
The miliseconds are there. They're just not displayed by default by DateTime.ToString(). EG:
var cmd = new SqlCommand("select cast('2021-11-11 19:26:00.323' as datetime) d", con);
using (var rdr = cmd.ExecuteReader())
{
rdr.Read();
var vals = new object[rdr.FieldCount];
rdr.GetValues(vals);
var val = (DateTime)vals[0];
Console.WriteLine($"{val.GetType().Name} {val} {val.ToString("O")}");
}
outputs
DateTime 11/11/2021 7:26:00 PM 2021-11-11T19:26:00.3230000
But also make sure you're not converting back and forth between datetime and datetime2, eg this
select cast(cast('2021-11-11 19:26:00.323' as datetime) as datetime2) d
outputs
d
---------------------------
2021-11-11 19:26:00.3233333
and this kind of conversion can be the source of mis-compares on subesquent queries.
Having a little bit of a strange error here that I have never encountered before. I have an application where users can type in a list of accounts in a datagrid and a date range and press a button and it will return the data for these accounts in a datagrid and give them the option to export it to an excel file. This works perfectly for me, logged in under my username and even when I log in under other people's username. The problem is when they try it, they get no data back. No errors, just it doesn't pull any data.
The interesting thing is this is all in the same database as the other information which they access without any problem. The only difference, which I think might be the explanation is I am calling this SQL code directly from the Application whereas everything else is called using stored procedures that sit on the server. The reason for this is I have to concatenate the SQL Query string for each item in the accounts field. Since they are able to enter as many accounts as they want, I cannot use a stored procedure since I don't know how many parameters it will have ultimately(if someone could let me know a method of doing this, I would actually prefer this way for keeping things consistent). Obviously the query string is working properly, as it's pulling data back for me, but the question I have is why is it failing to return data for others? The connection string is an SQL Authentication, so it shouldn't have anything to do with them not having Windows Authentication on the server, plus they are already able to log in to the application and it displays data on their dashboard, which couldn't happen...
Anyone that can point me in the right direction with this I would appreciate it...the only thing I can think of is it is an issue with using an in-code SQL string versus a stored procedure, but this doesn't make any sense since other people do this all the time in applications without issue.
public ICommand GetData
{
get => new RelayCommand(() =>
{
//call the SQL Code to lookup the account numbers
var SQLStr = "SELECT * FROM [Clients].[Data] WHERE (Account_Number = '";
for (var i = 0; i< AccountNums.Count; i++)
{
if (!String.IsNullOrEmpty(AccountNums[i].accNum)) SQLStr += i == 0 ? $"{AccountNums[i].accNum}'" : $" OR Account_Number = '{AccountNums[i].accNum}'";
}
SQLStr += $") AND SUB_QUERY_CREATED_ON BETWEEN '{StartDate.ToString()}' AND '{EndDate.ToString()}'";
_Data = DBMethods.GetSQLData(_Data, new Models.Clients.Data(), SQLStr, new List<string> { "ID" }, true);
ShowResPnl = true; //there are results, toggle the panel visibility bound variable
});
}
public static ObservableCollection<T> GetSQLData<T>(ObservableCollection<T> myCollection, T myClass, String SQLString, List<string> remParams, bool UseSQLQuery) where T : class
{
var conn = new SqlConnection();
try
{
var paramList = GenerateSQLParameters(myClass, remParams);
using (getConnection(conn))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand(SQLString, conn))
{
cmd.CommandType = CommandType.Text;
SqlDataReader reader;
reader = cmd.ExecuteReader();
//only execute if the reader has data
if (reader.HasRows)
{
while (reader.Read())
{
var tempModel = Global.GenerateNewInstance(myClass) as T;
Type model = tempModel.GetType();
var prop = model.GetProperties();
PropertyInfo pi;
//set the values for each property in the model
foreach (var p in prop)
{
if (!remParams.Contains(p.Name))
{
pi = tempModel.GetType().GetProperty(p.Name);
if (reader[p.Name] == DBNull.Value)
{
pi.SetValue(tempModel, null);
}
else
{
pi.SetValue(tempModel, reader[p.Name]);
}
}
}
myCollection.Add(tempModel);
}
reader.Close();
cmd.Dispose();
}
}
}
}
catch (Exception ex)
{
ErrorWindow errWin = new ErrorWindow("There was a problem trying to Get the Data with the Query '" + SQLString + "'! Error: " + ex.Message);
errWin.Show();
}
return myCollection;
}
UPDATE: OK I got it working perfectly with help from THIS thread:
How do I split a string so I can access item x?
and more specifically this post:
What about using string and values() statement?
DECLARE #str varchar(max)
SET #str = 'Hello John Smith'
DECLARE #separator varchar(max)
SET #separator = ' '
DECLARE #Splited TABLE(id int IDENTITY(1,1), item varchar(max))
SET #str = REPLACE(#str, #separator, '''),(''')
SET #str = 'SELECT * FROM (VALUES(''' + #str + ''')) AS V(A)'
INSERT INTO #Splited
EXEC(#str)
SELECT * FROM #Splited
I created a stored procedure using this, then did a left join on Account numbers from the Data Table and used a WHERE clause to set the Start and End Dates and exclude items that were NULL(checked one of the columns). Works perfectly and only took about 2 or 3 seconds to return the data. I had another working method as detailed here https://sqlperformance.com/2012/07/t-sql-queries/split-strings#comments using a function which was taking well over a minute to return data for only 4 accounts...obviously was not going to work well enough so I found the method mentioned prior and it works excellently!
I'm working on WCF project. I am trying to insert multiple records into my SQL Server database from an array.
when calling the service, I get an exception :"Procedure or function has too many arguments specified", while my arguments in my function are in confirmity with those declared in my stored procedure :
Here is my function in WCF :
public static string SetGaranties( List<int> CODE_GARANTIES, string NUMERO_POLICE, string CODE_BRANCHE, int CODE_SOUS_BRANCHE)
{
string MSG_ACQUITEMENT = string.Empty;
DbCommand com = GenericData.CreateCommand(GenericData.carte_CarteVie_dbProviderName, GenericData.Carte_CarteVie_dbConnectionString);
com.CommandText = "SetGaranties";
com.Parameters.Clear();
foreach (int CODE_GARANTIE in CODE_GARANTIES)
{
com.Connection.Open();
SqlParameter NUMERO_POLICE_Param = new SqlParameter("#NUMERO_POLICE", NUMERO_POLICE);
com.Parameters.Add(NUMERO_POLICE_Param);
SqlParameter CODE_BRANCHE_Param = new SqlParameter("#CODE_BRANCHE", CODE_BRANCHE);
com.Parameters.Add(CODE_BRANCHE_Param);
SqlParameter CODE_SOUS_BRANCHE_Param = new SqlParameter("#CODE_SOUS_BRANCHE", CODE_SOUS_BRANCHE);
com.Parameters.Add(CODE_SOUS_BRANCHE_Param);
SqlParameter CODE_POSTALE_Param = new SqlParameter("#CODE_GARANTIE", CODE_GARANTIE);
com.Parameters.Add(CODE_POSTALE_Param);
DbDataReader reader = com.ExecuteReader();
com.Connection.Close();
}
and here is my Stored procedure :
ALTER PROCEDURE [dbo].[SetGaranties]
#NUMERO_POLICE varchar(12),
#CODE_BRANCHE varchar(1),
#CODE_SOUS_BRANCHE int,
#CODE_GARANTIE int
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO dbo.MVT_GARANTIES VALUES(
#NUMERO_POLICE,
#CODE_BRANCHE,
#CODE_SOUS_BRANCHE,
#CODE_GARANTIE
);
END
Does anybody know how to fix this?
Build the parameters outside the loop just once, set the invariant values outside the loop and inside the loop just set only the one value that changes at each loop
public static string SetGaranties( List<int> CODE_GARANTIES, string NUMERO_POLICE, string CODE_BRANCHE, int CODE_SOUS_BRANCHE)
{
string MSG_ACQUITEMENT = string.Empty;
DbCommand com = GenericData.CreateCommand(GenericData.carte_CarteVie_dbProviderName, GenericData.Carte_CarteVie_dbConnectionString);
com.CommandText = "SetGaranties";
com.CommandType = CommandType.StoredProcedure;
// These parameter's values don't change, set it once
com.Parameters.Add("#NUMERO_POLICE", SqlDbType.VarChar).Value = NUMERO_POLICE;
com.Parameters.Add("#CODE_BRANCHE",SqlDbType.VarChar).Value = CODE_BRANCHE;
com.Parameters.Add("#CODE_SOUS_BRANCHE", SqlDbType.Int).Value = CODE_SOUS_BRANCHE;
// This parameter's value changes inside the loop
com.Parameters.Add("#CODE_GARANTIE",SqlDbType.Int);
com.Connection.Open();
foreach (int CODE_GARANTIE in CODE_GARANTIES)
{
com.Parameters["#CODE_GARANTIE"].Value = CODE_GARANTIE;
com.ExecuteNonQuery();
}
com.Connection.Close();
}
Other things to say:
You are using a global connection object, this usually is a very bad
idea. ADO.NET implements connection pooling and this means that you
should create your connection when you need it and destroy it
afterwards.
ExecuteNonQuery should be used when you INSERT/UPDATE/DELETE records.
No need to build an SqlDataReader when you don't have anything to
read back.
A Stored Procedure is executed only if you set the CommandType to
StoredProcedure otherwise you get a syntax error because the
CommandText is not a valid Sql Statement
This:
com.Parameters.Clear();
Should be inside your loop. With the current code the first iteration should have the correct number of parameters. But subsequent iterations will have too many because the the param list isn't being cleared.
I need to know, if I am writing the stored procedure correctly and If the C# code for executing is correct. for some reason the error being returned as is Incorrect syntax near 'c16b'. Old Error
The new error now is: Procedure or function 'sptimeupdate' expects parameter '#date', which was not supplied.
the nvarchar string for validating and updating in the column by ClientID is 3fc8ffa1-c16b-4d7b-9e55-1e88dfe15277, but the part in bold is only showing in the debug test intel sense in error handling
ALTER PROCEDURE sptimeupdate
#id nvarchar(50),
#date datetime
AS
BEGIN
SET NOCOUNT ON;
UPDATE ClientTable
SET Today_Date=(#date)
WHERE ClientID=(#id)
END
//--------------above stored procedure--------------------------------
//--------------Executing the stored procedure in C#
IEnumerable<XElement> searchClientID =
from clientid in main.XPathSelectElements("Network/ClientID")
where (string)clientid.Attribute("id") == IntializedPorts[i].ToString()
select clientid;
foreach (string clientid in searchClientID)
{
for (int up = 0; up < IntializedPorts.Count(); up++)
{
//Update the current time in the clientid tble.
//Renames the table copy for groups
try
{
string[] Clientid; //client id array
Clientid = new string[IntializedPorts.Count()]; //Intialization of the array
Clientid[up] = clientid.ToString();
DateTime td = Convert.ToDateTime(toolDate.Text); //Just added a datetime object withdate
SqlConnection sqlConnectionCmdString = new SqlConnection(#"Data=.\SQLEXPRESS;AttachDbFilename=C:\Users\Shawn\Documents\Visual Studio 2010\Projects\Server\database\ClientRegit.mdf;Integrated Security=True;User Instance=True");
//EXECUTE THE STORED PROCEDURE sptimedate
// string UpdateCommand = "sptimeupdate" + Clientid[up].ToString() + toolDate.Text;
string UpdateCommand = "sptimeupdate" + "'" + Clientid[up].ToString() + "'" + "'" +td.ToString()+ "'"; //this is the new UpdateCommand string as to pass parameters to stored procedure
SqlCommand sqlRenameCommand = new SqlCommand(UpdateCommand, sqlConnectionCmdString);
sqlConnectionCmdString.Open();
sqlRenameCommand.ExecuteNonQuery();
sqlConnectionCmdString.Close();
}
catch(DataException ex)
{ MessageBox.Show("Failed to UpdateCurrentTime","DataError",MessageBoxButtons.OK,MessageBoxIcon.Error);
}
}
}
When you call a stored procedure from code you need to create a command with its command type set to StoredProcedure, otherwise the engine tries to use your command text as it was an sql text like SELECT INSERT etc... But the mose important thing is that you need to pass the parameters required by the stored procedure in the Parameters collection of the command
So this could be the code to replace the actual one
string UpdateCommand = "sptimeupdate";
using(SqlConnection sqlConnectionCmdString = new SqlConnection(......))
using(SqlCommand sqlRenameCommand = new SqlCommand(UpdateCommand, sqlConnectionCmdString))
{
DateTime td = Convert.ToDateTime(toolDate.Text);
sqlRenameCommand.CommandType = CommandType.StoredProcedure;
sqlRenameCommand.Parameters.Add("#id", SqlDbType.NVarChar).Value = Clientid[up].ToString();
sqlRenameCommand.Parameters.Add("#date", SqlDbType.DateTime).Value = td;
sqlConnectionCmdString.Open();
sqlRenameCommand.ExecuteNonQuery();
}
Notice two things. The using statement is the best practice to follow when you create a connection to ensure the correct closing and disposing of the connection, second, the parameter for the DateTime expected by the sp should be passed as a DateTime not as a string- Of course this means that you should be certain that the content of toolDate is convertible to a DateTime value.
Your error is originating from this line of code:
string UpdateCommand = "sptimeupdate" + Clientid[up].ToString() + toolDate.Text;
There you are just concatenating the Clientid[up].ToString() as a string into the other string, same with the toolDate.Text, both without and sql markup.
Your resulting SQL query would look like this (assuming toolDate.Text is '2014-10-23'):
sptimeupdate3fc8ffa1-c16b-4d7b-9e55-1e88dfe152772014-10-23
which as you can see is not a proper SQL command.
You should always use parametrized command statements when calling simple SQL commands.
However in your case, you are actually calling a stored procedure.
So change your code to handle it like a stored procedure, example below.
// Create the connection object once
using (SqlConnection sqlConnectionCmdString = new SqlConnection(#"Data=.\SQLEXPRESS;AttachDbFilename=C:\Users\Shawn\Documents\Visual Studio 2010\Projects\Server\database\ClientRegit.mdf;Integrated Security=True;User Instance=True"))
{
// Same with the SqlCommand object and adding the parameters once also
SqlCommand sqlRenameCommand = new SqlCommand("sptimeupdate", sqlConnectionCmdString);
sqlRenameCommand.CommandType = CommandType.StoredProcedure;
sqlRenameCommand.Parameters.Add("#id", SqlDbType.NVarChar);
sqlRenameCommand.Parameters.Add("#datetime", SqlDbType.DateTime);
// Open the connection once only
sqlConnectionCmdString.Open();
foreach (string clientid in searchClientID)
{
for (int up = 0; up < IntializedPorts.Count; up++)
{
try
{
// The below three lines seem redundant.
// Clientid[up] will be equal to clientid after it all, so just use clientid
//string[] Clientid;
//Clientid = new string[IntializedPorts.Count];
//Clientid[up] = clientid.ToString();
sqlRenameCommand.Parameters["#id"].Value = clientid;
sqlRenameCommand.Parameters["#datetime"].Value = toolDate.Text;
sqlRenameCommand.ExecuteNonQuery();
}
// Might want to move this try..catch outside the two loops,
// otherwise you will get this message each time an error happens
// which might be alot, depending on the side of searchClientID
catch (SqlException)
{
MessageBox.Show("Failed to UpdateCurrentTime", "DataError", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
}
NOTE:
Please read the comments inside the code above for additional advice and suggestions.
Recreating a SqlConnection and SqlCommand for each iteration will have a performance impact on your application. So rather create them once and reuse them until you are done.
Further reading can be done here:
SqlCommand (There are nice examples at the bottom of that page)
dotnetperls version of SqlCommand
P.S. your sql procedure's code looks fine, you could remove the SET NOTCOUNT ON since that does not really do much in this scenario
I have a list Called ListTypes that holds 10 types of products. Below the store procedure loops and gets every record with the product that is looping and it stores it in the list ListIds. This is killing my sql box since I have over 200 users executing this constantly all day.
I know is not a good architecture to loop a sql statement, but this the only way I made it work. Any ideas how I can make this without looping? Maybe a Linq statement, I never used Linq with this magnitude. Thank you.
protected void GetIds(string Type, string Sub)
{
LinkedIds.Clear();
using (SqlConnection cs = new SqlConnection(connstr))
{
for (int x = 0; x < ListTypes.Count; x++)
{
cs.Open();
SqlCommand select = new SqlCommand("spUI_LinkedIds", cs);
select.CommandType = System.Data.CommandType.StoredProcedure;
select.Parameters.AddWithValue("#Type", Type);
select.Parameters.AddWithValue("#Sub", Sub);
select.Parameters.AddWithValue("#TransId", ListTypes[x]);
SqlDataReader dr = select.ExecuteReader();
while (dr.Read())
{
ListIds.Add(Convert.ToInt32(dr["LinkedId"]));
}
cs.Close();
}
}
}
Not a full answer, but this wouldn't fit in a comment. You can at least update your existing code to be more efficient like this:
protected List<int> GetIds(string Type, string Sub, IEnumerable<int> types)
{
var result = new List<int>();
using (SqlConnection cs = new SqlConnection(connstr))
using (SqlCommand select = new SqlCommand("spUI_LinkedIds", cs))
{
select.CommandType = System.Data.CommandType.StoredProcedure;
//Don't use AddWithValue! Be explicit about your DB types
// I had to guess here. Replace with the actual types from your database
select.Parameters.Add("#Type", SqlDBType.VarChar, 10).Value = Type;
select.Parameters.Add("#Sub", SqlDbType.VarChar, 10).Value = Sub;
var TransID = select.Parameters.Add("#TransId", SqlDbType.Int);
cs.Open();
foreach(int type in types)
{
TransID.Value = type;
SqlDataReader dr = select.ExecuteReader();
while (dr.Read())
{
result.Add((int)dr["LinkedId"]);
}
}
}
return result;
}
Note that this way you only open and close the connection once. Normally in ADO.Net it's better to use a new connection and re-open it for each query. The exception is in a tight loop like this. Also, the only thing that changes inside the loop this way is the one parameter value. Finally, it's better to design methods that don't rely on other class state. This method no longer needs to know about the ListTypes and ListIds class variables, which makes it possible to (among other things) do better unit testing on the method.
Again, this isn't a full answer; it's just an incremental improvement. What you really need to do is write another stored procedure that accepts a table valued parameter, and build on the query from your existing stored procedure to JOIN with the table valued parameter, so that all of this will fit into a single SQL statement. But until you share your stored procedure code, this is about as much help as I can give you.
Besides the improvements others wrote.
You could insert your ID's into a temp table and then make one
SELECT * from WhatEverTable WHERE transid in (select transid from #tempTable)
On a MSSQL this works really fast.
When you're not using a MSSQL it could be possible that one great SQL-Select with joins is faster than a SELECT IN. You have to test these cases by your own on your DBMS.
According to your comment:
The idea is lets say I have a table and I have to get all records from the table that has this 10 types of products. How can I get all of this products? But this number is dynamic.
So... why use a stored procedure at all? Why not query the table?
//If [Type] and [Sub] arguments are external inputs - as in, they come from a user request or something - they should be sanitized. (remove or escape '\' and apostrophe signs)
//create connection
string queryTmpl = "SELECT LinkedId FROM [yourTable] WHERE [TYPE] = '{0}' AND [SUB] = '{1}' AND [TRANSID] IN ({2})";
string query = string.Format(queryTmpl, Type, Sub, string.Join(", ", ListTypes);
SqlCommand select = new SqlCommand(query, cs);
//and so forth
To use Linq-to-SQL you would need to map the table to a class. This would make the query simpler to perform.