Reading data from SQL Server and formatting it - c#

I have a SQL Server database with a table QC and columns A, B, C, D, E,
Comment.
What I am trying to do is to read the data from the columns and display it in a label. But there is not always data in all columns.
Expected output is:
2.5|2.1
if there is data only in A and B column. But I get:
2.5|2.1| |||||
This is my code:
SqlCommand cmd = new SqlCommand("SELECT TOP 1 * FROM [TableQC] ORDER BY id DESC", conn);
SqlDataReader reader = cmd.ExecuteReader();
string temp = "";
string temp1 = "";
while (reader.Read())
{
temp += reader["A"].ToString() + "|";
temp += reader["B"].ToString() + "|";
temp += reader["C"].ToString() + "|";
temp += reader["D"].ToString() + "|";
temp += reader["E"].ToString() + "|";
temp1 += reader["Comment"].ToString();
//temp += "<br/>";
}
conn.Close();
label1.Text = temp;
label2.Text = temp1;

As Mong Zhu pointed out, check while reading the column values:
if (!string.IsNullOrEmpty(reader.GetString("A")))
This will test each column for null value and replace it with an empty string.
To avoid a dangling | delimiter at the end, work with an array of strings you the Join()
while (reader.Read())
{
// create an array big enough to hold all columns
object[] qc = new object[reader.FieldCount];
// iterate over all columns of your reader
for (int i = 0; i < reader.FieldCount; i++)
{
if (reader[i] == reader["Comment"])
{
label2.Text = reader.GetSqlString(i).IsNull ? null : reader.GetSqlString(i).Value;
}
else
{
// add to array
qc[i] = reader.GetValue(i);
}
}
label1.Text = string.Join("|", qc.OfType<string>());
}
However it seems to didn't tell the actual data type of columns A, B, etc. and assuming them to be of string/character data type turned out to be false.
Depending on your actual data types, you will have to edit the filtering Linq query to the actual type like qc.OfType<decimal>() or only filter for null values like qc.Where(v => !(v is DBNull)).

You can do this in the query. Basically you want concat_ws(), but that is not available in SQL Server. Instead:
SELECT TOP 1 STUFF( (COALESCE('|' + A, '') +
COALESCE('|' + B, '') +
COALESCE('|' + C, '') +
COALESCE('|' + D, '') +
COALESCE('|' + E, '') +
COALESCE('|' + Comment, '')
), 1, 1, ''
) as abcde
FROM [TableQC]
ORDER BY id DESC

Thanks you all for helping me and resolving my problem. This is the code that works for me:
SqlCommand cmd = new SqlCommand("SELECT TOP 1 * FROM [TableQC] ORDER BY id DESC", conn);
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
// create an array big enough to hold all columns
object[] qc = new object[reader.FieldCount];
// iterate over all columns of your reader
for (int i = 0; i < reader.FieldCount; i++)
{
if (reader[i] == reader["Comment"])
{
lblMessage1.Text = reader.GetSqlString(i).IsNull ? null : reader.GetSqlString(i).Value;
}
else
{
// add to array
qc[i] = reader.GetValue(i);
}
}
lblMessage.Text = string.Join("|", qc.OfType<double>());
}
conn.Close();
Thanks you a lot once more time.

Related

CSV - Import file to a Sql database through code

