SQL Oracle Query:可以优化此查询吗?

时间:2014-08-29 08:47:08

标签: sql oracle

我想选择数据库表的最新条目,该表包含具有相同产品编号(但日期不同)的多行。 在这种特殊情况下,我希望按TKP_NOISE_MOTOR_RESULTS表过滤PRODUCT_NUMBER表,该表在表中至少出现五次,而在该子集中,我想要检索最近的行{ {1}}每个prdocut编号

我设法创建了这样一个查询,但有三个子查询T1,T2,T3。我感觉只有两个表可以完成,不需要内连接。但是创建它需要花费很多时间,因为很难将脚本从MySQL转换为Oracle。

是否可以优化以下查询,因此需要更少的子查询?

SAVEDATE

3 个答案:

答案 0 :(得分:2)

如果您只想要产品编号和日期,可以简化当前的方法;如你所怀疑的那样,你需要多次访问该表,并且可以用IN子句替换连接:

SELECT PRODUCT_NUMBER, MAX(SAVEDATE)
FROM TKP_NOISE_MOTOR_RESULTS
WHERE PRODUCT_NUMBER IN (
  SELECT PRODUCT_NUMBER
  FROM TKP_NOISE_MOTOR_RESULTS 
  GROUP BY PRODUCT_NUMBER
  HAVING COUNT(*)>5
)
GROUP BY PRODUCT_NUMBER;

但是如果你有其他专栏,那么你需要让它更复杂。

您可以使用analytic functions来防止必须多次敲击表格或进行任何加入:

SELECT PRODUCT_NUMBER, SAVEDATE --, other columns
FROM (
  SELECT T.*,
    ROW_NUMBER() OVER (PARTITION BY T.PRODUCT_NUMBER
      ORDER BY T.SAVEDATE DESC) AS RN,
    COUNT(*) OVER (PARTITION BY T.PRODUCT_NUMBER) AS CNT
  FROM TKP_NOISE_MOTOR_RESULTS T
  WHERE T.SAVEDATE BETWEEN DATE '2014-08-27' AND DATE '2014-08-28'
)
WHERE CNT > 5
AND RN = 1;

内部查询从基表中获取所有列,并根据分析函数添加伪列。 ROW_NUMBER()为特定产品的每一行指定一个值,最新日期为数字1(通过ORDER BY ... DESC)。您还可以考虑RANK()DENSE_RANK(),特别是如果您可能有关系,并希望在出现平局时显示所有行。 COUNT(*)计算每种产品的行数。

外部查询然后将其过滤为仅包含计数大于5的产品;并且也只是排在第一位,这是最新的。

SQL Fiddle使用您的原始查询,并使用相同的数据。

我也转而使用日期文字;您应该至少使用TO_DATE使用显式格式掩码而不是依赖会话NLS设置。另请注意,BETWEEN包含在内,所以这个(和你原来的)会在28日午夜开始;你可能想用:

  WHERE T.SAVEDATE >= DATE '2014-08-27'
  AND T.SAVEDATE < DATE '2014-08-28'

..或者如果您尝试包括这两天的所有记录,那么< DATE '2014-08-29'。我认为他们有时间,否则同一日期的五个记录看起来是一样的,你需要一些其他的方式来决定哪个是最新的#。

答案 1 :(得分:2)

除非使用相当旧的Oracle版本,否则您可以使用COUNT()ROW_NUMBER()的分析形式来获得我认为的结果。试试这个:

SELECT
      *
FROM (
      SELECT
            TNMR.*
          , COUNT(*) OVER (PARTITION BY TNMR.PRODUCT_NUMBER) AS CN
          , ROW_NUMBER() OVER (PARTITION BY TNMR.PRODUCT_NUMBER
                               ORDER BY TNMR.SAVEDATE DESC) AS RN
      FROM messfeld.TKP_NOISE_MOTOR_RESULTS TNMR
      ) T1
WHERE T1.CN >= 5 AND T1.RN = 1
AND T1.SAVEDATE BETWEEN '27-AUG-14' AND '28-AUG-14'
;

但是我真的不推荐dd-mmm-yy作为日期文字,我从不使用BETWEEN作为日期范围,而是使用它代替:

AND T1.SAVEDATE >= to_date('27-08-2014','dd-mmm-yyyy') 
AND T1.SAVEDATE < to_date('28-08-2014','dd-mmm-yyyy') + 1 -- 1 day added

FOOTNOTE &#34;选择*&#34;仅用于方便,上面仅用于缩写和/或因为细节未知。请完整说明选择条款。

答案 2 :(得分:1)

您似乎正在搜索所有

的产品
  • 存在五个以上的记录
  • 在8月27日或28日至少有一条记录。

其中你想要在该日期范围内找到最新记录。

因此,选择所有包含5条以上记录的产品(如您所做),并使用案例构造确定日期范围内的最新保存日期。

select *
from messfeld.tkp_noise_motor_results 
where (product_number, savedate) in
(
  select
    product_number, 
    max(case when to_char(savedate, 'dd-mm-yyyy') in ('27-08-2014', '28-08-2014') then savedate end)
  from messfeld.tkp_noise_motor_results 
  group by product_number
  having count(*) > 5 
  -- the next line is not really needed. Use it if you find it more readable
  and max(case when to_char(savedate, 'dd-mm-yyyy') in ('27-08-2014', '28-08-2014') then savedate end) is not null
);
相关问题