4

バックグラウンド

サンプルデータセット

#Employee
Id | Period | Status 
---------------------
1  |  1 |   L    
1  |  2 |   G    
2  |  3 |   L    

status='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' の行を分離する
  • 行をランク付けする
  • 上位行を分離

私は次のものが欲しい:

  • 行をランク付けする
  • 上位にランク付けされた行を分離する
  • status='L' を分離する

質問

  • SELECT/WHERE 句を単純に変更し、基本的な述語演算子のみを使用するだけで、WHERE 句の分析関数に基づく述語が非集計述語よりも先に評価されるようにすることは可能ですか?

  • Oracle Discoverer Plusでエンドユーザーとして実装できる他のソリューションを持っている人はいますか?

ありがとう!

4

4 に答える 4

4

サブクエリなしでこれを行うことは可能ですか

技術的には、以下はサブクエリではなく派生テーブルです

SELECT * 
FROM (
    SELECT *, 
           RANK() OVER (PARTITION BY id ORDER BY period ASC) sequence
    FROM employees
) t
WHERE status = 'L' 
  AND sequence = 1

あなたの問題に対する別の解決策は考えられません。

于 2011-03-25T21:28:46.003 に答える
0

古典的なGroupby

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)
于 2011-03-25T22:04:57.100 に答える
0

私はおそらく「ドビー」をして、オーブンのドアに耳を叩きつけ、手にアイロンをかけなければならないでしょう...

現在の行を評価する関数を作成できます。
これは本質的に非スケーラブルであることに注意してください。でも何もないよりはいいと思います。

サンプル データを作成します。

--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

オーブンに向かって急いで...

于 2011-03-25T23:35:49.360 に答える