Как найти повторяющиеся данные с отметкой времени - PullRequest
1 голос
/ 17 ноября 2011

У меня есть следующая таблица:

create table issue_attributes (
  issue_id number,
  attr_timestamp timestamp,
  attribute_name varchar2(500),
  attribute_value varchar2(500),
  CONSTRAINT ia-pk PRIMARY KEY (issue_id, attr_timestamp, attribute_name)
)

Идея заключается в том, чтобы связать с проблемой несколько атрибутов (статус, владелец и т. Д.), Сохраняя при этом возможность сохранять историюизменения атрибутов.

Из-за ошибок в импорте данных мы повторили данные в таблице:

select issue_id, attr_timestamp, attribute_name, attribute_value
from issue_attributes where issue_id = 1 and attribute_name = 'OWNER';

дает пример данных:

1, 01-JAN-2011 12:00, 'OWNER', 'john.doe@example.com'
1, 01-FEB-2011 12:00, 'OWNER', 'john.doe@example.com'
1, 01-MAR-2011 12:00, 'OWNER', 'john.doe@example.com'
1, 01-APR-2011 12:00, 'OWNER', 'john.doe@example.com'

Я хотел бычтобы можно было найти все экземпляры повторяющихся атрибутов и просто сохранить последний.Желаемый набор результатов в этом случае данных выборки будет:

1, 01-JAN-2011 12:00, 'OWNER', 'john.doe@example.com'

Мы также можем иметь случай данных выборки:

2, 01-JAN-2011 12:00, 'OWNER', 'john.doe@example.com'
2, 01-FEB-2011 12:00, 'OWNER', 'jane.deere@example.com'
2, 01-MAR-2011 12:00, 'OWNER', 'john.doe@example.com'
2, 01-APR-2011 12:00, 'OWNER', 'john.doe@example.com'

, в этом случае я бы хотелчтобы получить результат:

2, 01-JAN-2011 12:00, 'OWNER', 'john.doe@example.com'
2, 01-FEB-2011 12:00, 'OWNER', 'jane.deere@example.com'
2, 01-MAR-2011 12:00, 'OWNER', 'john.doe@example.com'

Это на Oracle 11g, поэтому я мог бы использовать SQL или PL / SQL для исправления данных.Я думал, что один из способов сделать это - через PL / SQL, и для каждого значения__пуска сортировать атрибуты по убыванию, а если атрибут (х) = атрибут (х-1), то удалить атрибут (х).Это похоже на грубую силу, и мне было интересно, если бы был элегантный способ сделать это только с помощью SQL.

Ответы [ 4 ]

1 голос
/ 17 ноября 2011

Я бы посмотрел на предыдущую строку и увидел, изменились ли данные.Это можно сделать с помощью аналитической функции LAG.

Вы можете вернуться к предыдущему значению, упорядочив его по отметке времени.Если данные изменились, то вы хотите сохранить их.Первая строка всегда сохраняется, поскольку LAG возвращает NULL при отсутствии предыдущих данных.

with issue_attributes as (
  select 1 as issue_id, date '2011-01-01' as attr_timestamp, 
    'OWNER' as attribute_name, 'john.doe@example.com' as attribute_value from dual union all
  select 1 as issue_id, date '2011-02-01' as attr_timestamp, 
    'OWNER' as attribute_name, 'john.doe@example.com' as attribute_value from dual union all
  select 1 as issue_id, date '2011-03-01' as attr_timestamp, 
    'OWNER' as attribute_name, 'john.doe@example.com' as attribute_value from dual union all
  select 1 as issue_id, date '2011-04-01' as attr_timestamp, 
    'OWNER' as attribute_name, 'john.doe@example.com' as attribute_value from dual union all
  select 2 as issue_id, date '2011-01-01' as attr_timestamp, 
    'OWNER' as attribute_name, 'john.doe@example.com' as attribute_value from dual union all
  select 2 as issue_id, date '2011-02-01' as attr_timestamp, 
    'OWNER' as attribute_name, 'jane.deere@example.com' as attribute_value from dual union all
  select 2 as issue_id, date '2011-03-01' as attr_timestamp, 
    'OWNER' as attribute_name, 'john.doe@example.com' as attribute_value from dual union all
  select 2 as issue_id, date '2011-04-01' as attr_timestamp, 
    'OWNER' as attribute_name, 'john.doe@example.com' as attribute_value from dual 
)
select 
  issue_id, 
  attr_timestamp, 
  attribute_name, 
  attribute_value,
  case when lag(attribute_value) over (partition by issue_id, attribute_name order by attr_timestamp) = attribute_value then null else 'Y'end as keep_value
