#sql #oracle
#sql #Oracle
Вопрос:
У меня есть таблица с историей изменений данных, которая выглядит как:
-------- ---------- ---------------
| id | key | value |
-------- ---------- ---------------
| UUID-1 | editedBy | moderator |
-------- ---------- ---------------
| UUID-1 | comments | deleted... |
-------- ---------- ---------------
| UUID-2 | editedBy | low_moderator |
-------- ---------- ---------------
| UUID-2 | comments | deleted... |
-------- ---------- ---------------
| UUID-3 | editedBy | admin |
-------- ---------- ---------------
| UUID-4 | editedBy | admin2 |
-------- ---------- ---------------
Теперь я хочу выбрать ключ-значение с помощью редактора и ключ-значение с помощью comments
(которое не совпадает с deleted...
), поэтому я сделал это таким образом.
with table1 as
(
SELECT
sch.rid,
sch.rkey,
sch.rvalue,
coalesce( (
SELECT
rvalue
FROM
test sch2
WHERE
sch.rid = sch2.rid
AND sch2.rkey = 'comments' ), ' ' ) AS comments
FROM
test sch
WHERE
rkey = 'editedBy'
)
SELECT
*
FROM
table1 t1
WHERE
t1.comments != 'deleted...'
и я получил желаемый результат
-------- ---------- -------- ----------
| id | key | value | comments |
-------- ---------- -------- ----------
| UUID-3 | editedBy | admin | |
-------- ---------- -------- ----------
| UUID-4 | editedBy | admin2 | |
-------- ---------- -------- ----------
Но мне кажется, что мой скрипт слишком сложный, и есть способы сделать это лучше, но я не могу найти их один.
Ответ №1:
Вы можете использовать NOT EXISTS
:
SELECT *
FROM test t
WHERE NOT EXISTS ( SELECT 0
FROM test
WHERE rkey = 'comments'
AND rvalue = 'deleted...'
AND rid = t.rid );
или, в качестве альтернативы, вы можете использовать такой метод, содержащий аналитическую функцию :
WITH t AS
(
SELECT t.*,
SUM(CASE WHEN rkey = 'comments' AND rvalue='deleted...'
THEN 1
ELSE 0
END) OVER (PARTITION BY rid) AS cnt
FROM test t
)
SELECT rid, rkey, rvalue
FROM t
WHERE cnt = 0;
Комментарии:
1. Вместо
SELECT 0...
мне нравится выбирать строку, которая описывает строку, которую я проверяю. Например,SELECT 'comment indicating ID is deleted'...
.
Ответ №2:
Ваше описание предполагает, что у вас есть только два ключа comments
и editedBy
в строках с одинаковым UUID и что первый является необязательным.
Поэтому просто используйте OUTER JOIN
и отфильтруйте строку, которую вы не хотите видеть (строки с комментарием)
select
ed.rid, ed.rkey, ed.rvalue
from table1 ed
left outer join table1 del
on ed.RID = del.RID and del.rkey = 'comments'
where ed.rkey = 'editedBy'
and del.rkey is NULL /* no comment */
Ответ №3:
Функции окна:
SELECT t.*
FROM (SELECT t.*,
MAX(comments) OVER (PARTITION BY rid) as comments
FROM test t
) t
WHERE t1.comments <> 'deleted...'
Комментарии:
1. не могу понять, как это может работать. в любом случае, ORA-00904: «КОММЕНТАРИИ»: недопустимый идентификатор. моя скрипка — sqlfiddle.com /#!4/c7a87/3/0