I'm trying to create stored procedures from a c# program. It typically reads the sproc definition from a text file, and then run it against the chosen database.
My SQL script file looks like this:
DROP PROCEDURE IF EXISTS MySproc;
DELIMITER //
CREATE PROCEDURE MySproc(
IN Id BIGINT,
IN Reference VARCHAR(255),
IN Bla VARCHAR(255)
)
BEGIN
INSERT INTO TableA(`Id`, `Reference`) VALUES(Id, Reference);
INSERT INTO TableB(`Id`, `Bla`) VALUES(Id, Bla);
END
//
DELIMITER ;
and this works fine in the workbench.
I then execute it with this type of c# code:
using (MySqlCommand sqlCommand = _mySqlConnection.CreateCommand())
{
sqlCommand.Connection = _mySqlConnection;
sqlCommand.CommandText = scriptfile;
sqlCommand.CommandType = CommandType.Text;
sqlCommand.ExecuteNonQuery();
}
And it errors with:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'DELIMITER //
CREATE PROCEDURE MySproc( IN Id BIGINT
' at line 1
If I remove the DELIMITER // stuff, then it still parses the semi colons between BEGIN and END as a delimiter for the outer statement, and it errors with:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'END' at line 31
Any idea how I can set either the Command or the something int he script so that it works? Not even sure if the error actually comes from MySQL itself, or from the MySqlCommand library (MySql.Data.6.9.9). And MySQL server is 5.6.25, InnoDB tables.
Can you try replacing the DELIMITER // with something like delimiter $$
Pointless question, sorry, it's embarrassing. This morning, I created a unit test following the top part of this page: https://dev.mysql.com/doc/connector-net/en/connector-net-programming-stored-using.html
and it works fine:
[TestMethod]
public void TestSprocCreationFromMySqlDoc()
{
// from https://dev.mysql.com/doc/connector-net/en/connector-net-programming-stored-using.html
MySqlConnection conn = new MySqlConnection();
conn.ConnectionString = "server=localhost;user=root;database=test;port=3306;password=;";
MySqlCommand cmd = new MySqlCommand();
try
{
Console.WriteLine("Connecting to MySQL...");
conn.Open();
cmd.Connection = conn;
cmd.CommandText = "DROP PROCEDURE IF EXISTS add_emp";
cmd.ExecuteNonQuery();
cmd.CommandText = "DROP TABLE IF EXISTS emp";
cmd.ExecuteNonQuery();
cmd.CommandText = "CREATE TABLE emp (empno INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, first_name VARCHAR(20), last_name VARCHAR(20), birthdate DATE)";
cmd.ExecuteNonQuery();
cmd.CommandText = "CREATE PROCEDURE add_emp(" +
"IN fname VARCHAR(20), IN lname VARCHAR(20), IN bday DATETIME, OUT empno INT)" +
"BEGIN INSERT INTO emp(first_name, last_name, birthdate) " +
"VALUES(fname, lname, DATE(bday)); SET empno = LAST_INSERT_ID(); END";
cmd.ExecuteNonQuery();
}
finally
{
conn.Close();
}
}
Then, I did another test with my own statements (trying to replicate file read from disk, with crlf) and it works too!
cmd.CommandText =
"DROP PROCEDURE IF EXISTS MySproc; " + Environment.NewLine +
"CREATE PROCEDURE MySproc(" + Environment.NewLine +
"IN Id BIGINT," + Environment.NewLine +
"IN Reference VARCHAR(255)," + Environment.NewLine +
"IN Bla VARCHAR(255))" + Environment.NewLine +
"BEGIN " + Environment.NewLine +
"INSERT INTO TableA(`Id`, `Reference`) VALUES(Id, Reference); " + Environment.NewLine +
"INSERT INTO TableB(`Id`, `Bla`) VALUES(Id, Bla); " + Environment.NewLine +
"END";
cmd.ExecuteNonQuery();
And then I ran my original application (that read scripts from files) and it runs ok as well! So I can't explain it. I'm wondering if I did something to the MySql server that affected all connections, or did something in one connection that stayed on, affecting all connections, until a reboot.
Related
Recently, I have been working on a C# plugin for a game I play. My problem at the moment is that the query listed below is generating many errors, such as these errors:
MySql.Data.MySqlClient.MySqlException: Data too long for column 'lastServer' at row 1
^^This error shows when my lastServer data type is varchar(10), but when I changed it to varchar(25), it went away. However I would still like to know why this would be, if anyone is able to figure it out.
.
My current error is having #lastServer, #characterName, and #ip showing up as #lastServer, #characterName, and #ip instead of their "AddWithValue" values.
Here's the query used for Table Creation:
command.CommandText = string.Concat("CREATE TABLE `", MDiscipline.Instance.Configuration.Instance.PlayerInfoTableName, "` (`steamId` varchar(32) NOT NULL,`characterName` varchar(40) NOT NULL,`ip` varchar(15) NOT NULL, `lastPunishment` tinyint(2) UNSIGNED NOT NULL,`lastServer` varchar(25) NOT NULL,`lastLogin` TIMESTAMP NOT NULL DEFAULT current_timestamp, PRIMARY KEY (`steamId`)) ");
And Here is the Code I'm having problems with:
public void UpdatePlayerInfo(string steamid, string characterName, string ip)
{
try
{
MySqlConnection connection = createConnection();
MySqlCommand command = connection.CreateCommand();
command.Parameters.AddWithValue("#steamId", steamid);
command.Parameters.AddWithValue("#characterName", characterName);
command.Parameters.AddWithValue("#ip", ip);
command.Parameters.AddWithValue("#lastServer", MDiscipline.Instance.Configuration.Instance.Instance);
command.CommandText = "UPDATE `" + MDiscipline.Instance.Configuration.Instance.PlayerInfoTableName + "` SET `characterName` = '#characterName', `ip` = '#ip', `lastServer` = '#lastServer', `lastLogin` = NOW() WHERE `steamId` = '" + steamid.ToString() + "';";
connection.Open();
command.ExecuteNonQuery();
connection.Close();
}
catch (Exception ex)
{
Logger.LogException(ex);
}
}
Helpful info to understand variables:
MDiscipline.Instance.Configuration.Instance.PlayerInfoTableName can be translated to "player_info".
steamid or (#steamId) can be translated to a 32 char number.
characterName or (#characterName) can be translated to any value between 1 and 30 characters.
ip or (#ip) can be translated to an ip address in a string, such as "255.255.255.255".
MDiscipline.Instance.Configuration.Instance.Instance or (#lastServer) can be translated to Server01.
I am building a C# console application that restores a SQL Server database with pre defined parameters that can be modified in a switch menu. The focus of this application is simplicity. It's designed for anyone to be able to restore a SQL Server database at the press of a button. Yes, there should be someone who can perform this task competently, but there's a lot of ways things should be done... Regardless I've built the logic to loop through the backup directories and pick out the correct backup files based on a point in time. Everything works except the actual restore part.
From other questions I've read, I fear that it isn't possible to run SQL from C# that modifies the server in this way. I am reluctant to use SMO objects, because that involves extra complexities that I want to avoid, but if it is the only way I can do this, then that's what I'll do.
Whenever I try and run this code it complains that the #dbName value is invalid.
public static void RestoreDatabase(string Server_Name, string Instance_Name, string DB_Name, FileInfo BakFile, FileInfo DiffFile, FileInfo TrnFile, DateTime Point_In_Time)
{
SqlConnection conn = new SqlConnection();
conn.ConnectionString = "Data Source=" + Server_Name + "\\" + Instance_Name + ";Initial Catalog=master;Integrated Security=True";
string SqlQuery = #"ALTER DATABASE #dbName
SET SINGLE_USER
WITH ROLLBACK IMMEDIATE;
RESTORE DATABASE #dbName
FROM DISK = #BakFilePath
WITH NORECOVERY, REPLACE;
RESTORE DATABASE #dbName
FROM DISK = #DiffFilePath
WITH NORECOVERY;
RESTORE DATABASE #dbName
FROM DISK = #TrnFilePath
WITH RECOVERY, STOPAT = #RecoveryTime;
ALTER DATABASE #dbName
SET MULTI_USER;";
SqlCommand cmd = new SqlCommand();
cmd.CommandType = System.Data.CommandType.Text;
cmd.Connection = conn;
cmd.CommandText = SqlQuery;
try
{
cmd.Parameters.Add(new SqlParameter("#dbName", SqlDbType.NVarChar, 30));
cmd.Parameters.Add(new SqlParameter("#BakFilePath", SqlDbType.NVarChar, 255));
cmd.Parameters.Add(new SqlParameter("#DiffFilePath", SqlDbType.NVarChar, 255));
cmd.Parameters.Add(new SqlParameter("#TrnFilePath", SqlDbType.NVarChar, 255));
cmd.Parameters.Add(new SqlParameter("#RecoveryTime", SqlDbType.DateTime));
cmd.Parameters["#dbName"].Value = DB_Name;
cmd.Parameters["#BakFilePath"].Value = BakFile.FullName;
cmd.Parameters["#DiffFilePath"].Value = DiffFile.FullName;
cmd.Parameters["#TrnFilePath"].Value = TrnFile.FullName;
cmd.Parameters["#RecoveryTime"].Value = Point_In_Time;
}
catch (Exception ex)
{
Console.WriteLine(ex);
Console.ReadLine();
}
try
{
Console.WriteLine("Restoring {0}...", DB_Name);
cmd.Connection.Open();
cmd.ExecuteNonQuery();
cmd.Connection.Close();
Console.WriteLine("Restore Complete!");
Console.ReadLine();
}
catch (SqlException ex)
{
Console.WriteLine("Connection could not open. Error: {0}", ex);
Console.ReadLine();
}
}
8/15/2016 10:38
Based on some of the answers, you guys are recommending dynamic SQL. I was worried about SQL injection, but only admins will have access to this program. Regardless I'll still add stricter validation because who doesn't love putting garbage input in for kicks.
I had attempted dynamic SQL. This was my code, however I did not spend much time checking for errors, so I'll go that route again and try and clean up any mistakes.
string SqlQuery = string.Format(#"DECLARE #dbName NVARCHAR(MAX), #strSQL NVarchar(MAX)=N'';
SET #dbName = {0};
SELECT
#strSQL += 'DECLARE #BakFilePath nvarchar(255) = N''{1}'','
+ N' #DiffFilePath nvarchar(255) = N''{2}'','
+ N' #TrnFilePath nvarchar(255) = N''{3}'','
+ N' #RecoveryTime DateTime = N''{4}'''
+ N' ALTER DATABASE '+ #dbName
+ N' SET SINGLE_USER'
+ N' WITH ROLLBACK IMMEDIATE;'
+ N' RESTORE DATABASE ' + #dbName
+ N' FROM DISK = #BakFilePath'
+ N' WITH NORECOVERY, REPLACE;'
+ N' RESTORE DATABASE ' + #dbName
+ N' FROM DISK = #DiffFilePath'
+ N' WITH NORECOVERY;'
+ N' RESTORE DATABASE ' + #dbName
+ N' FROM DISK = #TrnFilePath'
+ N' WITH RECOVERY, STOPAT = #RecoveryTime;'
+ N' ALTER DATABASE ' + #dbName
+ N' SET MULTI_USER;
'
EXEC sp_executesql #strSQL",DB_Name, BakFile.FullName, DiffFile.FullName, TrnFile.FullName, Point_In_Time);
unfortunately there is an issue with the way your SQL is written. I provided an answer to a question that had a similar underlying issue, you can find it here:
DROP PROCEDURE throws syntax error
sql-server will complain about the usage of:
Restore Database #dbName
Because it is being passed as a literal string. You would need to write something like this to execute your code.
declare #sql varchar(64);
set #sql = 'RESTORE DATABASE ' + #dbName;
exec(#sql);
Update
As per Scott's comment, using:
set #sql = 'RESTORE DATABASE ' + QUOTENAME(#dbName);
Will escape the string to create a valid SQL Server delimited identifier:
https://msdn.microsoft.com/en-us/library/ms176114.aspx
#dbName is invalid.
when passing a parameter you have to respect the rules of where variables are allowed to be used in sql syntax. When using a SELECT statement you can use a variable in the column definition or where clause but it cannot be used to reference a specific database object. The same holds true for ALTER DATABASE, ATLER TABLE, CREATE TABLE, etc.....
So basically the parameter cannot take place of the object name unless you then use dynamic sql such as building the sql string from the parameters as the other answer suggests. Dynamic SQL in this manner can be very open to SQL Injection attacks so you should make sure your source(s) are trusted.
Lastly you ask if it is possible and the answer is yes it is very possible to run backup/alter database commands etc. from c# as long as you user has permissions and your sql statement is correct it will execute.
You can't parameterize everything in SQL.
SELECT * FROM myTable WHERE customerID = #custID
is valid.
SELECT * FROM #tablename
is not. Neither is using ALTER DATABASE or RESTORE DATABASE with a parameter.
This is by design. The fix is to do the replacement in the string before you send it to SQL, but then of course you'll have to scrub the incoming parameters for bad things.
Thank you for everyone's answers, they lead me in the direction to choose dynamic SQL. The code below was the SQL solution that worked for me. I'll explain what's going on because holy cow does it get complicated (at least for me).
My C# application calls a function and I pass five parameters:
The database name
Full backup file path
Differential backup file path
Transactional backup file path
point in time to restore to
These values are then used in the SQL String's variable definitions. Once the variables are set in the SQL string, it then becomes regular dynamic SQL. Dynamic SQL is still a huge pain; figuring out all the single quotes caused me a lot of grief. Once the dynamic SQL is formatted correctly, it's just like any other SQL statement that is executed with C#.
UPDATE: Modified solution to include parameters for input values upon Scott Chamberlains request, and included the entire function as solution.
public static void RestoreDatabase(string Server_Name, string Instance_Name, string DB_Name,
FileInfo BakFile, FileInfo DiffFile, FileInfo TrnFile, DateTime Point_In_Time)
{
SqlConnection conn = new SqlConnection();
conn.ConnectionString = "Data Source=" + Server_Name + "\\" + Instance_Name + ";Initial Catalog=master;Integrated Security=True";
string SqlQuery = string.Format(#"DECLARE #strSQL NVARCHAR(MAX) =''
SELECT
#strSQL += N'ALTER DATABASE ' + QUOTENAME(#dbName)
+ N' SET SINGLE_USER'
+ N' WITH ROLLBACK IMMEDIATE;'
+ N' RESTORE DATABASE ' + QUOTENAME(#dbName)
+ N' FROM DISK = N''' + #BakFilePath + ''''
+ N' WITH NORECOVERY, REPLACE;'
+ N' RESTORE DATABASE ' + QUOTENAME(#dbName) +
+ N' FROM DISK = N''' + #DiffFilePath + ''''
+ N' WITH NORECOVERY;'
+ N' RESTORE DATABASE ' + QUOTENAME(#dbName)
+ N' FROM DISK = N''' + #TrnFilePath + ''''
+ N' WITH NORECOVERY, STOPAT = N''' + #RecoveryTime + ''';'
+ N' RESTORE DATABASE ' + QUOTENAME(#dbName)
+ N' WITH RECOVERY;'
+ N' ALTER DATABASE ' + QUOTENAME(#dbName)
+ N' SET MULTI_USER;
'
EXEC sp_executesql #strSQL");
SqlCommand cmd = new SqlCommand();
cmd.CommandType = System.Data.CommandType.Text;
cmd.Connection = conn;
cmd.CommandText = SqlQuery;
try
{
cmd.Parameters.Add(new SqlParameter("#dbName", SqlDbType.NVarChar, 30));
cmd.Parameters.Add(new SqlParameter("#BakFilePath", SqlDbType.NVarChar, 255));
cmd.Parameters.Add(new SqlParameter("#DiffFilePath", SqlDbType.NVarChar, 255));
cmd.Parameters.Add(new SqlParameter("#TrnFilePath", SqlDbType.NVarChar, 255));
cmd.Parameters.Add(new SqlParameter("#RecoveryTime", SqlDbType.NVarChar,30));
cmd.Parameters["#dbName"].Value = DB_Name;
cmd.Parameters["#BakFilePath"].Value = BakFile.FullName;
cmd.Parameters["#DiffFilePath"].Value = DiffFile.FullName;
cmd.Parameters["#TrnFilePath"].Value = TrnFile.FullName;
cmd.Parameters["#RecoveryTime"].Value = Point_In_Time.ToString();
}
catch (Exception ex)
{
Console.WriteLine(ex);
Console.WriteLine("Press any key to exit");
Console.ReadLine();
}
try
{
Console.WriteLine("Restoring {0}...", DB_Name);
cmd.Connection.Open();
cmd.ExecuteNonQuery();
cmd.Connection.Close();
Console.WriteLine("Restore Complete!");
Console.WriteLine("Press any key to exit");
Console.ReadLine();
}
catch (SqlException ex)
{
Console.WriteLine("Connection could not open. Error: {0}", ex);
Console.ReadLine();
}
}
Starting to learn sql and having trouble with my query. I have - 2 tables calendar and activities and FK table DateActivities. Got 2 simple lists calendar with dates and activities. I want to be able with a button click to enter new activity through text box on selected date. But when I do that I get error on a query. Thanks for your help.
private void btnAddToDate_Click(object sender, EventArgs e)
{
string query = "DECLARE #ActivitiesId TABLE (Id INT) " +
"INSERT INTO Activities (Name) " +
"OUTPUT INSERTED.ID INTO #ActivitiesId Id(Id) " +
"VALUES (#ActivitiesName) " +
"INSERT INTO DateActivities VALUES (#CalendarId, #ActivitiesId)";
using (connection = new SqlConnection(connectionString))
using (SqlCommand command = new SqlCommand(query, connection))
{
connection.Open();
command.Parameters.AddWithValue("#ActivitiesName", textDate.Text);
command.Parameters.AddWithValue("#CalendarId", listCalendar.SelectedValue);
command.ExecuteNonQuery();
}
FillCalendar();
FillActivities();
}
You are trying to execute multiple statement and thus need to separate them with ; as line terminator like below else it's treated as single statement to execute. If you just copy/paste the statement block in SSMS you will get the same error.
"DECLARE #ActivitiesId TABLE (Id INT); " +
"INSERT INTO Activities (Name) " +
"OUTPUT INSERTED.ID INTO #ActivitiesId Id(Id) " +
"VALUES (#ActivitiesName); " +
"INSERT INTO DateActivities VALUES (#CalendarId, #ActivitiesId)"
You should better pull this off to a stored procedure instead running as adhoc query.
You are inserting whole table in the column value of DateActivities which is obviously wrong and will fail, you need to use another variable to hold the ActivityId and then insert it next, see below:
"DECLARE #ActivitiesId TABLE (Id INT)
DECLARE #ActivityId INT " +
"INSERT INTO Activities (Name) " +
"OUTPUT INSERTED.ID INTO #ActivitiesId Id(Id) " +
"VALUES (#ActivitiesName) " +
"SELECT #ActivityId = Id from #ActivitiesId"
"INSERT INTO DateActivities VALUES (#CalendarId, #ActivityId)";
I'm trying to convert the following stored procedure into a query, so that I can use it in SQL Server CE
USE TestResults
GO
CREATE PROCEDURE uspInsertNewTest
(#DeviceSerialNumber nvarchar(50),
#DeviceType nvarchar(50),
#ElapsedTime int)
AS
BEGIN
INSERT INTO [TestResults].[dbo].[Tests]([Date], [Device], [DeviceType], [ExecutionTimeMs])
OUTPUT INSERTED.TestId
VALUES (GETDATE(), #DeviceSerialNumber, #DeviceType, #ElapsedTime)
END
GO
From the above script, all I can understand is that it takes three input parameters
DeviceSerialNumber
DeviceType
ElapsedTime
but it'll update 5 columns in the table Tests including Date and TestId.
Since I can't use stored procedures in SQL Server CE, I've converted the above script into a string query,
string queryString = "INSERT INTO Tests ([Date], [Device], [DeviceType], [ExecutionTimeMs]) VALUES (#Date, #DeviceSerialNumber, #DeviceType, #ElapsedTime)"
Now how to include OUTPUT INSERTED.TestId into the string( queryString ) ?
There's a similar question here, but it doesn't help my problem
Thanks!
You can use ##IDENTITY to return the last inserted identity value:
string queryString = "INSERT INTO Tests " +
"([Date], [Device], [DeviceType], [ExecutionTimeMs]) " +
"VALUES (#Date, #DeviceSerialNumber,#DeviceType, #ElapsedTime); " +
"SELECT ##IDENTITY;"
When you execute your query, you need to set it up to return a single value using the ExecuteScalar method:
var newIdentity;
// set up the queryString variable & command using the above
newIdentity = cmd.ExecuteScalar();
This assumes that the column TestId is an identity column.
Though I accepted Tanner's answer, but I ended up doing like this,
string queryString = "INSERT INTO Tests " + "([Date], [Device], [DeviceType], [ExecutionTimeMs]) " +
"VALUES (#Date, #DeviceSerialNumber,#DeviceType, #ElapsedTime)";
string queryString2 = "SELECT ##IDENTITY";
DbCommand command = factory.CreateCommand ();
command.CommandText = queryString;
// Added Parameters here
command.ExecuteNonQuery ();
command.CommandText = queryString2;
object testId = command.ExecuteScalar ();
So I had to split the query into two string & run ExecuteNonQuery with the first string and run ExecuteScalar with the second string.
I'm trying to make a program that allows me to store trends in an SQL Table. I need to add a hashtag entered into a textbox into the database if it doesn't already exist, and then increment a counter by 1.
The first column is "HashTag" and the second is "Counter" which has char(10) and int properties respectively.
I'm new to SQL, so it's posing a bit of a problem. This is what I have so far.
SqlConnection connection = new SqlConnection();
connection.ConnectionString = (#"Data Source=.\SQLEXPRESS;AttachDbFilename=C:\Users\Jordan Moffat\Desktop\coursework\WindowsFormsApplication\WindowsFormsApplication\HashTags.mdf;Integrated Security=True;Connect Timeout=30;User Instance=True");
connection.Open();
HashTagReader r = new HashTagReader();
if (r.HashTagSearch(s))
MessageBox.Show("I Found it!");
else
{
SqlCommand myCommand = new SqlCommand("INSERT INTO tblHashTag (HashTag, Counter) " + "Values (s, ++)", connection);
myCommand.ExecuteNonQuery();
}
connection.Close();
Any suggestions?
Change the Counter column to Identity(1,1) and it will auto increment. You can easily do this through SQL Management Studio.
Then change your query to:
SqlCommand myCommand = new SqlCommand("INSERT INTO tblHashTag (HashTag) Values ('" + s + '")", connection);
Note: I believe SqlCommand inherits from DbCommand which implements IDisposable. You should wrap these objects with a using() statement, like so to clean up any unmanaged resources:
using(SqlCommand myCommand = new SqlCommand("INSERT INTO tblHashTag (HashTag) Values ('" + s + '")", connection))
{
...
}
If you're on SQL 2008+, you have access to the merge statement. Something like so:
CREATE TABLE #tmp
(
[HashTag] VARCHAR(10) NOT NULL ,
[Counter] INT NOT NULL
);
MERGE [#tmp] AS t
USING
(
SELECT [HashTag] ,
[Counter]
FROM ( VALUES ( '#kitties', 3) ) AS f ( [HashTag], [Counter] )
) AS s
ON t.[HashTag] = s.[HashTag]
WHEN NOT MATCHED BY TARGET
THEN
INSERT ( [HashTag], [Counter] )
VALUES
( s.[HashTag] ,
s.[Counter]
)
WHEN MATCHED
THEN
UPDATE
SET
t.[Counter] += s.[Counter]
OUTPUT
$ACTION ,
INSERTED.* ,
DELETED.*;
I'm using an output clause here just so that it says what it's doing. Execute the merge statement multiple times and see how the output changes. If you're feeling frisky, wrap this in a stored procedure that takes two parameters (hashtag and counter) and you've got yourself something nice. Enjoy!
To add to Chris' answer, to avoid duplicate inserts you should (if you 're on SQL Server 2005 or higher) add a unique index to the HashTag column to enforce the restriction.
Then in the code you should use a WHERE NOT EXISTS clause. See here: SQL Server insert if not exists best practice
So you'd wind up with:
"INSERT INTO tblHashTag (HashTag)
Values ('" + s + "')
WHERE NOT EXISTS (SELECT HashTag
FROM tblHashTag
WHERE HashTag = '" + s + '")"
You can use Parameters to avoid sql injection :
string hashtag = "Your HashTagValue";
string counter = "Your Counter Value";
SqlCommand myCommand = new SqlCommand("INSERT INTO tblHashTag (HashTag, Counter) Values (#HashTag,#Counter)", connection);
myCommand.Parameters.Add("#HashTag", SqlDbType.varchar,50).Value = hashtag; //Your hashTagvalue
myCommand.Parameters.Add("#Counter", SqlDbType.varchar,50).Value = counter; //Your Counter Value
myCommand.ExecuteNonQuery();