Adding paramater to large SQL Statement in c# - c#

I have a large and somewhat complex SQL script that I'm using in .Net as below..
using System.Data.SqlClient;
using System.IO;
using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlServer.Management.Smo;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string sqlConnectionString = "Data Source=(local);Initial Catalog=AdventureWorks;Integrated Security=True";
FileInfo file = new FileInfo("C:\\myscript.sql");
string script = file.OpenText().ReadToEnd();
SqlConnection conn = new SqlConnection(sqlConnectionString);
Server server = new Server(new ServerConnection(conn));
server.ConnectionContext.ExecuteNonQuery(script);
}
}
}
Inside of the SQL script I have an ID value that needs to be a parameter that I pass in from my code, How can I do this? If I use a SQLCommand I could see the script becoming quite complex. Any suggestions or ideas on how to achieve this?
Thanks

You can specify params in file by their index ({0} input to String.Format) and use string.format to provide actual value in code.
FileInfo file = new FileInfo("C:\\myscript.sql");
string fileContent = file.OpenText().ReadToEnd();
//fileContent = "Select * from ABC where COL1 = '{0}'";
string Col1Value = "Col1Values";
string fileString = String.Format(fileContent,Col1Value);

Related

Azure function to parse CSV from FTP to save it in Azure SQL DB

I need a function that reads csv files from FTP source and insert the file contents (including a new column containing the file name in the rows of the file ) into a specified table in Azure SQL DB
I managed to read the contents of the CSV file as a string, and was able to insert it in a table as a row for the whole strng. but I would like to know how can I parse the CSV string or read the csv file through the azure function as a table frame (for example). I noticed that the library for reading and parsing CSV Microsoft.VisualBasic.IO is not available in the azure functions V.2 .NET CORE (was available in V.1 .NET FRAMEWORK before)
#r "Newtonsoft.Json"
#r "System.Data"
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Collections.Generic;
using System.Globalization;
using System;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System;
using System.IO;
using System.Net;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Primitives;
using Newtonsoft.Json;
using FluentFTP;
using System.Linq;
using System.Text;
public static async Task<IActionResult> Run(HttpRequest req, ILogger log)
{
using (FtpClient conn = new FtpClient())
{
conn.Host = "ftpLink";
conn.Credentials = new NetworkCredential("username", "pass");
//SQL connection
var connectionstring = Environment.GetEnvironmentVariable("sqldb_connection");
// get a list of files and directories in the "/OUT" folder
foreach (FtpListItem item in conn.GetListing("/OUT"))
{
// if this is a file and ends with CSV
if (
item.Type == FtpFileSystemObjectType.File
&&
item.FullName.ToLower().EndsWith(".csv")
)
{
//log.LogInformation(item.FullName);
var ftpUserName = "username";
var ftpPassword = "pass";
var filename = "/out/"+ item.Name;
string delimiter = ";";
DataTable dt = new DataTable();
FtpWebRequest fileRequest = (FtpWebRequest)WebRequest.Create("ftp://link" + filename);
fileRequest.Method = WebRequestMethods.Ftp.DownloadFile;
fileRequest.Credentials = new NetworkCredential(ftpUserName, ftpPassword);
WebClient client = new WebClient();
client.Credentials = new NetworkCredential(ftpUserName, ftpPassword );
using (SqlConnection SQLcon = new SqlConnection(connectionstring))
{
if (SQLcon.State == ConnectionState.Closed)
SQLcon.Open();
SqlCommand cmd = new SqlCommand();
cmd.Connection = SQLcon;
cmd.CommandType = CommandType.Text;
SqlDataReader reader;
try
{
// that reads the file content as string
byte[] newFileData = client.DownloadData("ftp://ftplink" + filename);
string fileString = System.Text.Encoding.UTF8.GetString(newFileData);
string query = $"INSERT INTO [brt].[record] ([record_string]) VALUES ('{fileString}')";
cmd.CommandText = query;
reader = cmd.ExecuteReader();
log.LogInformation(fileString);
}
catch (WebException e)
{
log.LogInformation(item.FullName);
}
}
}
}
return new OkObjectResult($"Hello");
}
}
I need to dump the CSV contents into an SQL table filling its contents from the CSV, then with an extra column showing the CSV file name for each row of contents. The table to be something like the following:
column1 column2 column3 column4 filename
2 4 5 a file1.csv