from 
  issue_attributes

Это добавит дополнительный столбец, чтобы указать, нужно ли сохранять данные или нет, что выможет затем отфильтровать:

ISSUE_ID ATTR_TIMESTAMP ATTRIBUTE_NAME ATTRIBUTE_VALUE        KEEP_VALUE
1        01/01/2011     OWNER          john.doe@example.com   Y
1        01/02/2011     OWNER          john.doe@example.com 
1        01/03/2011     OWNER          john.doe@example.com 
1        01/04/2011     OWNER          john.doe@example.com 
2        01/01/2011     OWNER          john.doe@example.com   Y
2        01/02/2011     OWNER          jane.deere@example.com Y
2        01/03/2011     OWNER          john.doe@example.com   Y
2        01/04/2011     OWNER          john.doe@example.com 
1 голос
/ 17 ноября 2011

Вот хороший способ "Oracle" сделать это.

Использование данных вашего образца:

SQL> desc issue_attributes
 Name                                                              Null?    Type
 ----------------------------------------------------------------- -------- --------------------------------------------
 ISSUE_ID                                                                   NUMBER
 ATTR_TIMESTAMP                                                             TIMESTAMP(6)
 ATTRIBUTE_NAME                                                             VARCHAR2(500)
 ATTRIBUTE_VALUE                                                            VARCHAR2(500)

SQL> select * from issue_attributes;

  ISSUE_ID ATTR_TIMESTAMP                      ATTRIBUTE_ ATTRIBUTE_VALUE
---------- ----------------------------------- ---------- ------------------------------
         1 01-JAN-20 11.12.00.000000 AM        OWNER      john.doe@example.com
         1 01-FEB-20 11.12.00.000000 AM        OWNER      john.doe@example.com
         1 01-MAR-20 11.12.00.000000 AM        OWNER      john.doe@example.com
         1 01-APR-20 11.12.00.000000 AM        OWNER      john.doe@example.com
         1 01-JAN-20 11.12.00.000000 AM        OWNER      john.doe@example.com
         1 01-JAN-20 11.12.00.000000 AM        OWNER      john.doe@example.com
         1 01-FEB-20 11.12.00.000000 AM        OWNER      jane.deere@example.com
         1 01-MAR-20 11.12.00.000000 AM        OWNER      john.doe@example.com
         1 01-APR-20 11.12.00.000000 AM        OWNER      john.doe@example.com
         1 01-JAN-20 11.12.00.000000 AM        OWNER      john.doe@example.com
         1 01-FEB-20 11.12.00.000000 AM        OWNER      jane.deere@example.com
         1 01-MAR-20 11.12.00.000000 AM        OWNER      john.doe@example.com

12 rows selected.

SQL> delete from issue_attributes
        where rowid in(select rid
                         from (select rowid rid,
                                      row_number() over (partition by ISSUE_ID,
                                                                      ATTR_TIMESTAMP,
                                                                      ATTRIBUTE_NAME,
                                                                      ATTRIBUTE_VALUE
                                                             order by rowid) rn
                                from issue_attributes)
                        where rn<> 1);
7 rows deleted.

SQL> select * from issue_attributes;

  ISSUE_ID ATTR_TIMESTAMP              ATTRIBUTE_ ATTRIBUTE_VALUE
