I have a SQL database that stores some data that I would like to chart. The problem is, I inherited this database and they store the datetime values as Ticks. When I set my chart datasource to this table, it doesn't seem to understand ticks.
How do I get my chart to convert the ticks back to a DateTime format that my chart understands?
Database Table
My SQL query and code:
static public DataTable get_I1(RunningTests rt)
{
DataTable dt = new DataTable();
using (SqlConnection cs = new SqlConnection(connString))
{
string query = string.Format("SELECT Time_Stamp, I1 FROM Test WHERE Unit_ID = '{0}' AND Time_Stamp >= '{1}' AND Time_Stamp <= '{2}'", rt.Unit_ID, rt.StartTime.Ticks, rt.StopTime.Ticks);
Console.WriteLine(query);
SqlCommand cmd = new SqlCommand(query, cs);
using (SqlDataAdapter da = new SqlDataAdapter(cmd))
{
da.Fill(dt);
}
}
dt.DefaultView.Sort = "Time_Stamp DESC";
dt = dt.DefaultView.ToTable();
return dt;
}
My code to set my chart datasource:
private void do_chart_I1(RunningTests rt)
{
muCalGUI1.chartI1.Series.Clear();
DataTable dt = SQL.get_I1(rt);
muCalGUI1.chartI1.DataSource = dt;
Series s = new Series("I1");
s.XValueMember = "Time_Stamp";
s.YValueMembers = "I1";
s.ChartType = SeriesChartType.Line;
s.BorderWidth = 2;
s.MarkerSize = 5;
s.MarkerStyle = MarkerStyle.Circle;
muCalGUI1.chartI1.ChartAreas[0].AxisY.IsStartedFromZero = false;
muCalGUI1.chartI1.ChartAreas[0].AxisX.LabelStyle.Format = "yyyy-MM-dd\nHH:mm:ss";
muCalGUI1.chartI1.ChartAreas[0].AxisY.LabelStyle.Format = "0";
muCalGUI1.chartI1.ChartAreas[0].RecalculateAxesScale();
muCalGUI1.chartI1.Series.Add(s);
muCalGUI1.chartI1.Legends.Clear();
}
Results:
Desired Results:
I have a solution that works. If someone can provide a 'more clean' approach, I'll be happy to mark that as the answer. For now my work around was to create a new datatable and convert the ticks to a datetime.
SQL Code:
static public DataTable get_I1(RunningTests rt)
{
DataTable dt = new DataTable();
using (SqlConnection cs = new SqlConnection(connString))
{
//string query = string.Format("Select TOP {0} Serial AS [Serial #], Start, [Stop], N, ROUND(Mean,4) AS Mean, ROUND(StdDev,4) AS [Standard Deviation], ROUND(Minimum,4) AS Min, ROUND(Maximum,4) AS Max FROM TestTime JOIN Membrane ON TestTime.Membrane_ID = Membrane.Membrane_ID WHERE Serial LIKE '{1}' ORDER BY TestTime_ID", numRecords, serial);
string query = string.Format("SELECT Time_Stamp, I1 FROM Test WHERE Unit_ID = '{0}' AND Time_Stamp >= '{1}' AND Time_Stamp <= '{2}'", rt.Unit_ID, rt.StartTime.Ticks, rt.StopTime.Ticks);
SqlCommand cmd = new SqlCommand(query, cs);
using (SqlDataAdapter da = new SqlDataAdapter(cmd))
{
da.Fill(dt);
}
}
//Previous user stored the date time as ticks, have to convert back to DateTime
DataTable dtCloned = new DataTable();
dtCloned.Clear();
dtCloned.Columns.Add("Time_Stamp", typeof(DateTime));
dtCloned.Columns.Add("I1", typeof(int));
foreach (DataRow dr in dt.Rows)
{
DataRow r = dtCloned.NewRow();
r[0] = new DateTime((long)dr[0]);
r[1] = dr[1];
dtCloned.Rows.Add(r);
}
dtCloned.DefaultView.Sort = "Time_Stamp DESC";
dtCloned = dtCloned.DefaultView.ToTable();
return dtCloned;
}
Related
My chart doesn't seem to display the right values when it's a really small number (less than one). When I have big values (greater than one) it seems to chart and scale everything just fine. Any idea what I'm doing wrong?
My Charting Code:
private void do_chart_Conc(RunningTests rt, Chart c)
{
c.Series.Clear();
set_chart_alignment(c);
DataTable dt = SQL.get_Conc(rt);
c.DataSource = dt;
Series s = new Series("Conc");
s.XValueMember = "Time_Stamp";
s.YValueMembers = "Conc";
s.ChartType = SeriesChartType.Line;
s.BorderWidth = 2;
s.MarkerSize = 5;
s.MarkerStyle = MarkerStyle.Circle;
s.IsValueShownAsLabel = true;
s.Label = "#VALY{0.0000}";
c.ChartAreas[0].AxisY.IsStartedFromZero = false;
c.ChartAreas[0].AxisX.LabelStyle.Format = "yyyy-MM-dd\nHH:mm:ss";
c.ChartAreas[0].AxisY.LabelStyle.Format = "0.0000";
c.ChartAreas[0].RecalculateAxesScale();
c.Series.Add(s);
c.Legends.Clear();
}
My SQL Code:
static public DataTable get_Conc(RunningTests rt)
{
DataTable dt = new DataTable();
using (SqlConnection cs = new SqlConnection(connString))
{
string query = string.Empty;
if (rt.StopTime.Ticks > 0)
{
query = string.Format("SELECT Time_Stamp, RawConc FROM Test WHERE Unit_ID = '{0}' AND Time_Stamp > '{1}' AND Time_Stamp < '{2}'", rt.Unit_ID, rt.StartTime.Ticks, rt.StopTime.Ticks);
}
else
{
query = string.Format("SELECT Time_Stamp, RawConc FROM Test WHERE Unit_ID = '{0}' AND Time_Stamp > '{1}'", rt.Unit_ID, rt.StartTime.Ticks);
}
SqlCommand cmd = new SqlCommand(query, cs);
using (SqlDataAdapter da = new SqlDataAdapter(cmd))
{
da.Fill(dt);
}
}
//Person stored the date time to ticks, have to convert back to DateTime
DataTable dtCloned = new DataTable();
dtCloned.Clear();
dtCloned.Columns.Add("Time_Stamp", typeof(DateTime));
dtCloned.Columns.Add("Conc", typeof(int));
foreach (DataRow dr in dt.Rows)
{
DataRow r = dtCloned.NewRow();
r[0] = new DateTime((long)dr[0]);
r[1] = dr[1];
dtCloned.Rows.Add(r);
}
dtCloned.DefaultView.Sort = "Time_Stamp DESC";
dtCloned = dtCloned.DefaultView.ToTable();
return dtCloned;
}
Example Chart I'm getting:
Zoomed:
The example Data:
I would like it to chart the actual values and display them (instead of zero). IE: -0.0021
You are losing precision because you are feeding in a table with y-values as int.
Change
dtCloned.Columns.Add("Conc", typeof(int));
to
dtCloned.Columns.Add("Conc", typeof(double));
and all should be well..
Here I have selected rows data table through loop how can i fill matching records in Data Base to another data table
my code :
for (int i = 0; i <= selectedrows.Rows.Count - 1; i++)
{
string date1 = selectedrows.Rows[i]["Date"].ToString();
System.DateTime dateexcel = System.DateTime.ParseExact(date1, "MM/dd/yyyy", CultureInfo.InvariantCulture);
//check select rows exists or not in DB
SqlCommand cmd = new SqlCommand("select * from UploadTable where Date='" + dateexcel+"'", con);
da = new SqlDataAdapter(cmd);
DBdt = new DataTable();
da.Fill(DBdt); // Here i need to fill all the rows matching in DB not a one row
}
Thank you
You can use DataTable.Merge:
DataTable mainTable = new DataTable();
for (int i = 0; i <= selectedrows.Rows.Count - 1; i++)
{
string date1 = selectedrows.Rows[i]["Date"].ToString();
System.DateTime dateexcel = System.DateTime.ParseExact(date1, "MM/dd/yyyy", CultureInfo.InvariantCulture);
//check select rows exists or not in DB
SqlCommand cmd = new SqlCommand("select * from UploadTable where Date='" + dateexcel+"'", con);
da = new SqlDataAdapter(cmd);
var dBdt = new DataTable();
da.Fill(dBdt);
mainTable.Merge(dBdt);
}
I have a database that contains a Column of 3 Defined Types and a Column of that contains numbers.
The types can appear severl time in the database.
I want to create a DataTable that will show each type one time only and sum up to numbers that relate to that type.
List<String> types = typesInTable(table);
DataTable t = new DataTable();
t.Clear();
t.Columns.Add("Type");
t.Columns.Add("Total Expenses");
foreach (String type in types)
{
DataRow tmp = t.NewRow();
tmp["Type"] = type;
int total = 0;
myConnection.Open();
OleDbDataReader reader = null;
OleDbCommand cmd = new OleDbCommand("SELECT [Type] , [Expense] FROM [" + table+"]", myConnection);
reader = cmd.ExecuteReader();
while (reader.Read())
{
if(reader["Type"].ToString().Equals(type))
{
total += Convert.ToInt32(reader["Expense"].ToString());
}
}
tmp["Total Expenses"] = total;
if (!t.Rows.Contains(tmp))
{
t.Rows.Add(tmp);
}
myConnection.Close();
}
This Code makes the types appear several times.
You can use this code to create DataTable that contains every type grouped with the sum :
DataTable t = new DataTable();
myConnection.Open();
string query = string.Format("SELECT Type, Sum(Expense) AS TotalExpenses FROM [{0}] group by Type", table);
OleDbCommand cmd = new OleDbCommand(query, myConnection);
OleDbDataAdapter adapter = new OleDbDataAdapter(cmd);
adapter.Fill(t);
myConnection.Close();
if You want to sum up the types from different tables all together in 1 DataTable use this:
List<String> tableList = serviceMethod.getTableList();
DataTable dtAllType = new DataTable();
foreach (string table in tableList)
{
DataTable dtTemp = new DataTable();
myConnection.Open();
string query = string.Format("SELECT Type, Sum(Expense) AS TotalExpenses FROM [{0}] group by Type", table);
OleDbCommand cmd = new OleDbCommand(query, myConnection);
OleDbDataAdapter adapter = new OleDbDataAdapter(cmd);
adapter.Fill(dtTemp);
for (int i = 0; i < dtTemp.Rows.Count; i++)
{
bool isDupe = false;
for (int j = 0; j < dtAllType.Rows.Count; j++)
{
if (dtTemp.Rows[i][0].ToString() == dtAllType.Rows[j][0].ToString())
{
dtAllType.Rows[j][1] = int.Parse(dtAllType.Rows[j][1].ToString()) + int.Parse(dtTemp.Rows[i][1].ToString());
isDupe = true;
break;
}
}
if (!isDupe)
{
dtAllType.ImportRow(dtTemp.Rows[i]);
}
}
myConnection.Close();
}
the dtAllType DataTable contain Type grouped with sum of Expence
DataTable dt = db.getProductIdFromCategoriesId(categories_id);
foreach (DataRow row in dt.Rows)
{
string products_id = row["products_id"].ToString();
DataTable dt5 = db.FillDataGridfromTree(int.Parse(products_id));
show_products.ItemsSource = dt5.DefaultView;
}
this code show one by one rows in datagridview
but i want to show all the product rows having categories_id in datagridview in one go
this is the function FillDataGridfromTree in databasecore class and its object is db
public DataTable FillDataGridfromTree(int product_Id)
{
string CmdString = string.Empty;
using (SqlCeConnection con = new SqlCeConnection(ConString))
{
CmdString = "SELECT products.product_id as ID, products.remote_products_id as Remote_ID, products_description.products_name as name,products.products_model as model,products.manufacturers_id as manufacturersId,products.products_image as Image,products.products_price as Price,products.products_weight as Weight,products.products_date_added as dateAdded,products.products_last_modified as lastModified,products.products_date_available as dateAvailable,products.products_status as status,products.products_tax_class_id as taxClass FROM products INNER JOIN products_description ON products.product_id=products_description.products_id where products_description.language_id=1 and products_description.products_id=" + product_Id;
SqlCeCommand cmd = new SqlCeCommand(CmdString, con);
SqlCeDataAdapter adapter = new SqlCeDataAdapter(cmd);
DataTable dt = new DataTable("products");
adapter.Fill(dt);
//show_products.ItemsSource = dt.DefaultView;
return dt;
}
}
this is the function through which i get product_id
public DataTable getProductIdFromCategoriesId(int categories_id)
{
string CmdString = string.Empty;
using (SqlCeConnection con = new SqlCeConnection(ConString))
{
CmdString = "SELECT products_id FROM products_to_categories where categories_id=" + categories_id;
SqlCeCommand cmd = new SqlCeCommand(CmdString, con);
DataTable dt = new DataTable();
SqlCeDataAdapter adapter = new SqlCeDataAdapter(cmd);
adapter.Fill(dt);
return dt;
}
}
how to show all the rows instead of one row in datagridview
CHANGED Try changing your foreach loop to:
DataTable dt = db.getProductIdFromCategoriesId(categories_id);
DataTable dt5 = new Datatable();
foreach (DataRow row in dt.Rows)
{
string products_id = row["products_id"].ToString();
dt5.Merge(db.FillDataGridfromTree(int.Parse(products_id)));
}
show_products.ItemsSource = dt5.DefaultView;
You code is always going to display the last row for a category_id, this is because you're assigning an ItemsSource inside a loop. I've changed the top part to do what you looking for:
DataTable dt = db.getProductIdFromCategoriesId(categories_id);
List<DataRow> ProductList = new List<DataRow>();
foreach (DataRow row in dt.Rows)
{
string products_id = row["products_id"].ToString();
DataTable dt5 = db.FillDataGridfromTree(int.Parse(products_id));
if(dt5.Rows.Count > 0)
{
ProductList.AddRange(dt5.Select().ToList());
}
}
show_products.ItemsSource = ProductList.CopyToDataTable().DefaultView;
This value (val1) I'm passing through url (I mean this operation as jobong filter option in checkbox list, filtering by selection index then passing through another page and retrieve through database):
Default Page 3: /WebSite4/Default4.aspx?vaL1=blue,red
This retrieving form page to view in page.
Default Page 2:
public void grid()
{
con.Open();
cmd = new SqlCommand("select * from lady_cloth where color in('" + Request.QueryString["vaL1"] + "')", con);
SqlDataAdapter da1 = new SqlDataAdapter(cmd);
DataSet ds3 = new DataSet();
da1.Fill(ds3);
con.Close();
if (ds3.Tables[0].Rows.Count > 0)
{
GridView1.DataSource = ds3;
GridView1.DataBind();
}
else
{
}
}
SqlConnection con = new SqlConnection("Data Source=xxxx;Initial Catalog=e_commerce;User ID=sa;Password=xxx");
SqlCommand cmd = new SqlCommand();
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
//Label1.Text = Request.QueryString["Item"];
//Label2.Text = Request.QueryString["Color"];
//grid();
var colourTable = new DataTable();
colourTable.Columns.Add("Value", typeof(string));
var colours = Request.QueryString["vaL1"].Split(',');
for (int i = 0; i < colours.Length; i++)
{
var newRow = colourTable.NewRow();
newRow[0] = colours[i];
colourTable.Rows.Add(newRow);
}
}
string sql = "SELECT * FROM lady_cloth WHERE color IN (SELECT Value FROM #Colours)";
cmd = new SqlCommand(sql, con);
DataSet ds3 = new DataSet();
using (var adapter = new SqlDataAdapter(sql, con))
{
var parameter = new SqlParameter("#Colours", SqlDbType.Structured);
//parameter.Value = colourTable;
parameter.TypeName = "dbo.StringList";
cmd.Parameters.Add(parameter);
con.Open();
adapter.Fill(ds3);
}
if (ds3.Tables[0].Rows.Count > 0)
{
GridView1.DataSource = ds3;
GridView1.DataBind();
}
else
{
}
}
I think your problem is that you are not separating your items, so your SQL ends up looking like:
select *
from lady_cloth
where color in('blue,red')
Whereas what you would really want is
select *
from lady_cloth
where color in('blue','red')
If you are using SQL Server 2008 or later then I would recommend using table-valued parameters. The first step would be to create your type:
CREATE TYPE dbo.StringList TABLE (Value NVARCHAR(MAX));
I tend to just create generic types that can be easily reused, but this would be your call.
Then in your method you would need to split your values into an array and add them to a datatable:
var colourTable = new DataTable();
colourTable.Columns.Add("Value", typeof(string));
var colours = Request.QueryString["vaL1"].Split(',');
for (int i = 0; i < colours.Length; i++)
{
var newRow = colourTable.NewRow();
newRow[0] = colours[i];
colourTable.Rows.Add(newRow);
}
You can then add this table to your command as a parameter:
string sql = "SELECT * FROM lady_clock WHERE Color IN (SELECT Value FROM #Colours)"
cmd = new SqlCommand(sql, con);
var parameter = new SqlParameter("#Colours", SqlDbType.Structured);
parameter.Value = colourTable;
parameter.TypeName = "dbo.StringList";
cmd.Parameters.Add(parameter);
Finally, You can reduce your code by just initialising the SqlDataAdapter with your SQL and connection:
public void grid()
{
var colourTable = new DataTable();
colourTable.Columns.Add("Value", typeof(string));
var colours = Request.QueryString["vaL1"].Split(',');
for (int i = 0; i < colours.Length; i++)
{
var newRow = colourTable.NewRow();
newRow[0] = colours[i];
colourTable.Rows.Add(newRow);
}
string sql = "SELECT * FROM lady_clock WHERE Color IN (SELECT Value FROM #Colours)"
DataSet ds3 = new DataSet();
using (var adapter = new SqlDataAdapter(sql, con))
{
var parameter = new SqlParameter("#Colours", SqlDbType.Structured);
parameter.Value = colourTable;
parameter.TypeName = "dbo.StringList";
adapter.Parameters.Add(parameter);
con.Open();
da1.Fill(ds3);
}
if (ds3.Tables[0].Rows.Count > 0)
{
GridView1.DataSource = ds3;
GridView1.DataBind();
}
else
{
}
}