Trying to make a user input go through a LIKE SQL statement

Currently working on music guessing program. I have the user input lyrics and the program will try to find a match. If the program finds ones it will display the artist name. At the moment I am running trying to run a SELECT statement to find the most relevant match. When I hard code the element the console will give me the artists, but when I try to set it as the user input it displays nothing.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MySql.Data.MySqlClient;
using System.Data;
namespace Databasetesting
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Start\n");
// MySQL Database Connection String
string cs = #"server=192.168.0.5;userid=***;password=***;database= Music_Mixer;port=8889";
// set up connection
MySqlConnection con = null;
// make a reader
MySqlDataReader reader = null;
Console.WriteLine("Please enter song lyrics:");
string uI = Console.ReadLine();
// write a try catch statement
try
{
// cal in database
con = new MySqlConnection(cs);
// open connection
con.Open();
// Statement
String cmdText = "SELECT Artist FROM Songs WHERE Lyrics LIKE ('%#uI%')";
// make a new command
MySqlCommand cmd = new MySqlCommand(cmdText, con);
// binding
cmd.Parameters.AddWithValue("#uI", uI);
// make reader = to new command
reader = cmd.ExecuteReader();
// run the reader and display to user
while (reader.Read())
{
string Artists = reader["Artist"].ToString();
Console.WriteLine(Artists);
}
}
catch(MySqlException er)
{
Console.WriteLine(er);
}
finally
{
if(con != null)
{
con.Close();
}
Console.ReadLine();
}
}
}
}
Do this instead
string uI = "%" + Console.ReadLine() + "%";
you can also do string interpolation
string uI = $"%{Console.ReadLine()}%";
And your SQL statement
String cmdText = "SELECT Artist FROM Songs WHERE Lyrics LIKE #uI";
You can use string concatenation on the named parameter. In MySql you can try the concat operator || (depending on version, config ) or the concat function
isntead of ...LIKE ('%#uI%') go for ... LIKE concat('%',#uI,'%')
SELECT Artist FROM Songs WHERE Lyrics LIKE concat('%',#uI,'%')

Set connection string using a combobox 'selected' item using C#

I am self-learning C# using Visual Studio 2012 and stuck on a connection problem. Basically, I want to use a combobox to connect to a database based on the users selection.
For example: When the user selects TEST1 this will select the test1 database and TEST2 will enable test2 database..etc
The code I have pieced together uses a button which displays the results from a SQL script through a messagebox. At the moment I cant get this to work as the message box does not display anything.
I commented out the MainConnection() as that was a test to see if the connection was working.
Appreciate if someone could point me in the right direction.
Please see the C# code below:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Data.SqlClient;
namespace TestDB
{
public partial class Form1 : Form
{
class ComboItemExample
{
public string DisplayString { get; set; }
public string ConnectionString { get; set; }
public override string ToString() { return DisplayString; }
}
private string currentConnection = "Data Source= np-2 ;Initial Catalog= TESTDB Integrated Security=true";
public Form1()
{
InitializeComponent();
var firstConnection = new ComboItemExample { DisplayString = "Data Source= np-2 ;Initial Catalog= TESTDB1 Integrated Security=true" };
comboBox1.Items.Add("TEST1");
var secondConnection = new ComboItemExample { DisplayString = "Data Source= np-2 ;Initial Catalog= TESTDB2 Integrated Security=true" };
comboBox1.Items.Add("TEST2");
}
public void MainConnection()
{
//Make connection to np-2 TESTDB
//string str = "Data Source= np-hums12 ;Initial Catalog= TESTDB;"
//+ "Integrated Security=true";
// ReadOrderData(str);
}
public static void ReadOrderData(string currentConnection)
{
// Run SQL script
string queryString = "SELECT *;";
using (SqlConnection connection = new SqlConnection(currentConnection))
{
SqlCommand command = new SqlCommand(queryString, connection);
connection.Open();
SqlDataReader reader = command.ExecuteReader();
}
using (SqlConnection connection = new SqlConnection(ConnectionString))
{
SqlCommand command = new SqlCommand(queryString, connection);
connection.Open();
SqlDataReader reader = command.ExecuteReader();
// call read before accessing data.
while (reader.Read())
{
//display script in message box
MessageBox.Show(reader.GetValue(1).ToString());
}
// close when finished reading.
reader.Close();
}
}
private void CloseUI_Click(object sender, EventArgs e)
{
Application.Exit();
}
private void ShowData_Click(object sender, EventArgs e)
{
MainConnection();
}
private void comboBox1_SelectedIndexChanged_1(object sender, EventArgs e)
{
if (comboBox1.SelectedIndex <= 0) return;
var newConnection = ((ComboItemExample)comboBox1.Items[comboBox1.SelectedIndex]).ConnectionString;
// use "newConnection" as connection string.
currentConnection = newConnection;
using (var connection = new SqlConnection(currentConnection))
{
}
}
}
}
It looks like you're just adding the text value to your comboboxes, but not actually tying the connection string to it. You may be inadvertently passing the values "TEST1" and "TEST2" as connection strings. You should be adding the new variables you're creating in your constructor as the new items, not those strings. Use the Add() that takes an Item as a parameter.
mycombobox.Add(new Item("Test1", firstConnection));
Assuming your connection strings are correct and functioning, the reason it is displaying nothing is because it is throwing an error with your SQL.
This line is where your mistake lies
string queryString = "SELECT *;";
It is not a valid SQL query, you need to also specify a table. To help in the future, its is often wise to use try-catch statements to help identify potential errors.
For example in your code you could use
using (SqlConnection connection = new SqlConnection(ConnectionString))
{
SqlCommand command = new SqlCommand(queryString, connection);
try
{
connection.Open();
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
MessageBox.Show(reader.GetValue(1).ToString());
}
//dont need to close the reader as the using statement will dispose of it once finished anyway
}
connection.Close();
}
catch (Exception ex)
{
connection.Close();
Console.WriteLine(ex.Message);
//or, depending on the package Debug.WriteLine(ex.Message);
}
}
This will print out the exception and stop your program locking up too. As it stands, your current one won't throw an error saying nothing was found, but it will throw an SQL exception in the output log but won't give you details. Exeception.Message will give you details, or SqlException.Message can provide SQL related messages.
Edit: In response to the comment you posted (and something I missed previously)
Looking at the way you have added your ComboBox items, you haven't even added the objects that you think you have. From your code, your combobox items will be "TEST1" and "TEST2" - not the connection strings.
Instead, you could add your objects to the box like so
comboBox1.Items.Add(new ComboItemExample() {DisplayString ="TEST1",ConnectionString = "Data Source= np-2 ;Initial Catalog= TESTDB1 Integrated Security=true"});
comboBox1.Items.Add(new ComboItemExample() {DisplayString ="TEST2",ConnectionString = "Data Source= np-2 ;Initial Catalog= TESTDB2 Integrated Security=true"});
comboBox1.DisplayMember = "DisplayString";
comboBox1.ValueMember = "ConnectionString";
Then to retrieve the value from the combobox for your query
string myConnectionVal = comboBox1.SelectedValue.ToString();
The reason you are getting the cast error is because you never assigned the ComboItemExample to the combobox in the first place. With the item adding code above you would be able to do this in the future, but if all you need is a single value from the object, ValueMember is easier to use.