I need to load data from text file/csv file to a SQL Server database. I used the code shown below to load data and is loading to the database the problem is the data in second column may contain space but I use space for separate the column data.
i.e.
200007 XXXX Check XXXX yyy 50
200013 YYYY Check ZZZZ yyy 50
200022 nnnn 25Mg 30 Tabs
200042 mmmm 30 Mg 30 Tabs
I need to store the first ID number in the first column and the remaining text in second column:
string str = Properties.Settings.Default.con;
SqlConnection con = new SqlConnection(str);
SqlCommand cmd = new SqlCommand();
try
{
cmd.Connection = con;
con.Open();
cmd.CommandText = "IF NOT EXISTS (SELECT * FROM sysobjects WHERE name='TEMP_AUTO' AND xtype='U')" +
"CREATE TABLE TEMP_AUTO (" +
"ID varChar(10) NULL," +
"NAME varChar(50) NULL," +
"DATE TIMESTAMP NULL," +
")";
cmd.ExecuteNonQuery();
string query1 = "INSERT INTO [dbo].[TEMP_AUTO]([ID],[NAME]) VALUES (#num1, #num2)";
cmd.CommandText = query1;
string[] allLines = File.ReadAllLines(txtFilePath.Text);
for (int i = 0; i < allLines.Length; i++)
{
cmd.Parameters.Clear();
string[] items = allLines[i].Split(new char[] { ' ' });
cmd.Parameters.AddWithValue("#num1", items[0]);
cmd.Parameters.AddWithValue("#num2", items[1]);
cmd.ExecuteNonQuery();
}
MessageBox.Show("Successfully saved your data");
}
finally
{
cmd.Dispose();
con.Close();
}
A possible solution might be this:
string[] allLines = {
"200007 XXXX Check XXXX yyy 50",
"200013 YYYY Check ZZZZ yyy 50",
"200015 ",
"2541111"
};
for (int i = 0; i < allLines.Length; i++)
{
string param1 = null;
string param2 = null;
int spaceIndex = allLines[i].IndexOf(' ');
if (spaceIndex > 0)
{
param1 = allLines[i].Substring(0, spaceIndex);
if (spaceIndex < allLines[i].Length - 1)
{
param2 = allLines[i].Substring(spaceIndex + 1, allLines[i].Length-1 - spaceIndex);
}
}
else
{
param1 = allLines[i];
}
Console.WriteLine("param1:{0} param2:{1}", param1, param2);
}
Use SSIS to map this file as long as it has a standard structure to SQL Table.
Is this a one time thing? Have you tried getting the data organized in Excel then using the SSMS import tool to bring it in? If you right click on the Database then Tasks > Import Data the wizard will appear when given the option to choose the source, choose Excel. Flat files is an option but if you can format it in Excel first that tends to work better.
As you click through you can adjust the column types and where the breaks are, much like importing into Excel itself.
Use the String.Split(Char[], Int32) method to split on the first occurrence of ' ' only. Eg
string[] items = allLines[i].Split(new char[] { ' ' }, 2);
Refs: MSDN and previous relevant question
Use the below code.
using (StreamReader sr = File.OpenText("txtFile.txt")) // Mention the path,if the file is not in application folder.
{
string str = String.Empty;<br/>
while ((str = sr.ReadLine()) != null)
{
string[] item = str.Split(' ');
SqlConnection con = new SqlConnection(str);
SqlCommand cmd = new SqlCommand();
string query1 = "INSERT INTO [dbo].[TEMP_AUTO]([ID],[NAME]) VALUES ('" + item[0] + "', '" + item[1] + "')";
// Do remain part<br/>
}
}

Update Values in table with same id

I have 3 Tables
LaminationTitle**
LaminationTitleRelation
Papertypemaster
I Want to update Values of"LaminationTitleRelation" table which comes from CheckboxList... Below is my Update Form....
Lamination Title in Below form Updated in LaminationTitle Table, where as
Checkbox List Items should Update in LaminationTitleRelation Table
Note: if "Papertypeid" in LaminationTitleRelation and Items Checked are different then it should be add.
Plz help me
Use the following query:
query = "Create Table #PaperTypeMapping(LaminationTitleId int, PaperTypeId int)";
//For each value of Paper Type Id you will need to insert a row
query = "Insert Into #PaperTypeMapping(LaminationTitleId, PaperTypeId) Values(#laminationId, #paperTypeId)";
//Update existing values
query = "Update OldMapping Set OldMapping.ActiveStatus = 1 FROM LaminationTitleRelation OldMapping Inner join #PapertTypeMapping NewMapping ON OldMapping.LamTitleId = NewMapping.LaminationTitleId and OldMapping.PaperTypeId = NewMapping.PaperTypeId"
//Insert new values
query = "Insert into LaminationTitleRelation(lamTitleId, PapertTypeId, ActiveStatus) Select LaminationTitleId, PapertTYpeId, 1 From #PaperTypeMapping NewMapping where NOT EXISTS(SELECT 1 FROM LaminationTitleRelation OldMapping WHERE OldMapping.LamTitleId = NewMapping.LaminationTitleId and OldMapping.PaperTypeId = NewMapping.PaperTypeId)";
or alternatively you can use the following link a built in utility by MS SQL Merge
protected void btnUpdate_Click(object sender, EventArgs e) {
DB = new DBFunctions();
string vItems = mGetSelectedItems();
string vQuery = "Update laminationtitle Set title='" + txtLaminationTitle.Text + "',laminationtypeid='" + ddlProductType.SelectedValue + "' where laminationid='" + Request.QueryString["laminationid"] + "'";
int x = DB.SetData(vQuery);
DataTable dSelect = new DataTable();
DataTable dAll = new DataTable();
DB = new DBFunctions();
DB1 = new DBFunctions();
if (x > 0) {
int y = DB.SetData("delete from laminationtitlepapertyperelation where lamtitleid=" + Request.QueryString["laminationid"]);
if (y > 0) {
string[] values = vItems.Split(',');
for (int i = 0; i < values.Length; i++) {
vQuery = "insert into laminationtitlepapertyperelation(lamtitleid, papertypeid, activestatus)VALUES('" + Request.QueryString["laminationid"].ToString() + "','" + values[i] + "',1)";
DB.SetData(vQuery);
ScriptManager.RegisterStartupScript(this, GetType(), " Update Lamination Title", "alert('Lamination " + '"' + txtLaminationTitle.Text + '"' + " Title Updated Sucessfully');window.location='ManageLaminationTitle.aspx';", true);
}
}
}
}

