SQL - объединение неполного - PullRequest
2 голосов
/ 08 декабря 2011

Я использую Oracle 10g.У меня есть таблица с несколькими полями различных типов.Поля содержат наблюдения, которые были сделаны по конкретной вещи в определенную дату конкретным сайтом.

Итак:

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

В каждой записи содержится около 40 наблюдений.Структура таблицы не может быть изменена в данный момент.

К сожалению, не все Наблюдения были заполнены (случайно или из-за того, что сайт не может сделать эту запись).Мне нужно объединить все записи о конкретном элементе в одну запись в запросе, сделав ее максимально полной.

Простой способ сделать это будет выглядеть примерно так:

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

Но в идеале я бы хотел выбрать самое последнее доступное наблюдение, а не значение max / min.Я мог бы сделать это, написав подзапросы в форме

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

И соединив все ROWNUMBER 1 вместе для ItemID, но из-за количества полей для этого потребуется 40 подзапросов.

Myвопрос в том, есть ли более короткий способ сделать это, что я упускаю.

Ответы [ 2 ]

3 голосов
/ 08 декабря 2011

Создать таблицу и дату выборки

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.

А затем используйте предложение KEEP в агрегатной функции MAX с ORDER BY, который ставит строки с NULL-наблюдениями в конце. любая дата, которую вы используете в 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

Я подозреваю, что есть более элегантное решение игнорировать значения NULL, чем добавление оператора CASE к ORDER BY, но CASE выполняет свою работу.

0 голосов
/ 08 декабря 2011

Я не знаю о командах в Oracle, но в SQL вы могли бы использовать некоторые, как это

сводная таблица первого использования содержит последовательные числа 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: datatype 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 

идею о сводной таблице можно найти в «Поваренной книге Transact-SQL» ДжонатанаGennick, Ales Spetic "

Я должен признать, что вышеприведенное решение (Джастин Кейв) проще и проще для понимания, но это еще один хороший вариант

в конце, как вы сказали, что вы решили

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...