I have a query versus an SQL database in C#. From this query I get a List like:
List<List<string>>()
this list can be changed to any other table type if required..
In Microsoft Server Management Studio it looks like this:
In Microsoft SQL Server Management Studio you can simply output the result as text, which looks like this:
Now as I am automating some tasks I will use C# rather than manually using MSSQL. Due to a GXP environment it is important to have every datachange in the Database Documented separately with a text report attached to a "ticket".
For now my query with Table Text generation looks like this:
SqlCommand command = new SqlCommand("SELECT '" + description + "' AS '" + description + "', CPPS_Site,Study_Id,CustNo,CPPS_Job FROM CDS.dbo.Studies " +
"WHERE Study_Id = " + studyID, con);
List<string> overview = new List<string>();
overview.Add("|=========================================================|");
overview.Add("|"+description + "\t|CPPS_Site\t|Study_ID\t|CustNo\t|CPPS_Job|");
overview.Add("|---------------------------------------------------------|");
using (SqlDataReader resultQuery = command.ExecuteReader())
{
var schemaTable = resultQuery.GetSchemaTable();
while (resultQuery.Read())
{
string build = "|";
build += resultQuery.GetSqlValue(0) + "\t|"
+ resultQuery.GetSqlValue(1) + "\t\t|"
+ resultQuery.GetSqlValue(2) + "\t\t|"
+ resultQuery.GetSqlValue(3) + "\t|"
+ resultQuery.GetSqlValue(4);
build += "|";
overview.Add(build);
}
overview.Add("|=========================================================|");
return overview;
}
Result:
while this is technically working and would also be accepted, I am personally very unpleased with this ugly solution. For instance with strings of different length, the format will not fit anymore. Do you know a more clean solution?
Composite string formatting provides an aligment component that can be used to specify a field size and align values left or right. For example
String.Format("|{0,5}",5);
will produce
| 5|
Each line can be written as :
var linePattern="|{0,-7}|{1,-17}|{2,-11}|{3,-14}|{4,-8}|";
var line= String.Format(linePattern
resultQuery.GetSqlValue(0),
resultQuery.GetSqlValue(1),
resultQuery.GetSqlValue(2),
resultQuery.GetSqlValue(3),
resultQuery.GetSqlValue(4));
The header can be written using the same pattern:
var header=String.Format(linePattern,"Before","CPPS_Site","Study_ID","CustNo","CPPS_Job");
Writing both the header and line to the console will appear like this :
|Before |CPPS_Site |Study_ID |CustNo |CPPS_Job|
|Before |1 |2 |C50030 |999 |
If the strings are larger than the field values though, they won't be truncated and the format will appear broken, eg:
|Before |CPPS_Site |Study_ID |CustNo |CPPS_Job|
|Before123 |1 |2 |C50030 |999 |
Related
I'm trying to build a query, to list all the known computers in SCCM with a specific name.
The query looks like this:
string query = string.Format("Select Name From SMS_R_System Where Name like '" + "%" + computerName + "%" + "'");
If results are found, it puts the result(s) in a dropdown box.
My problem in these case, the output looks like this:
"instance of SMS_R_System{Name = "DC01";};"
But of course, for our use case we only need DC01 as output.
Any tips?
The full Code for the ButtonEvent:
private void ChkBtn_Click(object sender, EventArgs e)
{
string computerName = PCDropDown.Text;
lBox.Items.Clear();
SmsNamedValuesDictionary namedValues = new SmsNamedValuesDictionary();
WqlConnectionManager connection = new WqlConnectionManager(namedValues);
// Connect to remote computer.
try
{
connection.Connect(PrimarySiteServer.ToString());
// Set the query.
string query1 = string.Format("Select Name From SMS_R_System Where Name like '" + "%" + computerName + "%" + "'");
string query2 = string.Format("Select * From SMS_UserMachineRelationship WHERE ResourceName like '" + "%" + computerName + "%" + "' AND IsActive = '1' AND Types = '1'");
// Get the query results
IResultObject queryResults = connection.QueryProcessor.ExecuteQuery(query1);
// Check for results and display in infobox
bool resultsFound = false;
foreach (IResultObject queryResult in queryResults)
{
resultsFound = true;
lBox.Items.Add("Rechner ist vorhanden");
PCDropDown.Items.Add(queryResult.ToString());
}
if (resultsFound == false)
{
lBox.Items.Add("Rechnername nicht gefunden");
}
}
catch
{
MessageBox.Show("No Connection to Config-Manager - Als ZZA ausgeführt? SCCM-Servername richtig?");
}
}
Instead of adding queryResult.ToString() like you do here:
PCDropDown.Items.Add(queryResult.ToString());
you need to add the correct field of queryResult, so in this case:
PCDropDown.Items.Add(queryResult["Name"].StringValue);
Also a quick note. I don't know for who you are writing this and what the next step would be but if this is a read only application that is only used by SCCM Admins I would consider ignoring WMI and going to the SCCM DB via SQL instead. It is a lot faster, SQL has far more powerful options for queries and it does not need the integration of those strange sccm console Dlls (although that is not 100% necessary for WMI either).
If you need write access to create devices or collections etc., or you need to work with the roles the sccm access rights systems implements however WMI is the better or only choice. (And in this case I'd rather really use those strange dlls because all of the MS examples rely on them and it can be hard to translate those tutorials to the vanilla WMI solution C# offers.
I have following query that works.
string sqlCommandText = "SELECT * FROM Admin_T where AdminID =
'" + textBox.Text + "'";
It is a fix command and I cannot use it with user given Table names and Column names at run time.
What I am actually trying to make is command like
string sqlCommandText = "SELECT * FROM Admin_T where
'" + UserGivenColumnName + "' = '" + conditionTB.Text + "'";
"UserGivenColumnName" can be any column that is part of that specific table.
Trying to create flexibility so that same command can be used under different circumstances.
SqlCommand and none of related classes used by ADO.NET does not support such a functionality as far as I know.
Of course your should never build your sql queries with string concatenation. You should always use parameterized queries. This kind of string concatenations are open for SQL Injection attacks.
But prepared statements only for values, not column names or table names. If you really wanna put your input string to your column name, create a whitelist and use it as a validation before you put it in your query.
http://codeblog.jonskeet.uk/2014/08/08/the-bobbytables-culture/
I think an Object-Relational Mapper (ORM) is perhaps the droid you are looking for. Entity Framework might be a good place to start.
Please also do take the time to understand what SQL injection is, as the other users have also prompted you to.
It is not returning anything as it is just comparing two strings
With the 'UserGivenColumnName' it is a string comparison
And those two strings are not equal
You can do it (column) by just not including the '
But it is still a bad idea
SQLinjection is a very real and very bad thing
string sqlCommandText =
"SELECT * FROM Admin_T where " + UserGivenColumnName + " = '" + conditionTB.Text + "'";
or
string sqlCommandText =
"SELECT * FROM Admin_T where [" + UserGivenColumnName + "] = '" + conditionTB.Text + "'";
I found some threads here in the forum related to this problem but they didn't help me. I just want to update my database with a date value. These come from a Textfile (written there as 2014-10-02 for example). Now I tried this (which was mentioned in the other threads):
String connectionQuery = form1.conString.Text;
SqlConnection connection = new SqlConnection(connectionQuery);
SqlCommand sqlComInsert = new SqlCommand(#"INSERT INTO [" + form1.tableName.Text + "] ([" + form1.CusId.Text + "],["+ form1.date.Text +"],[" + form1.cusName.Text + "]) VALUES('" + cusId[i] + "',convert(date,'" + date[i] + "',104),'" + "','" + cusName[i] + "')", connection);
sqlComInsert.Connection.Open();
sqlComInsert.ExecuteNonQuery();
sqlComInsert.Connection.Close();
Now when I leave the "'" out ("',convert / "',104)) he tells me that the syntax is incorrect near 2013 (the beginning of my date). When I write it like above then I get:
String or binary data would be truncated.
What is this? I tried also to convert the date with:
for (int i = 0; i < typeDelDate.Count; i++)
{
unFormatedDate = date[i];
formatedDate = unFormatedDate.ToString("dd/MM/yyyy");
dateFormat.Add(formatedDate);
}
but I get still the same errors. How can I update my values? the column type is "date".
Use parametrized queries instead of slapping strings together:
var commandText = "insert (column) values (#dt);";
var cmd = new SqlCommand(commandText, connection);
cmd.Parameters.AddWithValue("dt", DateTime.ParseExact(dateString, "yyyy-MM-dd"));
cmd.ExecuteNonQuery();
Do not pass values into queries by adding strings - if possible, you should always use parameters. It saves you a lot of trouble converting to proper values (different for different locales etc.), it's more secure, and it helps performance.
I can insert my XML easily into my database table, but i follow this exhausting manner as seen in my down code using LINK, which is perfectly tested. But, I wonder if I can find a way to read all my XML descendants elements of "Level" node, using iteration of all child tagnames, because when I make any change to my XML file, I would have to change my LINK code once again,and usually i'll face some errors when i use this exhausting manner. Please help improve this code:
try
{
XElement d = XElement.Parse(richTextBox1.Text.ToString());
var people = (from Level in d.Descendants("Level")
select new
{
ID = Convert.ToInt32(Level.Element("ID").Value),
Day1 = Level.Element("Day1").Value,
Day2 = Level.Element("Day2").Value,
Day3 = Level.Element("Day3").Value,
Day4 = Level.Element("Day4").Value,
Day5 = Level.Element("Day5").Value,
Day6 = Level.Element("Day6").Value,
Day7 = Level.Element("Day7").Value
}).ToList();
foreach (var item in people)
{
//Insert and Update
datacommand1.CommandText = "Insert Into MyTable(ID,Day1,Day2,Day3,Day4,Day5,Day6,Day7) values(" + item.ID + "," + "','" + item.Day1 + "','" + item.Day2 + "','" + item.Day3 + "','" + item.Day4 + "','" + item.Day5 + "','" + item.Day6 + "','" + item.Day7 + "')";
datacommand1.ExecuteNonQuery();
}
}
my XML file seems like that:
<level>
<id> 101 </id>
<Day1> task 1</Day1>
<Day2> task 2</Day2>
<Day3> task 3</Day3>
<Day4> task 4</Day4>
<Day5> task 5</Day5>
<Day6> task 6</Day6>
<Day7> task7 </Day7>
</level>
Instead of declaring one variable for each tag in the file, you may want to try to iterate over all them, extracting the name and the value for each one and composing the SQL statement at runtime from those, no matter what they are. Try something like this:
IEnumerable<XElement> items = d.Descendants("level").Elements();
string names = string.Empty;
string values = string.Empty;
foreach (XElement item in items)
{
names += item.Name + ",";
values += "#" + item.Name + ",";
IDbDataParameter parameter = datacommand1.CreateParameter();
parameter.ParameterName = "#" + item.Name;
parameter.DbType = DbType.String;
parameter.Value = item.Value;
datacommand1.Parameters.Add(parameter);
}
datacommand1.CommandText = "INSERT INTO MyTable (" + names.Substring(names.Length - 1) + ") VALUES (" + values.Substring(values.Length - 1) + ");";
datacommand1.ExecuteNonQuery();
This builds the command on the fly, based on the XML structure, and fills its parameters with the data there. But doing so relies on the fact that the table structure will be exactly the same as in the file, and still needs manual schema updating when the structure changes, but as long as they're in sync it should be fine.
EDIT
About datatypes, there are 2 choices I can think of. Leave as it is, sending everything as strings no matter what, and rely on the DB engine to parse, validate and turn those into numbers (depending on what DB you're using, that may be possible or not, but I guess it's not rare to see). Or modify the code to separate the special fields apart from the loop (and excluding from it) and add those one by one, specifying their types accordingly. This is easy to do if the numeric columns are fixed, like the ID, and everything else is text.
I use the following code to insert a record from one database to another but it doesn't work. I tried the query in MS-ACCESS 2007 and it works fine but it doesn't work when called programmatically from my C# code?
string query_insert = "INSERT INTO Questionnaires_Table(BranchName,Factor,Region,Branch_ID,Current_Date,No_Employees) "
+ "SELECT BranchName,Factor,Region,Branch_ID,Current_Date,No_Employees "
+ "FROM Questionnaires_Table IN '" + dialog.FileName + "' Where Branch_ID = " + textBox1.Text ;
dbConnDest.Open();
OleDbDataAdapter dAdapter = new OleDbDataAdapter();
OleDbCommand cmd_insert = new OleDbCommand(query_insert, dbConnDest);
dAdapter.InsertCommand = cmd_insert;
textBox2.Text = query_insert.ToString();
dbConnDest.Close();
When I take the the content of query_insert in ms access, it works fine.
I think you need to use
cmd_insert.executeNonQuery()
Remove the comma after the last field name in the SELECT list.
"SELECT BranchName,Factor,Region,Branch_ID,Current_Date,No_Employees"
dAdapter.Update();
should do the trick
This seems suspect:
" Where Branch_ID = " + textBox1.Text ;
Does textBox1 contain a numeric ID? Does the ID that is entered exist in the source database?
I would 1) do a check that the ID exists and warn the user if it doesn't, and 2) change the query to use paramters instead of concatenating SQL.
What would happen if your company opened a branch with the ID of
"1; DROP TABLE Branches"