【问题标题】:Best way to do a pivot table in SQLite?在 SQLite 中做数据透视表的最佳方法?
【发布时间】:2011-08-02 22:43:30
【问题描述】:

我正在使用 C# 和 SQLite 对大量数据进行切片,并且我经常需要以数据透视表的形式显示我的数据。通过使用 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 实现可以比 custom-data-manipulation-on-each-row 操作更快地执行简单的 filter-group-and-sum 操作,而这足以弥补该开销。 问题是,这类 SQL 语句生成起来更复杂,因为每列出现在语句中的两个位置——一次在 fields 子句中,一次在 FROM 子句中,而不是像前两种方法那样仅在 fields 子句中.另外,我需要小心所有这些临时表的名称。

那么,有什么意见吗?

【问题讨论】:

    标签: c# sql sqlite pivot


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

      看起来您正在使用EAV 设计,这使得有必要将行转为列。在适当的关系数据库设计中,您不会使用 EAV。列就是列,你不需要旋转。

      也就是说,我知道 EAV 有时是一种轻而易举的设计,当人们需要在数据库中存储一组“可扩展”的属性时,它是一种流行的设计。

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

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

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

      这有好处:

      • 查询很容易编写。选择列表中只需命名三列,不需要列别名。
      • RDBMS 执行查询的成本很低。没有GROUP BY,没有自加入等。
      • 仍然支持 EAV 设计的可扩展优势。事实上,它更容易扩展,因为当您向数据添加新的逻辑列时,您不必重写 SQL 查询。

      【讨论】:

      • 我不使用 EAV。 col1、col2 和 col3 之间没有本质区别 - 例如,它们可能是不同的日期。我想要一个透视 SQL 查询的唯一原因是我可以在 Excel 电子表格中向我的客户显示它。我考虑过对数据透视进行硬编码,但我更喜欢将它留在 SQL 中,因为我想将我的 SQL 放在 XML 文件中,这样我就可以使用同一个程序来加载不同的 XML 并生成不同的数据切片。
      猜你喜欢
      • 2019-06-11
      • 2017-02-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多