So i created this array to return all monday dates from a specific date range as a list:
var from = DateTime.Today.AddDays(-49);
var to = DateTime.Today;
var allMondays = from.GetWeekdayInRange(to, DayOfWeek.Monday);
string output = string.Join(Environment.NewLine, allMondays.Select(d => d.ToString("dd/MM/yyyy")).ToArray());
My goal is to use it's values to find matching rows in my SQLite table.
I've only tried the most straightforward solutions by now, such as just referencing it directly:
cmd.CommandText = "select count(name2) from daily where date LIKE " + "'" + output + "'";
or using a string reader:
using (System.IO.StringReader reader = new System.IO.StringReader(output)) {
string line = reader.ReadLine();
}
but i obviously didn't get the results i wanted, any suggestions?
Related
I would like to make my not null DateTime column null when I do the sum of the entire table so that I do not get any value for date time 1/1/0001 12:00:00. I would like to add whatever possible statement into this method. I tried to do parse it but it doesn't work, but for Amount it's perfectly fine.
private void SumOfRecords_Button(object sender, RoutedEventArgs e)
{
ObservableCollection<Receipt> receipts = new ReceiptDAO().GetAllReceiptsFromPiName();
Receipt receipt = new Receipt();
if (receipt.DateTime != null)
{
Receipt receipt0 = new Receipt()
{
DateTime = DateTime.TryParse(),
Amount = new ReceiptDAO().SumOfRecords("Amount")
};
receipts.Add(receipt);
this.Dispatcher.Invoke(() => ReceiptList.ItemsSource = receipts);
}
}
This is the method for SumOfRecords where I am writing my query.
public double SumOfRecords(string columnName)
{
ObservableCollection<Receipt> receipts = new ReceiptDAO().GetAllReceiptsFromPiName();
Receipt receipt = new Receipt();
string commandstring;
commandstring = "select Sum(" + columnName + ") from " + getTable();
using (SQLiteConnection connection = ConnectToDatabase())
{
using (SQLiteCommand command = new SQLiteCommand(commandstring, connection))
{
using (SQLiteDataReader reader = command.ExecuteReader())
{
reader.Read();
return reader.GetDouble(0);
}
}
}
}
Just ignore dates when you calculate the sum. Assuming you're using sql server for database.
var where = " WHERE Table.Date <> '0001/01/01 00:00:00'";
commandstring = "select Sum(" + columnName + ") from " + getTable() + where;
You can pass where as a parameter to the method to make it reusable. Based on what database you're using, you may want look into date comparison. Otherwise the concept remains the same.
I am having a problem with my C# code, I put the query in C# code it returns the error as below:
Additional information: 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 ':= (0 + 1) as numA, ID, UID, File, StartDate, EndDate FROM OEE_PROD.thermalValue' at line 1.
I run the query in MySql database it work and can get the data.
This is my code:
public void exportCSVBtn_Click(object sender, EventArgs e)
{
string conn = ConfigurationManager.ConnectionStrings["constr"].ConnectionString;
using (MySqlConnection con = new MySqlConnection(conn))
{
string a = (string)Session["Userid"];
using (MySqlCommand cmd = new MySqlCommand("select A.*, timediff(B.StartDate, A.EndDate) from (select #rownumA:= (#rownumA + 1) as numA, ID, UID, File, StartDate, EndDate FROM OEE_PROD.thermalValue where File = '" + ddrKdf.SelectedItem.Text + "'AND UserID='" + a + "' order by ID) A LEFT JOIN(select #rownumB:= (#rownumB + 1) as numB, ID as BID, StartDate, EndDate FROM OEE_PROD.thermalValue where File = '" + ddrKdf.SelectedItem.Text + "'AND UserID='" + a + "'order by ID) B ON B.numB = (A.numA + 1)"))
{
using (MySqlDataAdapter sda = new MySqlDataAdapter())
{
cmd.Connection = con;
sda.SelectCommand = cmd;
cmd.Parameters.AddWithValue("#rownumB", 0);
cmd.Parameters.AddWithValue("#rownumA", 0);
using (DataTable dt = new DataTable())
{
sda.Fill(dt);
//Build the CSV file data as a Comma separated string.
string csv = string.Empty;
foreach (DataColumn column in dt.Columns)
{
//Add the Header row for CSV file.
csv += column.ColumnName + ',';
}
//Add new line.
csv += "\r\n";
foreach (DataRow row in dt.Rows)
{
foreach (DataColumn column in dt.Columns)
{
//Add the Data rows.
csv += row[column.ColumnName].ToString().Replace(",", ";") + ',';
}
//Add new line.
csv += "\r\n";
}
//Download the CSV file.
Response.Clear();
Response.Buffer = true;
Response.AddHeader("content-disposition", "attachment;filename=KDFExport_" + DateTime.Now + ".csv");
Response.Charset = "";
Response.ContentType = "application/text";
Response.Output.Write(csv);
Response.Flush();
Response.End();
}
}
}
}
}
The error message is caused by you treating #rownumA and #rownumB mysql user defined variables as a C# query parameter and provide 0 as its value with the following lines:
cmd.Parameters.AddWithValue("#rownumB", 0);
cmd.Parameters.AddWithValue("#rownumA", 0);
This means that #rownumA:= (#rownumA + 1) mysql expression becomes 0:= (0 + 1), which is obviously not correct.
If you want to use sql user defined variables, then add the following parameter to the connection string of your .Net connector connection:
Allow User Variables=True
or
AllowUserVariables=True
This option was added to connector v5.2.2
This way you can remove the parameter assignment lines from your C# code and the mysql variables do not get substituted.
However, the file and userid field values in the where clause indeed should be supplied via parameters and not through string concatenation!
Let's structure this an alternative way: run the two queries separately, download their data in order, then write the CSV using both results. This in contrast to getting mysql to join the data on a fake number created by row order.
using (MySqlDataAdapter daA = new MySqlDataAdapter ("
SELECT ID, UID, File, StartDate, EndDate
FROM OEE_PROD.thermalValue
WHERE File = #file
ORDER BY ID", connstr
))
using (MySqlDataAdapter daB = new MySqlDataAdapter ("
SELECT StartDate
FROM OEE_PROD.thermalValue
WHERE File = #file AND UserID = #userID
ORDER BY ID", connstr
))
{
DataTable dtA = new DataTable();
DataTable dtB = new DataTable();
daA.SelectCommand.Parameters.AddWithValue("#file", ddrKdf.SelectedItem.Text);
daB.SelectCommand.Parameters.AddWithValue("#file", ddrKdf.SelectedItem.Text);
daB.SelectCommand.Parameters.AddWithValue("#userID", a);
daA.Fill(dtA);
daB.Fill(dtB);
for(int i = 0; i < dtA.Rows.Count; i++)
{
string csvTimeDiffCol = "";
if(i+1 < dtB.Rows.Count){
DateTime st = (DateTime)dtA.Rows[i]["StartDate"];
DateTime ed = (DateTime)dtB.Rows[i+1]["EndDate"];
//now you can choose how do you want to represent this timespan?
csvTimeDiffCol = (ed - st).ToString();
}
//now write the row to CSV, including the csvTimeDiffCol string
}
}
Notes:
I've effectively rewritten your code here from what I could guess at your algorithm from what I saw in your code: "get db to prepare a superset and a subset of records, ordered by their ID, join them together on row position with an off-by-one offset" - I personally think this is wonky but I can't fault the logic because it's not mine
We download the two result sets then step over them in order, taking relevant rows
I've no idea what your timediff or dates looks like; I've assumed that they're Dates and you're looking for the difference in hours minutes etc between them, hence I cast them to DateTime in the c# and then used x-y to turn them into a TimeSpan; you'll probably need to format this
I haven't written your csv code in, because that part is unchanged. There are libraries to help with that though; you don't need to roll your own
This algorithm may not be perfect/may need debugging. I don't present it as a "paste this and I did your work for you" - I'm presenting it as something to get you to think about the problem another way
The problem:
I'm trying to insert a date time into an access database using the Oledb interface in C#.
Hacking solution: Generate my on insert string without using command.Properties
I can insert text into the database with no problem, but when trying datetime, I end up with this error: System.Data.OleDb.OleDbException {"Data type mismatch in criteria expression."}
There are several posts similar to this but alas with no working solution.
Here is my code:
void TransferData()
{
string instCmd = Get_InsertCommand(0); // hard coded table 0 for testing
Fill_ProductTable_ToInsert();
con.Open();
// It would be nice not to have to separate the date indexes
int[] textIndex = { 0, 1, 2, 3, 4, 7 };
int[] dateIndex = { 5, 6 };
try
{
foreach (DataRow row in DataToStore.Tables[0].Rows)
{
OleDbCommand command = new OleDbCommand();
command.Connection = con;
command.CommandText = instCmd;
foreach(int j in textIndex)
command.Parameters.AddWithValue("#" + j, row[j]);
foreach (int j in dateIndex)
{
// TESTING CODE
///////////////////////////////////////////////////////////////////////////
string input = "#\'" +DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss") +"\'#";
command.Parameters.AddWithValue("#" + j, input.ToString());
Program.WriteLine(input.ToString());
///////////////////////////////////////////////////////////////////////////
}
command.ExecuteNonQuery();
}
}
finally
{
con.Close();
}
}
string Get_InsertCommand(int i)
{
string sqlIns = "INSERT INTO " + DataToStore.Tables[0].TableName + " (";
string temp = "VALUES (";
for (int j = 0; j < expected_header[i].Length - 1; j++)
{
sqlIns += expected_header[i][j] + ", ";
temp += "#" + j + ", ";
}
int lastIndex = expected_header[i].Length -1;
sqlIns += expected_header[i][lastIndex] + ") ";
temp += "#" + lastIndex + ")";
sqlIns += temp;
return sqlIns;
}
Inside the area labeled testing code, I have tried every permutation of date time I could think of.
I tried every format with # and '
I tried these formats: yyyy-MM-dd, yyyyMMdd, yyyy\MM\dd, yyyy/MM/dd
I also tried ToOADate()
And ToString(), ToShortDateString()
I also tried setting the database to accept ANSI-92 Sql
I'm running out of ideas.
Note: This code is set up to deal with multiple tables from multiple databases, mind the loops...
Use parameters properly, and don't worry about the format of the datetime value that you concatenate in your query.
I don't understand why you want to convert the datetime value to a string value ?
DateTime theDate = new DateTime(2012,10,16);
var cmd = new OleDbCommand();
cmd.CommandText = "INSERT INTO sometable (column) VALUES (#p_bar)";
cmd.Parameters.Add ("#p_bar", OleDbType.DateTime).Value = theDate;
I was able to solve this issue by not using command properties. I generated my own sql input and set it to cmd.commandText. The text input for datetime to a data base is #yyyy-MM-dd#
I use the following code for saving.Updating records to Oracle,
OracleConnection con = new OracleConnection(constr);
con.Open();
// Create the command.
OracleCommand cmd = new OracleCommand("", con);
cmd.CommandText = "<?xml version=\"1.0\"?>\n" +
"<ROWSET>\n" +
" <MYROW>\n" +
" <FIELD1>2</FIELD1>\n" +
" <FIELD2>zafar</FIELD2>\n" +
" </MYROW>\n" +
"</ROWSET>\n";
// Set the XML save properties.
KeyColumnsList = new string[1];
KeyColumnsList[0] = "FIELD1";
UpdateColumnsList = new string[1];
UpdateColumnsList[0] = "FIELD2";
cmd.XmlSaveProperties.KeyColumnsList = KeyColumnsList;
cmd.XmlSaveProperties.UpdateColumnsList = UpdateColumnsList;
cmd.XmlSaveProperties.RowTag = "MYROW";
cmd.XmlSaveProperties.Table = "testconn";
cmd.XmlSaveProperties.Xslt = null;
cmd.XmlSaveProperties.XsltParams = null;
rows = cmd.ExecuteNonQuery();
Console.WriteLine("rows: " + rows);
In the Field2 column I want to use select user from dual. I am not able to save current DB user.
The structure of data in the CommandText assumes that all values are literals. There is no way to have it recognize an inner query or expression. If you want to query the user you will have to do it separately and incorporate that into the data. This may be possible with the Xslt and XsltParams clauses.
I've been at this for few hours now and can't seem to find a solution. I have 2 inventory lists, one a spreadsheet and the other a data table. I need to match the spreadsheet against the data table to find out if I have missing inventory. The spreadsheet should match with what I have in the db, ie the spreadsheet is like a master so when I have missing inventory in DB I need to add it an list and build a report.
I thought by looping throught the spreadsheet and for each inventory in the spreadsheet loop through the data table I can achieve my goal but that proved to be wrong. Any ideas how I would do this?
Thanks,
Eric
Here is the method:
public void Reconcile()
{
ObjectDataSource ods = new ObjectDataSource();
ods.ID = "ods";
ods.TypeName = "";
ods.SelectMethod = "GetAssets";
ods.TypeName = "dsAssetsTableAdapters.AssetsTableAdapter";
ods.SelectParameters.Clear();
ReportDataSource rds = new ReportDataSource("dsAssets_Assets", ods);
reportViewer1.LocalReport.DataSources.Clear();
reportViewer1.LocalReport.DataSources.Add(rds);
string _list = "";
string _list_missing_SN = "";
string filename = Server.MapPath("XLS/reconcile.xls");
string sheetname = GetExcelSheetNames(filename)[0].ToString();
String sConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;" +
"Data Source=" + filename + ";" +
"Extended Properties=Excel 8.0;";
OleDbConnection objConn = new OleDbConnection(sConnectionString);
objConn.Open();
OleDbCommand objCmdSelect = new OleDbCommand("SELECT * FROM [" + sheetname + "]", objConn);
OleDbDataAdapter objAdapter1 = new OleDbDataAdapter();
objAdapter1.SelectCommand = objCmdSelect;
DataSet objDataset1 = new DataSet();
objAdapter1.Fill(objDataset1, "XLData");
string m_AssetManagement = System.Configuration.ConfigurationManager.ConnectionStrings["Asset_Management"].ToString();
List<string> SN_list = new List<string>();
SqlDataReader Assets_rd;
SqlCommand cmdMyAssets = new SqlCommand();
cmdMyAssets.Connection = new SqlConnection(m_AssetManagement);
cmdMyAssets.CommandType = CommandType.StoredProcedure;
cmdMyAssets.CommandText = "sp_Assets_Hardware_Select_by_Serial_Number";
try
{
cmdMyAssets.Connection.Open();
Assets_rd = cmdMyAssets.ExecuteReader();
string strString;
while (Assets_rd.Read())
{
strString = Assets_rd.GetSqlString(0).ToString().Trim() + "^" + Assets_rd.GetInt32(1).ToString().Trim() + "^" + Assets_rd.GetInt32(2).ToString().Trim();
SN_list.Add(strString);
}
}
catch (SqlException dbError)
{
Trace.Write("Database unavailable with Message: ", dbError.Message);
Trace.Write("Stack Trace: ", dbError.StackTrace);
throw;
}
bool record_match = false;
foreach (DataRow drXCL in objDataset1.Tables[0].Rows)
{
if (drXCL.ItemArray[1].ToString() != string.Empty)
{
try
{
string[] assetInfo = null;
assetInfo = SN_list[0].Split('^');
if (assetInfo[0].Contains(drXCL.ItemArray[1].ToString()))
{
_list += "|" + drXCL.ItemArray[1].ToString();
}
else
{
_list_missing_SN += drXCL.ItemArray[1].ToString().Trim() + "<br>";
}
}
catch (Exception SqlEx)
{
// Throw Sqw Exception
clAppExceptions.buildEmailNotification(SqlEx.Message.ToString());
}
}
else
{
//_list += "|*** NO SERIAL NUMBER ***";
}
}
if (_list_missing_SN != "")
{
Page.ClientScript.RegisterClientScriptBlock(this.Page.GetType(), "myAlert", "<script language='javascript'>alert('Following Serial Numbers were not on the spreasheet: " + _list_missing_SN + "');</script>");
}
_list += "|";
ods.SelectMethod = "GetAssetsBySerialNumbers";
ods.SelectParameters.Add("list", _list);
reportViewer1.LocalReport.ReportPath = Server.MapPath("~/Reports/Asset_List.rdlc");
ReportParameter rpCategory = new ReportParameter("ReportParameter", "These assets are gone.");
ReportParameter[] _rpCategory = { rpCategory };
reportViewer1.LocalReport.SetParameters(_rpCategory);
reportViewer1.LocalReport.Refresh();
}
I would load the master list into an array and create a second array of bools that correspond to the positions of the first array. Then looping through the datatable, when you find the element, flip the bool to true. If you cannot find it, store that element in a not found array. Once the datatable loop is finished, you can produce 2 lists. The first list is the items in the datatable but not in the master list... the not found array. The second list is created by looping through the bool array, any value of false means that the master list element was not found in the datatable.
This can then be expanded to include counts or other pieces of information that should match but do not.
I'd suggest a different approach. You could copy the data from the database and put it in the spreadsheet on a different worksheet and use the match function. You could also take the data from the spreadsheet and put it in a new table. Then use a query to find discrepencies. I don't think a programming solution is required unless this isn't a one time thing. If this is required for an application of some sort, ignore my answer:)
Don't know if this is of any use but if you have the two lists in IEnumerable sequeneces you could do something simple with LINQ.
I have an extension method I wrote for IEnumerable that I use for this purpose:
public static IEnumerable<T> NotIn<T>(this IEnumerable<T> inputSequence, IEnumerable<T> secondSequence)
{
return secondSequence == null ? new List<T>(inputSequence) : inputSequence.Where(element => !secondSequence.Contains(element));
}
If I recall correctly I ended up finding a native LINQ function that accomplished the same thing but I, of course, forgot what it was
If your just looking for a quick solution, I would just do everything in Excel. It's easy to link Excel to a DB and to link lists.
Link your DB to your Excel file (this way it's always linked to the DB)
Insert a formula to check if the (part, key, etc...) in your master list exists in your list from the DB.
Use this link to see how to link lists in Excel.
Ultimately you have many options. To make a sound decision you need to answer a few questions.
How often will this task need to be performed?
What level of resources do you have available to utilize?
How quickly does this task need to run?
How much data needs to be compared?
Once you have answered these questions, we can suggest a solid solution to you more accurately.
Keep it simple... ADO.Net will probably the simplest approach for this problem. If you fill a DataTable with the values from the spreadsheet (hopefully using OleDb) you will be able to also pull information from the Database (using either OleDb or the correct ADO.Net client.) You can then update the values back into the database for fields such as location or last seen time. These Fill and Update commands can be queries or stored procs.
If you provide more detail such as table schema I could expand my answer further.
Edit...
If you already have one of the sources in a DataTable in .Net you could put both of them in the same DataSet and write a DataView query that would do an outer join. The Outer Join would allow you to see the matched and unmatched values.
Updated...
Sorry it took so long to get back to this. (Started a new job so I have been rather busy.) I am using two spreedsheets, but there is not reason that you couldn't use thie same concept between different databases and even different ADO.Net providers. The basic idea behind this example is to create a LastSeen timestamp in your database. Then instead of looking for what isn't there, you post the latest inventroy back to the database and then query for what hasn't been updated.
var inventoryFile = "Inventory.xlsx"; //ID,Item
var databaseFile = "Database.xlsx"; //ID,Item,Type,SN,LastSeen
var connectionFormatter = "Provider=Microsoft.ACE.OLEDB.12.0;" +
"Data Source=\"{0}\";Mode=ReadWrite;" +
"Extended Properties=\"Excel 12.0 Xml;HDR=Yes;\";";
var inventoryConnectionString = string.Format(connectionFormatter,
inventoryFile);
var databaseConnectionString = string.Format(connectionFormatter,
databaseFile);
using (var inventoryConnection =
new OleDbConnection(inventoryConnectionString))
using (var databaseConnection =
new OleDbConnection(databaseConnectionString))
{
if (inventoryConnection.State != ConnectionState.Open)
inventoryConnection.Open();
if (databaseConnection.State != ConnectionState.Open)
databaseConnection.Open();
var lastSeenCmdString = "SELECT MAX(LastSeen) FROM [Sheet1$]";
var lastSeenCommand = new OleDbCommand(lastSeenCmdString,
databaseConnection);
var lastSeen = lastSeenCommand.ExecuteScalar();
var inventorySelectCmdString = "SELECT ID, Item FROM [Sheet1$]";
var inventoryCmd = new OleDbCommand(inventorySelectCmdString,
inventoryConnection);
var table = new DataTable();
var idCol = table.Columns.Add("ID", typeof(int));
var itemCol = table.Columns.Add("Item", typeof(int));
var inventoryDataAdapter = new OleDbDataAdapter(inventoryCmd);
var databaseDataAdapter = new OleDbDataAdapter();
var updateLastSeenCmdString =
"UPDATE [Sheet1$] SET LastSeen=NOW() WHERE Item=?";
var updateCmd = new OleDbCommand(updateLastSeenCmdString,
databaseConnection);
var parameter = updateCmd.Parameters.Add("Item",
OleDbType.Integer,
0,
"Item");
databaseDataAdapter.UpdateCommand = updateCmd;
inventoryDataAdapter.Fill(table);
table.AcceptChanges();
foreach (var row in table.Rows.OfType<DataRow>())
row.SetModified();
databaseDataAdapter.Update(table);
var notSeenCmdString = "SELECT ID,Item,Type,SN,LastSeen " +
"FROM [Sheet1$]" +
"WHERE LastSeen <= ?";
var notSeenCmd = new OleDbCommand(notSeenCmdString,
databaseConnection);
notSeenCmd.Parameters.Add("LastSeen", OleDbType.Date).Value = lastSeen;
databaseDataAdapter.SelectCommand = notSeenCmd;
var missingInventory = new DataTable();
databaseDataAdapter.Fill(missingInventory);
foreach (var row in missingInventory.Rows.OfType<DataRow>())
Console.WriteLine("ID: {0} Item:{1} Type:{2} SN:{3} LastSeen:{4}",
row.ItemArray);
}