在我的项目中,我必须根据上传的Excel工作表创建数据库表。那么有人能告诉我如何使用asp.net的文件上传控件上传该文件后,从Excel工作表中动态生成SQL数据库中的表吗?
例如,我有一个像这样的Excel工作表sheet1.xlsx
ID Name MoblieNO
1 xyz 1234
2 zxy 5678
3 abc 9012
上传文件后,它应该在sql数据库中创建一个表,其中包含相同的no列和相同的数据类型。
答案 0 :(得分:2)
在我的示例中,我正在使用Excel电子表格的CSV实例,只是为了简化操作。无论您使用哪种方法,都要确保使用库来处理文件的解析(例如,使用string.Split(',')表示CSV无法正确处理CSV中的所有可能变体。
对于您使用的任何库,对于我的算法,如果您可以使用x,y坐标访问任何给定的单元格,事情就会变得更容易。
我不是基于这样的数据来确定列类型的专家,也许这样做是一种万无一失的方法。但是我发现这总是总是会变得非常不稳定和不合时宜。例如,从INT转换为BIGINT。您根据类型确定类型的值可能只有123,但填写该电子表格的人可能会输入123456784305之类的值,但如果您要转换,则不会知道基于123。
指定最大长度或使用VARCHAR与TEXT相同。如果没有首先遍历整个记录集,并确定每列的最大可能值,则很难这样做。
基于最后两点,我会说最终会更容易将所有内容存储为VARCHAR,以保持桌面的灵活性,然后在运行时进行转换。
很高兴在此提供更多详细信息,但希望代码+评论能够很好地解释这些内容。
class Program
{
static void Main(string[] args)
{
string fileName = "Products.csv";
/* First, put all of our lines and columns into a list...
* My code assumes that any library you use for this would allow you to access a specific cell using x,y co-ordinatates.
*/
List<List<string>> lines = new List<List<string>>();
using (StreamReader csvReader = new StreamReader(fileName))
{
string line;
while ((line = csvReader.ReadLine()) != null)
{
List<string> columns = new List<string>(line.Split(','));
lines.Add(columns);
}
}
/* Now, iterate through each line.
* 1) Break it into a further list of the colums for that line
* 2) If this is the first line, assume we have headers, which will be the names of the table columns
* 3) Check the second row of that column and determine it's data type. If the value is empty, then go to the next row and check that.
* 4) Keep checking down the rows for each column until you find a value that can determine the data type.
* 5) Use this information to write out the appropriate CREATE TABLE command, and execute.
*/
//Use this dictionary to keep track of the type of each column later on.
Dictionary<string, string> tableTypes = new Dictionary<string, string>();
StringBuilder tableQuery = new StringBuilder("CREATE TABLE " + getTableName(fileName) + " (");
for (int row = 0; row < lines.Count; row++)
{
List<string> currentColumns = lines[row];
for (int column = 0; column < currentColumns.Count; column++)
{
//If this is the first row, need to determine the table structure for this column.
if (row == 0)
{
string columnName = currentColumns[column];
//Now check the same column for the row below, and try to determine it's type.
for (int checkRow = 1; checkRow < lines.Count; checkRow++)
{
string typeValue = getType(lines[checkRow][column]);
if (typeValue != null)
{
//Found a valid type for this column, add to query.
tableQuery.Append(columnName + " " + typeValue);
if (column < (currentColumns.Count - 1))
{
tableQuery.Append(",");
}
else
{
tableQuery.Append(")");
//We're done building the query... Execute it.
Console.WriteLine("Creating new table: " + tableQuery.ToString());
}
tableTypes.Add(columnName, typeValue);
//Stop looking for a non-empty value...
break;
}
}
}
//We're not in the first row anymore, use the dictionary created above to determine what column names to put into your INSERT queries.
else
{
//Insert the rest of the rows here...
}
}
}
Console.ReadLine();
}
/// <summary>
/// This method will determine the Type of an object based on a string value
/// </summary>
/// <param name="Value">The string representation of a value. Eg. "1", "1.0", "foo", etc</param>
/// <returns></returns>
static string getType(string Value)
{
if (String.IsNullOrEmpty(Value) || String.IsNullOrWhiteSpace(Value))
{
return null;
}
long longValue;
decimal decimalValue;
if (Int64.TryParse(Value, out longValue))
return "BIGINT";
if (Decimal.TryParse(Value, out decimalValue))
return "DECIMAL";
//If none of the above worked, just return the type of string
return "NVARCHAR";
}
static string getTableName(string Value)
{
string[] values = Value.Split('.');
string name = values[0];
name = name.Replace(" ", "");
return name;
}
}