在SQLite(C#)中,当我UNION两个表时,我丢失了列类型信息

时间:2014-06-03 12:24:05

标签: c# sqlite

在下面的代码中,当我从单个表执行查询时,类型信息是完美的...但是,当我从两个相同定义的表的并集执行查询时...类型信息丢失(到a学位)如下:

Select * from Test1
Name (System.String)
Date (System.DateTime)
Value (System.Int32)

Select * from Test1 UNION Select * from Test2
Name (System.String)
Date (System.String)  <== DateTime converted to String
Value (System.Int64)  <== Int32 converted to Int64

当我使用UNION时,有没有办法保存类型信息?

代码:

        sql = "Create Table Test1 " +
            "([Name] string, [Date] date, [Value] int)";
        using (SQLiteCommand command = new SQLiteCommand(sql, connection))
        { command.ExecuteNonQuery(); }

        sql = "Create Table Test2 " +
            "([Name] string, [Date] date, [Value] int)";
        using (SQLiteCommand command = new SQLiteCommand(sql, connection))
        { command.ExecuteNonQuery(); }

        sql = "Insert into Test1 (Name, Date, Value) values (@Name, @Date, @Value)";
        using (SQLiteCommand command = new SQLiteCommand(sql, connection))
        {
            command.Parameters.Add(new SQLiteParameter("@Name", "John Doe"));
            command.Parameters.Add(new SQLiteParameter("@Date", DateTime.Parse("11/30/1958")));
            command.Parameters.Add(new SQLiteParameter("@Value", 1));
            command.ExecuteNonQuery();
        }

        sql = "Insert into Test2 (Name, Date, Value) values (@Name, @Date, @Value)";
        using (SQLiteCommand command = new SQLiteCommand(sql, connection))
        {
            command.Parameters.Add(new SQLiteParameter("@Name", "Brian Rice"));
            command.Parameters.Add(new SQLiteParameter("@Date", DateTime.Parse("12/1/1970")));
            command.Parameters.Add(new SQLiteParameter("@Value", 2));
            command.ExecuteNonQuery();
        }

        sql = "Select * from Test1";
        DataTable dt = new DataTable();
        using (SQLiteCommand cmd = new SQLiteCommand(sql, connection))
        {
            // create data adapter
            using (SQLiteDataAdapter da = new SQLiteDataAdapter(cmd))
            {
                // this will query your database and return the result to your datatable
                da.Fill(dt);
            }
        }
        Console.WriteLine(sql);
        foreach (DataColumn column in dt.Columns)
            Console.WriteLine(column.ColumnName + " (" + column.DataType + ")");

        sql = "Select * from Test1 UNION Select * from Test2";
        dt = new DataTable();
        using (SQLiteCommand cmd = new SQLiteCommand(sql, connection))
        {
            // create data adapter
            using (SQLiteDataAdapter da = new SQLiteDataAdapter(cmd))
            {
                // this will query your database and return the result to your datatable
                da.Fill(dt);
            }
        }
        Console.WriteLine(sql);
        foreach (DataColumn column in dt.Columns)
            Console.WriteLine(column.ColumnName + " (" + column.DataType + ")");

2 个答案:

答案 0 :(得分:2)

我在这里修好了。

改为创建视图

  CREATE VIEW "vwTest" AS Select * from Test1 UNION Select * from Test2

然后你应该从视图中选择

  Select * from vwTest

答案 1 :(得分:1)

根据Datatypes In SQLite Version 3,在SQLite 3中没有真正的,或者我应该说,没有传统的数据类型。它明确表示既不是Date, Datetime也没有Bool存在。

而是有Storage Classes

  • NULL。该值为NULL值。
  • INTEGER。该值是有符号整数,存储为1,2,3,4,6或8个字节,具体取决于值的大小。
  • REAL。该值是浮点值,存储为8字节IEEE浮点数。
  • TEXT。该值是一个文本字符串,使用数据库编码(UTF-8,UTF-16BE或UTF-16LE)存储。
  • BLOB。该值是一个数据块,完全按照输入的方式存储。

还有类型亲和力的概念  它根据需要组织各种类和子类之间的转换。 (!?)

这可能是SQLite内部或.NET接口在处理UNION语句的过程中产生您注意到的转换的原因。 这是文档中另一个有趣的引用:

SQLite没有为存储日期和/或时间而预留的存储类。相反,SQLite的内置日期和时间函数能够将日期和时间存储为TEXT,REAL或INTEGER值。

看起来,在解析UNION's SELECT语句时,每个列都会转换为它后面可能找到的最通用的子类:对于所有INT,它将是INT64,这是显而易见的;对于日期而言,它是STRING,这不太明显但仍然合理......

由于你的桌子是相同的,你的价值也差不多似乎是一个人必须忍受的条款,我担心,除非不同的界面会采取不同的行为......