run .sql file over a collection of databases on an instance

FileInfo file = new FileInfo("C:\\LS\\SmartStats.sql");
string script = file.OpenText().ReadToEnd();
SqlConnection conn = new SqlConnection(sqlConnectionString);
Server server = new Server(new ServerConnection(conn));
server.ConnectionContext.ExecuteNonQuery(script);
I'm not sure where I pilfered this code from but it worked on a single database.
I'm new to C#.
I want to be able to call any .sql file from inside or outside the app. Can't I just string the .sql file and do a foreach over a collection of databases on any given instance?
//reference the following assemplyies of SMO
Microsoft.SqlServer.Management.Sdk.Sfc
Microsoft.SqlServer.ConnectionInfo
Microsoft.SqlServer.Smo
// using Microsoft.SqlServer.Management.Common;
//using Microsoft.SqlServer.Management.Smo;
public static void ExecuteScript(string fname, List<string> databases)
{
string script = File.ReadAllText(fname);
ServerConnection conn = new ServerConnection("server-name/instance", "user", "password");
Server SMOServer = new Server(conn);
// foreach (Database db in SMOServer.Databases) //for all databases in server
foreach (var dbname in databases)
{
var db = SMOServer.Databases[dbname];
var ds = db.ExecuteWithResults(script); //if you want query result as a Dataset
//db.ExecuteNonQuery(script); // if you run non return query result, e.g update/insert/delete
}
conn.Disconnect();
}
I am going to assume that you have the list of databases somewhere that you need to iterate over and that you can figure that part out.
Once you do that, the secret to making this work is the SQL USE statement. You just need to add this dynamically at the top of the script and everything should work correctly.
For example:
FileInfo file = new FileInfo("C:\\LS\\SmartStats.sql");
string script = file.OpenText().ReadToEnd();
SqlConnection conn = new SqlConnection(sqlConnectionString);
Server server = new Server(new ServerConnection(conn));
var databaseNames = new List<String> {"database1", "database2"};
foreach (var databaseName in databaseNames)
{
server.ConnectionContext.ExecuteNonQuery("USE " + databaseName + Environment.NewLine + "GO" + Environment.NewLine + script);
}

