2011-12-08 15 views
2

私はOracle 10gを使用しています。私はさまざまな種類のフィールドの数を持つテーブルを持っています。これらのフィールドには、特定のサイトで特定の日付に特定のことが行われたことによる観測結果が含まれています。SQL - 不完全結合

ので:

ItemID, Date, Observation1, Observation2, Observation3... 

各レコードには約40の観察があります。この時点でテーブル構造を変更することはできません。

残念ながら、すべての観測に(偶然に、またはサイトがその記録を作成できないために)入力されているわけではありません。私は、特定の項目に関するすべてのレコードをクエリの単一のレコードに結合し、できるだけ完全なものにする必要があります。これを行うには

簡単な方法は、

SELECT 
    ItemID, 
    MAX(Date), 
    MAX(Observation1), 
    MAX(Observation2) 
    etc. 
FROM 
    Table 
GROUP BY 
    ItemID 

ようなものになるだろう。しかし、理想的に私はそれが最大/最小値、利用可能な最新の観測をしませ選ぶしたいと思います。私は、フォーム

SELECT 
    ItemID, 
    ObservationX, 
    ROW_NUMBER() OVER (PARTITION BY ItemID ORDER BY Date DESC) ROWNUMBER 
FROM 
    Table 
WHERE 
    ObservationX IS NOT NULL 

にサブクエリを書き込み、アイテムIDのためではなく、このためには、40のサブクエリを必要とするフィールドの数をすべて一緒ROWNUMBERの1秒に参加することによってこれを行うことができます。

私の質問は、これを行うためのより簡潔な方法がないかどうかです。

答えて

3

は、テーブルとサンプル日付

SQL> create table observation(
    2 item_id number, 
    3 dt  date, 
    4 val1 number, 
    5 val2 number); 

Table created. 

SQL> insert into observation values(1, date '2011-12-01', 1, null); 

1 row created. 

SQL> insert into observation values(1, date '2011-12-02', null, 2); 

1 row created. 

SQL> insert into observation values(1, date '2011-12-03', 3, null); 

1 row created. 

SQL> insert into observation values(2, date '2011-12-01', 4, null); 

1 row created. 

SQL> insert into observation values(2, date '2011-12-02', 5, 6); 

1 row created. 

を作成し、最後にNULL観察と行を置くORDER BYMAX集計関数にKEEP句を使用します。 ORDER BYで使用している日付は、テーブルの中で最も早い時期に観察する必要があります。

SQL> ed 
Wrote file afiedt.buf 

    1 select item_id, 
    2   max(val1) keep(dense_rank last 
    3        order by (case when val1 is not null 
    4            then dt 
    5            else date '1900-01-01' 
    6           end)) val1, 
    7   max(val2) keep(dense_rank last 
    8        order by (case when val2 is not null 
    9            then dt 
10            else date '1900-01-01' 
11           end)) val2 
12 from observation 
13* group by item_id 
SQL>/

    ITEM_ID  VAL1  VAL2 
---------- ---------- ---------- 
     1   3   2 
     2   5   6 

は私がORDER BYからCASE文を追加するよりも、NULL値を無視するように、よりエレガントな解決策があると思われるが、CASEは仕事を取得します。

+0

+1、素敵です。よりコンパクトなソリューションのために、NVL2(val1、dt、date '1900-01-01')だけで注文できますか? – DCookie

+0

@DCookie - それはよりコンパクトになるでしょう。しかし、NVL2を見るとすぐに私は一時停止します。なぜなら、NVL2の動作をすぐに覚えていないからです。私は、 'last_value'解析関数の' ignore nulls'節のようなものがありますが、集約関数の中にあることを期待しています。 –

+0

本当にありがとうございます。 – George

0

私は、Oracleのコマンドについて知らないが、SQLにあなたはその

最初に使用するピボットテーブルはconsecutives番号0,1,2が含まれているか、いくつかを使用することができます...

私はよく分からないが、Oracleに機能 "ISNULLは" "NVL" である

select items.ItemId, 
    case p.i = 0 then observation1 else '' end as observation1, 
    case p.i = 0 then observation1 else '' end as observation2, 
    case p.i = 0 then observation1 else '' end as observation3, 
    ... 
    case p.i = 39 then observation4 else '' as observation40 
    from (
    select items.ItemId 
    from table as items 
    where items.item = _paramerter_for_retrive_only_one_item /* select one item o more item where you filter items here*/ 
    group by items.ItemId) itemgroup 
    left join 
    (
     select 
     items.ItemId, 
     p.i, 
     isnull( max ( case p.i = 0 then observation1 else '' end), '') as observation1, 
     isnull( max ( case p.i = 1 then observation2 else '' end), '') as observation2, 
     isnull( max ( case p.i = 2 then observation3 else '' end), '') as observation3, 
     ... 
     isnull( max ( case p.i = 39 then observation4), '') as observation40, 
     from 
     (select i from pivot where id < 40 /*you number of columns of observations, that attach one index*/ 
     ) 
     as p 
     cross join table as items 

     lef join table as itemcombinations 
     on item.itemid = itemcombinations.itemid 

     where items.item = _paramerter_for_retrive_only_one_item /* select one item o more item where you filter items here*/ 
     and (p.i = 0 and not itemcombinations.observation1 is null) /* column 1 */ 
     and (p.i = 1 and not itemcombinations.observation2 is null) /* column 2 */ 
     and (p.i = 2 and not itemcombinations.observation3 is null) /* column 3 */ 
     .... 
     and (p.i = 39 and not itemcombinations.observation3 is null) /* column 39 */ 
     group by p.i, items.ItemId 
    ) as itemsimplified 
    on itemsimplified.ItemId = itemgroup.itemId 

    group by itemgroup.itemId 

ピボットテーブルについて

ピボットテーブルを作成し、その

ピボットを見てみましょうテーブルスキーマ

名前:ピボット列:{i:データ型int}

create foo table 

schema foo 

name: foo column: value datatype varchar 

insert into foo 
values('0'), 
values('1'), 
values('2'), 
values('3'), 
values('4'), 
values('5'), 
values('6'), 
values('7'), 
values('8'), 
values('9'); 

/* insert 100 values */ 
insert into pivot 
select concat(a.value, a.value) /* mysql */ 
    a.value + a.value /* sql server */ 
    a.value | a.value /* Oracle im not sure about that sintax */ 
from foo a, foo b 

/* insert 1000 values */ 
insert into pivot 
select concat(a.value, b.value, c.value) /* mysql */ 
a.value + b.value + c.value /* sql server */ 
a.value | b.value | c.value /* Oracle im not sure about that sintax */ 
from foo a, foo b, foo c 
ピボットテーブルについての考えは、私が(ジャスティン洞窟による)上記溶液が単純であることを認めざるを得ない

「ジョナサンGennick、アレスSpeticことでのTransact-SQLクックブック」に相談することができ

とを読み込む方法3210理解しやすいですがこれは別の良いオプションです

最後にあなたが解決したと言ったように