Rest API SQL query times out from too many rows, how to limit reader from reading too many rows

I setup this C# query with a simple form of pagination, but some of the queries it performs may have millions of rows. I was recently testing it with various parameters, and some of the queries were timing out when there were more than 200,000 or so records. How can I go about limiting the reader to read say ~50,000 rows each time?
public DataTable GetTranReport(string aliasName, string pageString, string year, string month)
{
DataTable dataTable = new DataTable();
dataTable.Columns.Add(new DataColumn("recid"));
dataTable.Columns.Add(new DataColumn("folder"));
dataTable.Columns.Add(new DataColumn("cust"));
dataTable.Columns.Add(new DataColumn("direction"));
//pagination variables (pageString must be 1+ in order to represent current page)
int pageInt;
Int32.TryParse(pageString, out pageInt);
if (dbConnection5.State.ToString() != "Open")
{
dbConnection5.Open();
}
int itemNum = 0;
string selecteddate = string.Format("[" + year + month + "]");
string query = string.Format("SELECT recid, folder, cust, direction FROM " + selecteddate + " WHERE cust = #aliasname order by thedate DESC;");
SqlCommand command = new SqlCommand(query, dbConnection5);
command.Parameters.AddWithValue("#selecteddate", selecteddate);
command.Parameters.AddWithValue("#aliasname", aliasname);
SqlDataReader reader = command.ExecuteReader();
int i = 0;
DataRow newTRRow;
if (reader.HasRows)
{
while (reader.Read())
{
++i;
if (pageInt > 1)
{
if (i >= ((pageInt * 10) - 10) && i < (10 * pageInt))
{
itemNum += 1;
string itemString = string.Format("itemString" + itemNum);
newTRRow = dataTable.NewRow();
newTRRow["recid"] = reader["recid"];
newTRRow["folder"] = reader["folder"];
newTRRow["customer"] = reader["customer"];
newTRRow["direction"] = reader["direction"];
dataTable.Rows.Add(newTRRow);
}
}
else
{
if (itemNum < 10)
{
itemNum += 1;
string itemString = string.Format("itemString" + itemNum);
newTRRow = dataTable.NewRow();
newTRRow["recid"] = reader["recid"];
newTRRow["folder"] = reader["folder"];
newTRRow["customer"] = reader["customer"];
newTRRow["direction"] = reader["direction"];
dataTable.Rows.Add(newTRRow);
}
}
}
}
dataTable.Rows.Add(string.Format("Total number of records is: {0}", i));
reader.Close();
dbConnection5.Close();
return dataTable;
}
you need to add 2 extra parameter (the position of records you want) and use a CTE which has a row_number:
assuming you want records from rcA to rcB, you can do:
with cte as(
SELECT recid, folder, cust, direction,
row_number() over(order by recid) rn
FROM your_table
where --your conditions (it's not need to use order by here)
)
select * from cte
where rn between rcA and rcB
You can limit your no. of rows at the SQL query level itself. Just use the TOP keyword to limit it.
string query = string.Format("SELECT TOP 50000 recid, folder, cust, direction FROM " + selecteddate + " WHERE cust = #aliasname order by thedate DESC;");

Using stream reader to catch values returned by sql statemtnt c#

guys i have an SQL statement returning more than 1 value.
I am trying to use the StreamReader to get the values into an array as below
string sql = "select distinct COLUMN_NAME from INFORMATION_SCHEMA.KEY_COLUMN_USAGE where TABLE_NAME=' " + table + "' and CONSTRAINT_NAME like 'PK_%'";
SqlConnection conn2 = new SqlConnection(cnstr.connectionString(cmbDatabase.Text));
SqlCommand cmd_server2 = new SqlCommand(sql);
cmd_server2.CommandType = CommandType.Text;
cmd_server2.Connection = conn2;
conn2.Open();
//reader_sql = new StreamReader();
SqlDataReader reader_sql = null;
string[] colName = new string[200];
reader_sql = cmd_server2.ExecuteReader();
while (reader_sql.Read());
for (int rr = 0; rr < 20; rr++)
{
colName[rr] = reader_sql["COLUMN_NAME"].ToString();
}
It is not working, what am I doing wrong guys ?
You've got a stray ; turning your while into a tight loop, so instead try:
while (reader_sql.Read())
for (int rr = 0; rr < 20; rr++)
{
colName[rr] = reader_sql["COLUMN_NAME"].ToString();
}
You get the exception because
while (reader_sql.Read());
should be
while (reader_sql.Read())
{
for (int rr = 0; rr < 20; rr++)
{
colName[rr] = reader_sql["COLUMN_NAME"].ToString();
}
}
Perhaps you should remove the semicolon at the end of Read
while (reader_sql.Read())
{
for (int rr = 0; rr < 20; rr++)
colName[rr] = reader_sql["COLUMN_NAME"].ToString();
}
However, if your intention is to retrieve the columns belonging to the primary key, your code is wrong because you add 20 times the same primary key column, then repeat the same for the remaining columns ending with an array of 20 strings all equals to the last column in the primary key set. I think you should change your code to use a List(Of String) instead of a fixed length array and let the reader loop correctly on the primary key columns retrieved
List<string> pks = new List<string>();
while (reader_sql.Read())
{
pks.Add(reader_sql["COLUMN_NAME"].ToString());
}
EDIT: I have just noticed that your query contains a space before the table name. The string concatenation then produces an invalid table name, the query is syntactically right but doesn't return any data
string sql = "select distinct COLUMN_NAME from INFORMATION_SCHEMA.KEY_COLUMN_USAGE " +
"where TABLE_NAME='" + table + "' and CONSTRAINT_NAME like 'PK_%'";
^ space removed here
And while you are at it, remove the string concatenation and use a parameterized query.....
string sql = "select distinct COLUMN_NAME from INFORMATION_SCHEMA.KEY_COLUMN_USAGE " +
"where TABLE_NAME=#tName and CONSTRAINT_NAME like 'PK_%'";
SqlCommand cmd_server2 = new SqlCommand(sql, connection);
connection.Open();
cmd_server2.Parameters.AddWithValue("#tName", table);

Variable in SqlCommand must be unique within a query batch.. but it is?

I am making a windows service to gather a bunch of information and I'm sending it to the DB. I know methodology below works because I have used it on other tables with no errors. But I had to expand my DELETE command to use to have two conditions, and now I'm receiving an error.
This is the error I am receiving: "The variable name '#deletedrive' has already been declared. Variable names must be unique within a query batch or stored procedure."
Here is my code (The ending left out because it simply is catches the exception we're getting. Also ignore commented lines):
private static void ServerSpaceTimerAction(object source, ElapsedEventArgs e, string InstallLocation)
{
//StreamWriter RecordServerSpace = new StreamWriter(InstallLocation + "\\Temp\\ServerSpaceTemp.csv");
try
{
ServerSpace GetSpace = new ServerSpace();
GetConfigurations Configs = new GetConfigurations();
Configs.GetServers();
Configs.GetDatabase();
var connection = new SqlConnection("Data Source=" + Configs.DataSource + "; Initial Catalog=" + Configs.DatabaseCatalog + "; Integrated Security=" + Configs.IntegratedSecurityProtocol);
connection.Open();
char[] delim = { ' ', ',' };
string sInsertServerSpace = "INSERT INTO ServerSpace (date_time, server, region, farm, technology, role, drive, total_space, free_space) VALUES (#dt, #ser, #reg, #farm, #tech, #role, #drive, #ts, #fs)";
string sDeleteServerSpace = "DELETE FROM ServerSpace WHERE server=#serd AND drive=#deletedrive";
foreach (string server in Configs.servers)
{
string temp;
SqlCommand cmdInsertServerSpace = new SqlCommand(sInsertServerSpace, connection);
SqlCommand cmdDeleteServerSapce = new SqlCommand(sDeleteServerSpace, connection);
Configs.GetServerAttributes(server);
if (Configs.technology != "SQL")
{
GetSpace.DriveSpaceByServer(server);
}
else
{
GetSpace.DriveSpaceByServerMount(server);
}
string[] driveStats = GetSpace.ServerSpaceStats.Split(delim);
temp = DateTime.Now.ToString();
cmdInsertServerSpace.Parameters.AddWithValue("#dt", temp);
temp = server.ToString();
cmdDeleteServerSapce.Parameters.AddWithValue("#serd", temp);
cmdInsertServerSpace.Parameters.AddWithValue("#ser", temp);
temp = Configs.regiongroup.ToString();
cmdInsertServerSpace.Parameters.AddWithValue("#reg", temp);
temp = Configs.farmgroup.ToString();
cmdInsertServerSpace.Parameters.AddWithValue("#farm", temp);
temp = Configs.technology.ToString();
cmdInsertServerSpace.Parameters.AddWithValue("#tech", temp);
temp = Configs.rolegroup.ToString();
cmdInsertServerSpace.Parameters.AddWithValue("#role", temp);
for (int i = 0; i < driveStats.Length; i++)
{
temp = driveStats[i].ToString();
cmdInsertServerSpace.Parameters.AddWithValue("#drive", temp);
cmdDeleteServerSapce.Parameters.AddWithValue("#deletedrive", temp);
i++;
temp = driveStats[i].ToString();
cmdInsertServerSpace.Parameters.AddWithValue("#ts", temp);
i++;
temp = driveStats[i].ToString();
cmdInsertServerSpace.Parameters.AddWithValue("#fs", temp);
cmdDeleteServerSapce.ExecuteNonQuery();
cmdInsertServerSpace.ExecuteNonQuery();
}
//RecordServerSpace.WriteLine(DateTime.Now + "," + server + "," + Configs.regiongroup + "," + Configs.farmgroup + "," + Configs.technology + "," + Configs.rolegroup + "," + GetSpace.ServerSpaceStats);
}
connection.Close();
Let me know if you may need anything else to reference.
You only need to add the parameters once. You are adding parameters each time through the loop. Change it so that you add the parameters once, but set their values each time toruhg the loop.
SqlCommand cmdDeleteServerSapce = new SqlCommand(sDeleteServerSpace, connection);
....
cmdInsertServerSpace.Parameters.AddWithValue("#drive", temp);
cmdDeleteServerSapce.Parameters.AddWithValue("#deletedrive", temp));
for (int i = 0; i < driveStats.Length; i++)
{
temp = driveStats[i].ToString();
cmdInsertServerSpace.Parameters["#drive"].value = temp;
cmdDeleteServerSapce.Parameters["#deletedrive"].value = temp;
.....
cmdDeleteServerSapce.ExecuteNonQuery();
cmdInsertServerSpace.ExecuteNonQuery();
}
It looks like you're using the command in the loop. You only need to put the parameter in once (AddWithValue). You can alter it in the subsequent attempts but don't add it again.
You should do:
cmdDeleteServerSapce.Parameters.Add("#deletedrive", SqlDbType.VarChar);
Outside the loop.
and
cmdDeleteServerSapce.Parameters["#deletedrive"].Value = temp;
Inside the loop.
I believe you are missing a call to cmdInsertServerSpace.ExecuteNonQuery() and cmdDeleteServerSapce.ExecuteNonQuery() within your loop. I would recommend the following:
cmdInsertServerSpace.Parameters.Add("#drive", SqlDbType.VarChar);
cmdDeleteServerSapce.Parameters.Add("#deletedrive", SqlDbType.VarChar);
for (int i = 0; i < driveStats.Length; i++) {
string temp = driveStats[i].ToString();
cmdInsertServerSpace.Parameters["#drive"].Value = temp;
cmdDeleteServerSapce.Parameters["#deletedrive"].Value = temp;
i++;
.....
cmdInsertServerSpace.ExecuteNonQuery();
cmdDeleteServerSapce.ExecuteNonQuery();
}
You must use parameter clear
**cmdInsertServerSpace.Parameters.Clear();**
cmdInsertServerSpace.Parameters.AddWithValue("#dt", temp);
temp = server.ToString();
cmdDeleteServerSapce.Parameters.AddWithValue("#serd", temp);
cmdInsertServerSpace.Parameters.AddWithValue("#ser", temp);

Categories