Inserting only part of a string into an SQL databases using C#

I'm a new C# coder and I am also new with Microsoft SQL Server. The code I have written will parse data from a file using filehelpers and then will place that data in a SQL table. My question is whether it can parse the data but only place part of the string in the SQL server. For example, here is my code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using FileHelpers;
using System.Data.SqlClient;
using System.IO;
namespace OnQ_prototype
{
class Report
{
[DelimitedRecord("\t")]
[IgnoreEmptyLines()]
public class ColumnReportNames
{
public String textbox22;
public String textbox29;
public String textbox24;
public String textbox23;
public String PSFullAcct;
public String AccountDescription;
public String BusDateAmount;
public String ThisPTDAmount;
public String LastPTDAmount;
public String ThisYTDAmount;
public String LastYTDAmount;
public String BusDatePctAvail;
public String ThisPTDPctAvail;
public String LastPTDPctAvail;
public String ThisYTDPctAvail;
public String LastYTDPctAvail;
}
static void ProcessFilesCSVFiles(string originalPath, string destinationPath)
{
foreach (var GenesisDirectory in Directory.GetDirectories(originalPath))
{
foreach (var inputFile in Directory.GetFiles(GenesisDirectory, "*.csv"))
{
string lines = inputFile;
FileHelperEngine engine = new FileHelperEngine(typeof(ColumnReportNames));
var records = engine.ReadFile(lines) as ColumnReportNames[];
foreach (var record in records)
{
SqlCommand cmd;
SqlConnection conn;
conn = new SqlConnection("Data Source=hureports01;Initial Catalog=hureports;Integrated Security=True");
conn.Open();
var sqlCommand = string.Format(#"MERGE [OnQReport] AS target USING (select #Property as Property, #Date_of_Report as Date_of_Report, #Percent_Occupancy_PAR as Percent_Occupancy_PAR, #val as {0}) AS source ON (target.Date_of_Report = source.Date_of_Report) WHEN MATCHED THEN UPDATE SET {0}= source.{0} WHEN NOT MATCHED THEN INSERT (Property, Date_of_Report, Percent_Occupancy_PAR, {0}) VALUES (source.Property, source.Date_of_Report, Percent_Occupancy_PAR, source.{0});", column);
cmd = new SqlCommand(sqlCommand, conn);
cmd.Parameters.AddWithValue("#Property", record.textbox24);
cmd.Parameters.AddWithValue("#Date_of_Report", record.textbox23);
cmd.Parameters.AddWithValue("#Percent_Occupancy_PAR", amount2);
cmd.Parameters.AddWithValue("#val", amount);
cmd.ExecuteNonQuery();
conn.Close();
}
So one of the values I am adding is Date_of_Report which is located in textbox23. However, the value of textbox23 is Business Date: 6/14/2016. Is there a way for it to only put the date in Date_of_Report (i.e. get rid of "Business Date:"
Try this:
string[] getDate = textBoxVal.Split(':');
string dateOfReport = getDate[1];
Are you storing this as a SQL datetime? You may want to convert it afterward.
Relevant fiddle: https://dotnetfiddle.net/ql40kl

Categories

Resources