在SQLite中执行数据透视表的最佳方法是什么?

我正在使用C#和SQLite来分割大量数据,我经常需要以数据透视表的forms显示我的数据。 我可以通过使用C#从另一个查询创建SQL命令轻松地使我的枢轴动态化,但我仍然无法决定哪种方式进行旋转本身,所以我希望听到一些关于这个问题的程序员的意见比我..

我有三种方法。 假设我们有一个名为tData的简单表,其中包含三列:“row”表示该数据的行号,“col”表示列号,“val”表示该值。

正统的方法是使用CASE表达式:

SELECT row, sum(CASE col WHEN 1 THEN val END) AS col1, sum(CASE col WHEN 2 THEN val END) AS col2, sum(CASE col WHEN 3 THEN val END) AS col3 FROM tData GROUP BY row 

但是,我想也许它可能会更快,如果我放弃CASE语句并直接在值上使用逻辑表达式,利用true == 1和false == 0的事实:

 SELECT row, sum((col=1)*val) AS col1, sum((col=2)*val) AS col2, sum((col=3)*val) AS col3 FROM tData GROUP BY row 

我怀疑这个方法应该更快,因为CASE表达式应该有一些开销,但我不太确定。

第三种方法有点复杂:它使用JOIN来进行透视:

 SELECT rows.row, col1.valSum AS col1, col2.valSum AS col2, col3.valSum AS col3 FROM (SELECT row FROM tData GROUP BY row) AS rows LEFT JOIN (SELECT row,sum(val) AS valSum FROM tData WHERE col=1 GROUP BY row) AS col1 ON rows.row=col1.row LEFT JOIN (SELECT row,sum(val) AS valSum FROM tData WHERE col=2 GROUP BY row) AS col2 ON rows.row=col2.row LEFT JOIN (SELECT row,sum(val) AS valSum FROM tData WHERE col=3 GROUP BY row) AS col3 ON rows.row=col3.row 

确实,那些JOIN有一个严重的开销,但是从我处理大型表的经验来看,SQL实现可以比每行操作上的自定义数据操作快得多地执行简单的filter组和操作,并且超过了这个开销。 问题是,这些类型的SQL语句生成起来比较复杂,因为每个列出现在语句的两个位置 – 一次在fields子句中,一次在FROM子句中,而不是像前两个方法一样在fields子句中。 另外,我需要小心所有那些临时表的名字。

那么,有什么意见吗?

我希望case语句方法比对表执行尽可能多的groupbys-and-join更快地执行,因为在列中有不同的值。 前者是CPU密集型,后者是磁盘密集型。 例如,如果要成为列标题的列值包含一周中的某一天,则您将拥有七个数据透视列和七个选择组。 那可能很贵; 这取决于桌子的大小。

看起来您正在使用EAV设计,这使得必须将行转移到列中。 在适当的关系数据库设计中,您不会使用EAV。 列将是列,您不需要透视。

也就是说,我知道EAV有时候是邪恶中的较小者,当需要在数据库中存储“可扩展”属性集时,它是一种流行的设计。

获取数据的最有效方法是忘记在SQL中执行数据透视。 只需将每个给定值row多个行获取属性:

 SELECT row, col, val FROM tData WHERE row = ... 

然后在C#应用程序中编写代码以循环生成的多行结果集。 为每个不同的row创建一个新对象。 将对象的col字段设置为值val 。 然后继续获取查询结果的下一行。

这有以下优点:

  • 查询很容易编写。 在select-list中只能命名三列,不需要列别名。
  • 查询对于RDBMS执行来说是便宜的。 没有GROUP BY ,没有自我加入等
  • 仍然支持EAV设计的可扩展优势。 实际上,它更容易扩展,因为当您向数据添加新的逻辑列时,您不必重写SQL查询。