无法获取从 SELECT 返回的多行以按特定列正确汇总

Unable to get multiple rows returned from a SELECT to summarize correctly by a specific column

我有一个 Oracle table,看起来像这样:

     test_time              test_name    test_type     test_location    test_value
     -----------------      ---------    ---------     -------------    ----------
     09/22/20 12:00:05         A            RT             Albany           200
     09/22/20 12:00:05         A            RT             Chicago          500
     09/22/20 12:00:05         B            RT             Albany           400
     09/22/20 12:00:05         B            RT             Chicago          300
     09/22/20 12:00:05         A            WPL            Albany           1500
     09/22/20 12:00:05         A            WPL            Chicago          2300
     09/22/20 12:00:05         B            WPL            Albany           2100
     09/22/20 12:00:05         B            WPL            Chicago          1900
     09/22/20 12:05:47         A            RT             Albany           300
     09/22/20 12:05:47         A            RT             Chicago          400
     09/22/20 12:05:47         B            RT             Albany           600
     09/22/20 12:05:47         B            RT             Chicago          500
     09/22/20 12:05:47         A            WPL            Albany           1700
     09/22/20 12:05:47         A            WPL            Chicago          2000
     09/22/20 12:05:47         B            WPL            Albany           1800
     09/22/20 12:05:47         B            WPL            Chicago          2400         

我想 运行 一个 SELECT 反对这个 table 这将显示特定 test_type 引用的每个位置的平均值(在这种情况下, “RT”)在过去 11 分钟内,由 test_name 总结。 “11 分钟”用于确保我将从至少两次脚本迭代中检索行,该脚本每五分钟插入一次记录。

我希望针对此 table 的 SELECT 语句的结果如下所示:

     test_name      albany_avg_val     chicago_avg_val  
     ---------      --------------     ---------------  
      A                 250                450         
      B                 500                400    

(注意:test_name“A”的“albany_avg_val”反映了与test_name的两次迭代相关的“test_value”值的平均值"A"/test_type "RT"/test_location "Albany" 即 运行 在 12:00 和 12:05).

我到目前为止构建的 SELECT 语句如下所示:

SELECT
   test_name,
   CASE test_location
      WHEN 'Albany'
         THEN ROUND(AVG( test_value ),0) albany_avg_val
      WHEN 'Chicago'
         THEN ROUND(AVG( test_value ),0) chicago_avg_val
   END
FROM
   test_table
WHERE
   test_type = 'RT' AND test_time > sysdate - interval '11' minute;

...但它没有按预期工作。有人可以帮我解决我可能遗漏的问题吗?

我想你想要:

select
    test_name,
    round(avg(case when test_location = 'Albany'  then test_value end)) albany_avg_val
    round(avg(case when test_location = 'Chicago' then test_value end)) chicago_avg_val
from test_table
where
   test_type = 'rt' 
   and test_location in ('Albany', 'Chicago')
   and test_time > sysdate - 11 / 24 / 60
group by test_name

即:

  • 使用group by!

  • 在聚合函数avg()

    内移动case表达式
  • 每列应该分开 - 条件表达式不能生成两列

还有...:[=​​20=]

  • where子句中预过滤提高查询效率

  • 针对 sysdate(即 date)使用“数字”日期算法更安全;如果你想要区间运算,请使用 systimestamp 而不是

  • 0round()

    的默认精度

看来您需要条件聚合:

SELECT
      test_name,
      AVG(CASE 
          WHEN test_location='Albany'
          THEN ROUND( test_value ) END) AS albany_avg_val,
      AVG(WHEN test_location='Chicago'
          THEN ROUND( test_value ) END) AS chicago_avg_val
 FROM test_table
WHERE test_type = 'RT' 
  AND test_time > sysdate - interval '11' minute;
GROUP BY test_name

ROUND() 函数的第二个参数 (0) 是多余的。

请尝试这样的操作

