2

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

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

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

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

4

1 回答 1

2

几点考虑

  • 在我的示例中,我使用 Excel 电子表格的 CSV 插入,只是为了简化事情。无论您使用哪个,请确保您使用库来处理文件解析(例如,对 CSV 使用 string.Split(',') 将无法正确处理 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;
    }
}
于 2012-11-03T07:23:05.950 回答