调整多级行到列查询

Posted

技术标签:

【中文标题】调整多级行到列查询【英文标题】:Tuning Multi-Level Rows-to-Cols Query 【发布时间】:2009-09-18 19:29:17 【问题描述】:

在对上一篇文章 (Tuning Rows-to-Cols Query) 的回答中,我学习了如何更有效地构建允许按日期过滤的行到列查询。但是,我现在需要更进一步。

以下查询的架构如下:SAMPLE (1-to-many) TEST (1-to-many) RESULT (1-to-MANY) 每个样本都有一个或多个测试,每个测试都有一个或多个结果。

问题:如何更有效地重写此视图,同时仍允许按“采样日期”进行快速过滤?

关注点:MAX(tst.created_on) 的分数应该是 test_id(第 1 组)的唯一测试集,而不是 test_id(第 2 集)的唯一结果集:

设置 1: 1, 2, 76, 77, 135, 136
第 2 组:1, 1, 2, 2, 76, 76, 77, 77, 135, 135, 136, 136
CREATE OR REPLACE VIEW V_TITRATION_SAMPLES as
     SELECT sam.sampled_on "Date Sampled",
            MAX(CASE WHEN res.result_tmpl_id = 4 THEN result END) "titrator", 
            MAX(CASE WHEN res.result_tmpl_id = 3 THEN result END) "factor",
            MAX(tst.created_on) "Last Test Creation"
       FROM lims.sample sam
       JOIN lims.test tst ON sam.sample_id = tst.sample_id
       JOIN lims.result res ON tst.test_id = res.test_id
      WHERE sam.sample_tmpl_id = 4
   GROUP BY sample_id, sam.sampled_on

在 GROUP BY 之前:

   SAMPLE COLUMNS      |    TEST COLUMNS     | RESULT COLUMNS
   id  tmp sampled_on  | *id tmp created_on  | *id tmp result
    1   4  09-20 21:50 |   1  7  09-20 22:20 |   1  1     5
    1   4  09-20 21:50 |   1  7  09-20 22:20 |   2  3    2.1
    1   4  09-20 21:50 |   2  9  09-20 22:23 |   3  4     6
    1   4  09-20 21:50 |   2  9  09-20 22:23 |   4  6    123

   25   4  09-21 08:26 |  76  7  09-21 08:53 |  96  1     4
   25   4  09-21 08:26 |  76  7  09-21 08:53 |  97  3    1.6
   25   4  09-21 08:26 |  77  9  09-21 08:52 |  98  4     4
   25   4  09-21 08:26 |  77  9  09-21 08:52 |  99  6    103

  102   4  09-21 09:54 | 135  7  09-21 10:34 | 185  1     1
  102   4  09-21 09:54 | 135  7  09-21 10:34 | 186  3    1.8
  102   4  09-21 09:54 | 136  9  09-21 10:05 | 187  4     5
  102   4  09-21 09:54 | 136  9  09-21 10:05 | 188  6    110

* Shortened TABLE_id and TABLE_template_id to id and tmp, 
  respectively to keep this data grid narrow.

结果:

   "Date Sampled"  titrator   factor   "Last Test Creation"
   09-20 21:50        6         2.1    09-20 22:23
   09-21 08:26        4         1.6    09-21 08:53
   09-21 09:54        5         1.8    09-21 10:34

【问题讨论】:

我不确定我是否理解“只需要在样本的测试中检查,而不是在样本下所有测试的所有结果中检查”在这种情况下的含义。您能否展示数据样本并向我们展示您的预期输出?在这一点上,我的赌注是该解决方案将涉及分析函数,但我不确定您要寻找什么输出,所以我不确定建议使用哪个函数。 架构描述不清楚。你能(1)对所有表使用别名并(2)用“on”替换“using”子句吗? 我简化了主要问题。现在应该更清楚了。 我想我现在明白了 - 更新了我的答案。 【参考方案1】:

试一试:

WITH titrate AS (
     SELECT r.test_id,
            MAX(r.result) 'titrator'
       FROM LIMS.RESULT r
      WHERE r.result_tmpl_id = 4
   GROUP BY r.test_id),
    factor AS (
     SELECT r.test_id,
            MAX(r.result) 'factor'
       FROM LIMS.RESULT r
      WHERE r.result_tmpl_id = 3
   GROUP BY r.test_id),
     created AS (
     SELECT t.sample_id,
            MAX(t.created_on) 'created'
       FROM LIMS.TEST t
   GROUP BY t.sample_id)
   SELECT s.sampled_on,
          ti.titrator,
          f.factor,
          t.created
     FROM LIMS.SAMPLE s
     JOIN created t ON t.sample_id = s.sample_id
LEFT JOIN titrate ti ON ti.test_id = t.test_id
LEFT JOIN factor f ON f.test_id = t.test_id

我使用子查询分解更改了 CASE 语句 - LEFT JOIN 可能不是必需的。

关键部分是 LIMS.TEST 表的内联视图/子查询分解,您希望在其中获取 sample_id 的最大 created_on 日期 - 将其与查询的其余部分分开将为您提供更多控制从该表中返回您想要的具体内容。

使用内联视图的等效替代方案 - 它们的执行方式相同,只是自 9i 起才支持子查询分解:

   SELECT s.sampled_on,
          ti.titrator,
          f.factor,
          t.created
     FROM LIMS.SAMPLE s
     JOIN (SELECT t.sample_id,
                  MAX(t.created_on) 'created'
             FROM LIMS.TEST t
         GROUP BY t.sample_id) t ON t.sample_id = s.sample_id
LEFT JOIN (SELECT r.test_id,
                  MAX(r.result) 'titrator'
             FROM LIMS.RESULT r
            WHERE r.result_tmpl_id = 4
         GROUP BY r.test_id) ti ON ti.test_id = t.test_id
LEFT JOIN (SELECT r.test_id,
                  MAX(r.result) 'factor'
             FROM LIMS.RESULT r
            WHERE r.result_tmpl_id = 3
         GROUP BY r.test_id) f ON f.test_id = t.test_id

【讨论】:

以上是关于调整多级行到列查询的主要内容,如果未能解决你的问题,请参考以下文章

SQL 查询中的行到列

如何在 sql server 2008 中编写对行到列的查询?

PostgreSQL 交叉表转置行到列

行到列SQL

使用 PIVOT 函数的行到列 (Oracle)

行到列的总和