SELECT
   test_name,
   ROUND(AVG(CASE when test_location='Albany'
         THEN  test_value 
         else null end),0) albany_avg_val,
 ROUND(AVG(CASE when test_location='Chicago'
         THEN  test_value 
         else null end),0) Chicago_avg_val
 
FROM
   test_table
WHERE
   test_type = 'RT' AND test_time > sysdate - interval '11' minute
   group by test_name; ```

pivot 子句正是为此类事情设计的:以下查询聚合了所有 test_type 值:

select *
from (select test_name, test_location, test_type, test_value from test_table)
pivot(
  avg(test_value)
  for test_location in ('Albany ' as Albany,'Chicago' as Chicago)
);

结果:

TEST_NAME TEST_TYPE     ALBANY    CHICAGO
--------- --------- ---------- ----------
A         RT               250        450
B         RT               500        400
A         WPL             1600       2150
B         WPL             1950       2150

或者如果您只想过滤 RT:

select *
from (select test_name, test_location, test_value from test_table where test_type='RT')
pivot(
  avg(test_value)
  for test_location in ('Albany ' as Albany,'Chicago' as Chicago)
);

结果:

TEST_NAME     ALBANY    CHICAGO
--------- ---------- ----------
B                500        400
A                250        450

带有示例数据的完整测试用例:

with test_table(test_time,test_name,test_type,test_location,test_value) as (
select to_date('09/22/20 12:00:05','mm/dd/yy hh24:mi:ss'), 'A', 'RT ', 'Albany ', 200  from dual union all
select to_date('09/22/20 12:00:05','mm/dd/yy hh24:mi:ss'), 'A', 'RT ', 'Chicago', 500  from dual union all
select to_date('09/22/20 12:00:05','mm/dd/yy hh24:mi:ss'), 'B', 'RT ', 'Albany ', 400  from dual union all
select to_date('09/22/20 12:00:05','mm/dd/yy hh24:mi:ss'), 'B', 'RT ', 'Chicago', 300  from dual union all
select to_date('09/22/20 12:00:05','mm/dd/yy hh24:mi:ss'), 'A', 'WPL', 'Albany ', 1500 from dual union all
select to_date('09/22/20 12:00:05','mm/dd/yy hh24:mi:ss'), 'A', 'WPL', 'Chicago', 2300 from dual union all
select to_date('09/22/20 12:00:05','mm/dd/yy hh24:mi:ss'), 'B', 'WPL', 'Albany ', 2100 from dual union all
select to_date('09/22/20 12:00:05','mm/dd/yy hh24:mi:ss'), 'B', 'WPL', 'Chicago', 1900 from dual union all
select to_date('09/22/20 12:05:47','mm/dd/yy hh24:mi:ss'), 'A', 'RT ', 'Albany ', 300  from dual union all
select to_date('09/22/20 12:05:47','mm/dd/yy hh24:mi:ss'), 'A', 'RT ', 'Chicago', 400  from dual union all
select to_date('09/22/20 12:05:47','mm/dd/yy hh24:mi:ss'), 'B', 'RT ', 'Albany ', 600  from dual union all
select to_date('09/22/20 12:05:47','mm/dd/yy hh24:mi:ss'), 'B', 'RT ', 'Chicago', 500  from dual union all
select to_date('09/22/20 12:05:47','mm/dd/yy hh24:mi:ss'), 'A', 'WPL', 'Albany ', 1700 from dual union all
select to_date('09/22/20 12:05:47','mm/dd/yy hh24:mi:ss'), 'A', 'WPL', 'Chicago', 2000 from dual union all
select to_date('09/22/20 12:05:47','mm/dd/yy hh24:mi:ss'), 'B', 'WPL', 'Albany ', 1800 from dual union all
select to_date('09/22/20 12:05:47','mm/dd/yy hh24:mi:ss'), 'B', 'WPL', 'Chicago', 2400 from dual 
)
select *
from (select test_name, test_location, test_type, test_value from test_table)
pivot(
  avg(test_value)
  for test_location in ('Albany ' as Albany, 'Chicago' as Chicago)
);