.net:从Excel工作表中动态生成SQL数据库中的表

时间:2012-11-01 12:40:09

标签: .net c#-4.0

在我的项目中,我必须根据上传的Excel工作表创建数据库表。那么有人能告诉我如何使用asp.net的文件上传控件上传该文件后,从Excel工作表中动态生成SQL数据库中的表吗?

例如,我有一个像这样的Excel工作表sheet1.xlsx

ID   Name  MoblieNO
1    xyz   1234
2    zxy   5678
3    abc   9012

上传文件后,它应该在sql数据库中创建一个表,其中包含相同的no列和相同的数据类型。

1 个答案:

答案 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;
    }
}