Sql 计算分析函数上的WHERE谓词优先于其他谓词(Oracle分析函数) 背景

Sql 计算分析函数上的WHERE谓词优先于其他谓词(Oracle分析函数) 背景,sql,oracle,where-clause,operator-precedence,analytic-functions,Sql,Oracle,Where Clause,Operator Precedence,Analytic Functions,样本数据集 #Employee Id | Period | Status --------------------- 1 | 1 | L 1 | 2 | G 2 | 3 | L 我需要一个简单的select查询,仅当状态为“L”时,才能生成员工的最新记录(按期间) 结果如下所示: #Desired Results Id | Period | Status | Sequence ------------------------------- 2

样本数据集

#Employee
Id | Period | Status 
---------------------
1  |  1 |   L    
1  |  2 |   G    
2  |  3 |   L    
我需要一个简单的select查询,仅当状态为“L”时,才能生成员工的最新记录(按期间)

结果如下所示:

#Desired Results
Id | Period | Status | Sequence
-------------------------------
2  |  3     |   L    |   1
天真的企图 显然,我天真的查询尝试不起作用:

#select query
SELECT *, RANK() OVER (PARTITION BY id ORDER BY period ASC) sequence
FROM employees
WHERE   status = 'L' 
 AND    sequence = 1
其结果如下:

#Naive (incorrect) Results
ID | Period | Status | Sequence
-------------------------------
1  |  1 |   L    |   1
2  |  3 |   L    |   1
了解SQL中子句的求值顺序可以解释为什么它不起作用。以下是如何计算我的查询:

  • 隔离status='L'所在的行
  • 按行排列
  • 隔离顶级行
我希望:

#Naive (incorrect) Results
ID | Period | Status | Sequence
-------------------------------
1  |  1 |   L    |   1
2  |  3 |   L    |   1
  • 排成一行
  • 隔离排名靠前的行
  • 隔离status='L'所在的位置
问题
  • 只需对SELECT/WHERE子句进行简单修改并仅使用基本谓词运算符,就可以确保基于WHERE子句中分析函数的谓词在非聚合谓词之前得到求值吗

  • 是否有其他解决方案可以作为最终用户在Oracle Discoveryr Plus中实施

谢谢

是否可以在没有子查询的情况下执行此操作

从技术上讲,以下不是子查询,而是派生表

SELECT * 
FROM (
    SELECT *, 
           RANK() OVER (PARTITION BY id ORDER BY period ASC) sequence
    FROM employees
) t
WHERE status = 'L' 
  AND sequence = 1
我想不出一个不同的方法来解决你的问题。

经典的分组方式

SELECT e.id, e.period, e.status, 1 sequence
FROM
(
    SELECT id, min(period) period
    FROM employees
    GROUP BY id
) X
JOIN employees e on e.period=X.period and e.id=X.id
WHERE e.status = 'L'
存在

select e.id, e.period, e.status, 1 sequence
FROM employees e
WHERE e.status = 'L'
  AND NOT EXISTS (select *
                  from employees e2
                  where e2.id=e.id and e2.period>e.period)

我可能要做一个“多臂机”,把耳朵塞进烤箱门,然后用铁烫手

您可以创建一个计算当前行的函数。
请注意,这本质上是不可伸缩的。但我想总比什么都没有好

创建示例数据:

--drop table employee purge;

create table employee(
    id     number  not null
   ,period number  not null
   ,status char(1) not null
   ,constraint employee_pk primary key(id, period)
);

insert into employee(id,period, status) values(1, 1, 'L');
insert into employee(id,period, status) values(1, 2, 'G');
insert into employee(id,period, status) values(2, 3, 'L');

commit;
创建数据库中最慢的函数:

create or replace function i_am_slow(
    ip_id     employee.id%type
   ,ip_period employee.period%type
)
return varchar2
as
   l_count number := 0;
begin
    select count(*)
      into l_count
      from employee e
     where e.id     = ip_id
       and e.period = ip_period
       and e.status = 'L'
       and not exists(
            select 'x'
              from employee e2
             where e2.id = e.id
               and e2.period > e.period);

    if l_count = 1 then
        return 'Y';
    end if;

    return 'N';
end;
/
演示函数的用法:

select id, period, status
  from employee
 where i_am_slow(id, period) = 'Y';

        ID     PERIOD STATUS
---------- ---------- ------
         2          3 L

冲向烤箱……

如果没有派生表、子查询、联接或GROUP BY子句,这部分内容是无法理解的
所以你想烤一块没有面粉、牛奶或鸡蛋的蛋糕?为什么不想使用派生表或子查询?我有特殊的限制。我试图以最终用户的身份在Oracle Discoveryr Plus(一个GUI查询生成器)中实现此查询。在Discoverer中,我无权访问覆盖SQL或控制所有连接的EUL(“最终用户层”)。因此,我正在寻找一种解决方法。当面对此类工具时,我发现创建一个视图最容易,该视图将所需数据作为工具选择的简单对象。我同意Richard的观点-为此创建一个视图(在我的示例中基本上是派生表)谢谢Richard。不幸的是,我无法使用EXISTS谓词或GROUP BY。不幸的是,此解决方案无法在我的约束范围内工作。有关更多详细信息,请参阅更新的问题和问题评论。谢谢你跳出框框思考!然而,脾气暴躁的DBA并不是一个真正的约束。如果报告值得实现,则应创建视图。不要浪费公司的钱:)我认为说我在浪费公司的钱是不公平的。现在我意识到我所要求的是SQL中的一个非常糟糕的黑客,但可能是Discoveryr中的一个巧妙的解决方法,可以减少维护负载。然而,我对SQL的了解还不够,无法做到这一点。我将相应地编辑这篇文章,使之成为一篇面向发现者的文章。然而,我现在也意识到,我应该与我的DBA合作,提出一个最佳实践解决方案——而不是让Stack Overflow集体讨论解决我的模糊问题的方案。谢谢。@Bago,我重新阅读了我的评论,意识到这听起来很粗鲁,这不是我的本意。我很高兴你决定和你的DBA一起解决这个问题。你们两个会想出一个好办法的。我也发明了一些限制,当没有人可以节省文书工作/会议时,有时也是出于无知,但幸运的是,在我成为浪费金钱的人之前,我周围的人会戳我的眼睛;)