---------- ----------------------------------- ---------- ------------------------------
         1 01-JAN-20 11.12.00.000000 AM        OWNER      john.doe@example.com
         1 01-FEB-20 11.12.00.000000 AM        OWNER      john.doe@example.com
         1 01-MAR-20 11.12.00.000000 AM        OWNER      john.doe@example.com
         1 01-APR-20 11.12.00.000000 AM        OWNER      john.doe@example.com
         1 01-FEB-20 11.12.00.000000 AM        OWNER      jane.deere@example.com

5 rows selected.

Надеюсь, это поможет.

0 голосов
/ 17 ноября 2011

То, что вы хотите обнаружить, это: кортежи с тем же {issueid, attributetename, attributevalue}, но (при заказе по метке времени) no промежуточные кортежи с тем же {issueid, attributetename}, но другим { AttributeValue}.

Это можно записать как запрос с одним подзапросом EXISTS и одним подзапросом NOT EXISTS.

ОБНОВЛЕНИЕ:

SET search_path='tmp';

-- The rows you want to delete.
SELECT * FROM issue_attributes to_del
WHERE EXISTS (
    SELECT * FROM issue_attributes xx
    WHERE xx.issue_id = to_del.issue_id
    AND xx.attribute_name = to_del.attribute_name
    AND xx.attribute_value = to_del.attribute_value
    AND xx.attr_timestamp > to_del.attr_timestamp
    AND NOT EXISTS ( SELECT * FROM issue_attributes nx
        WHERE nx.issue_id = to_del.issue_id
        AND nx.attribute_name = to_del.attribute_name
        AND nx.attribute_value <> to_del.attribute_value
        AND nx.attr_timestamp > to_del.attr_timestamp
        AND nx.attr_timestamp < xx.attr_timestamp
        )   
    ) ;

-- For completeness: the rows you want to keep.
SELECT * FROM issue_attributes must_stay
WHERE NOT EXISTS (
    SELECT * FROM issue_attributes xx
    WHERE xx.issue_id = must_stay.issue_id
    AND xx.attribute_name = must_stay.attribute_name
    AND xx.attribute_value = must_stay.attribute_value
    AND xx.attr_timestamp > must_stay.attr_timestamp
    AND NOT EXISTS ( SELECT * FROM issue_attributes nx
        WHERE nx.issue_id = must_stay.issue_id
        AND nx.attribute_name = must_stay.attribute_name
        AND nx.attribute_value <> must_stay.attribute_value
        AND nx.attr_timestamp > must_stay.attr_timestamp
        AND nx.attr_timestamp < xx.attr_timestamp
        )
    ) ;

Результат:

 issue_id |   attr_timestamp    | attribute_name |   attribute_value    
----------+---------------------+----------------+----------------------
        1 | 2011-03-01 12:00:00 | OWNER          | john.doe@example.com
        1 | 2011-01-01 12:00:00 | OWNER          | john.doe@example.com
        1 | 2011-02-01 12:00:00 | OWNER          | john.doe@example.com
        2 | 2011-03-01 12:00:00 | OWNER          | john.doe@example.com
(4 rows)

 issue_id |   attr_timestamp    | attribute_name |    attribute_value     
----------+---------------------+----------------+------------------------
        1 | 2011-04-01 12:00:00 | OWNER          | john.doe@example.com
        2 | 2011-02-01 12:00:00 | OWNER          | jane.deere@example.com
        2 | 2011-04-01 12:00:00 | OWNER          | john.doe@example.com
        2 | 2011-01-01 12:00:00 | OWNER          | john.doe@example.com
(4 rows)
0 голосов
/ 17 ноября 2011

Я не знаю об Oracle в частности, но что-то вроде

SELECT MAX(attr_timestamp), issue_id, attribute_name, attribute_value
FROM issue_attributes
GROUP BY issue_id, attribute_name, attribute_value

выдаст список, где появляется каждая отдельная тройка issue_id, attribute_name, attribute_value вместе с самой последней отметкой времени в ряде СУБД. Может стоит попробовать.

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