我已经在这里待了几个小时,似乎无法找到解决方案。我有2个库存清单,一个是电子表格,另一个是数据表。我需要将电子表格与数据表进行匹配,以确定我是否缺少库存。电子表格应该与我在数据库中的内容相匹配,即电子表格就像一个主数据库,所以当我在数据库中缺少库存时,我需要添加一个列表并构建一个报告。
我想通过遍历电子表格和电子表格循环中的每个库存通过数据表我可以实现我的目标,但事实证明这是错误的。有什么想法我会怎么做?
谢谢, 埃里克
以下是方法:
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();
}
答案 0 :(得分:1)
我会将主列表加载到数组中并创建第二个bool数组,这些bool数组对应于第一个数组的位置。然后循环遍历数据表,当找到元素时,将bool翻转为true。如果找不到,请将该元素存储在未找到的数组中。完成数据表循环后,您可以生成2个列表。第一个列表是数据表中的项目,但不在主列表中......未找到的数组。第二个列表是通过循环遍历bool数组创建的,任何false值都表示在数据表中找不到主列表元素。
然后可以将其扩展为包括应该匹配但不匹配的计数或其他信息。
答案 1 :(得分:1)
我建议采用不同的方法。您可以从数据库中复制数据并将其放在不同工作表的电子表格中并使用匹配功能。您还可以从电子表格中获取数据并将其放入新表中。然后使用查询来查找差异。我认为不需要编程解决方案,除非这不是一次性的事情。如果这是某种应用程序所必需的,请忽略我的答案:)
答案 2 :(得分:1)
不知道这是否有用,但如果你有IEnumerable序列中的两个列表,你可以用LINQ做一些简单的事情。
我有一个我为IEnumerable编写的扩展方法,我将其用于此目的:
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));
}
如果我没记错的话,我最终找到了原生的LINQ功能,完成了同样的事情,但我当然忘记了它是什么
答案 3 :(得分:1)
如果您只是寻找快速解决方案,我会在Excel中完成所有工作。将Excel链接到数据库和链接列表很容易。
将您的数据库链接到您的Excel文件(这样它始终链接到数据库)
插入公式以检查主列表中的(部分,键等)是否存在于数据库的列表中。
使用此link查看如何在Excel中链接列表。
答案 4 :(得分:0)
保持简单...... ADO.Net可能是解决此问题的最简单方法。如果使用电子表格中的值填充DataTable(希望使用OleDb),您还可以从数据库中提取信息(使用OleDb或正确的ADO.Net客户端。)然后,您可以将值更新回数据库对于诸如位置或上次看到的时间等字段。这些Fill和Update命令可以是查询或存储过程。
如果您提供更多详细信息,例如表格架构,我可以进一步扩展我的答案。
修改... 强>
如果你已经在.Net中的DataTable中拥有了一个源,你可以将它们放在同一个DataSet中并编写一个可以进行外连接的DataView查询。外部联接将允许您查看匹配和不匹配的值。
<强>更新... 强>
很抱歉,花了这么长时间才回到这里。 (开始一份新工作,所以我一直很忙。)我正在使用两个spreedsheets,但没有理由不能在不同的数据库甚至不同的ADO.Net提供商之间使用相同的概念。此示例背后的基本思想是在数据库中创建LastSeen时间戳。然后,不是查找不存在的内容,而是将最新的inventtroy发布回数据库,然后查询尚未更新的内容。
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);
}
答案 5 :(得分:0)
最终你有很多选择。要做出明智的决定,您需要回答几个问题。
一旦您回答了这些问题,我们就可以更准确地为您提供可靠的解决方案。