#sql #oracle #plsql #oracle11g
#sql #Oracle #plsql #oracle11g
Вопрос:
Я новичок в PL-SQL. У меня есть таблица, которая содержит тысячи записей о файловой информации (извлечение показано ниже) .Мне нужно сравнить для 2 файлов A и B, для одной и той же задачи, чтобы проверить, совпадает ли имя_задачи или отличается. Например, в приведенной ниже таблице файл A task 10 имеет то же имя task_name (xx), что и файл B task 10. в то время как файл A task 20 имеет другое имя task_name, чем файл B task 20. Я должен быть в состоянии отметить эти различия и сходства. Я хотел бы использовать курсор внутри курсора для цикла и сравнения этих значений, но я не знаю, как это сделать. В настоящее время я использую oracle 11. Спасибо
File Task Task_name
A 10 xx
A 20 xy
A 30 xz
B 10 xx
B 20 xz
**редактировать
Спасибо за ответ. Причина, по которой мне понадобился цикл, заключается в том, что в конце мне нужно отобразить результаты в переменной clob в формате ниже. Итак, мне нужно зафиксировать на итерации номер задачи и ее имя для отображения в переменной clob
——-сравнение файлов——-
Другое имя_задачи
Задача 20: Файл A с именем задачи xx и файл B с именем задачи xz
Задача 30: Файл A с именем задачи xz против файла B с именем задачи NULL
То же самое имя_задачи
Задача 10: Имя_задачи xx
Комментарии:
1. Каков ваш ожидаемый результат?
2. Предполагается ли, что данная задача (скажем, 10) имеет согласованное имя_задачи (скажем, ‘xx’). Если это так, то ваша модель данных в корне ошибочна. В вашей таблице должны быть только ФАЙЛ и задача. Тогда у вас была бы отдельная «таблица поиска», чтобы связать задачу (более правильно TASK_ID) с TASK_NAME.
3. я отредактировал свой вопрос, чтобы показать результат. Спасибо
Ответ №1:
Вам не нужно использовать PL / SQL, но достаточно использовать SQL с COUNT(..) OVER (..)
аналитической функцией, сгруппированной по столбцам Task
и Task_name
с помощью PARTITION BY
предложения вместе с CASE..WHEN
условным выражением, например
SELECT f.*,
CASE WHEN COUNT(DISTINCT "File") OVER (PARTITION BY Task, Task_name) = 2 THEN
'Same'
ELSE CASE WHEN COUNT(DISTINCT "File") OVER (PARTITION BY Task) = 1 THEN
'Unique'
ELSE
'Different'
END
END AS flag
FROM files f
Комментарии:
1. Спасибо за ответ. Причина, по которой мне понадобился цикл, заключается в том, что в конце мне нужно отобразить результаты в переменной clob в формате ниже. Итак, мне нужно записать на итерации задачу и имя задачи для отображения в переменной clob ——сравнение файлов—— Другое имя_задачи Задача 20: Файл имя_задачи xx против файла B имя_задачи xz Задача 30: Файл имя_задачи xz против файла B Имя_задачи NULL То же имя_задачи Задача 10: имя_задачи xx
Ответ №2:
Вы можете агрегировать по задачам, чтобы получить различия:
select
task,
max(case when file = 'A' then task_name end) as task_file_a,
max(case when file = 'B' then task_name end) as task_file_b
from mytable
where file in ('A', 'B')
group by task
having count(*) <> 2 or count(distinct task_name) <> 1
order by task;
Вы можете использовать это внутри PL / SQL с Cursor FOR LOOP
. Вот черновик:
create or replace function get_diff return clob is
v_clob clob;
begin
for row in
(
select
task,
max(case when file = 'A' then task_name end) as task_file_a,
max(case when file = 'B' then task_name end) as task_file_b,
case when count(*) <> 2 or count(distinct task_name) <> 1
then 'diff'
else 'same'
end as diff_same
from mytable
where file in ('A', 'B')
group by task
order by diff_same, task
) loop
v_clob := v_clob ...
end loop;
end;
Вы можете получить доступ к данным строки следующим образом: 'Task for file A is' || row.task_file_a
.
Вам нужно будет проверить same / diff, или вы просто используете два цикла, один для различий, другой для равенств.
Комментарии:
1. Спасибо за ответ. Не могли бы вы объяснить, что эта строка кода делает в вашем запросе: имея count(*) <> 2 или count(отличное имя_задачи) <> 2
2. О, извините, это неправильно. Предполагается, что он обнаруживает разницу. Но это должно быть
having count(*) <> 2 or count(distinct task_name) <> 1
. Если для задачи вы не нашли две строки (count(*) <> 2
, либо A, либо B отсутствуют. Если для задачи вы найдете более одного имени задачи (count(distinct task_name) <> 1
), то имена задач для A и B различны. Я обновил свой ответ.
Ответ №3:
with t (Files, Task, Task_name ) as
(
select 'A',10,'xx' from dual union all
select 'A',20,'xy' from dual union all
select 'A',30,'xz' from dual union all
select 'B',10,'xx' from dual union all
select 'B',20,'xz' from dual
)
select t1.*, nvl((select 'Y' from t t2 where t2.files <> t1.files and t2.task = t1.task and t2.task_name = t1.task_name),'N') as is_same
from t t1
order by 1, 2
Вывод:
Ответ №4:
Вы также можете использовать operator EXISTS
.Оператор EXISTS используется с подзапросом для проверки наличия строк.
Хотя в вашем вопросе нет упоминания о дубликате в A / B, вы можете использовать универсальный запрос для поиска дубликатов в одной группе или разных/
Также обратите внимание на то, что этот запрос возвращает правильный результат в случае, когда дублируется только в пределах одной файловой группы (например, только в A):
--using cte to set row's number
with cte as
(
select *, row_number()over (order by Task,TaskName)num from Table
)
select File,Task,TaskName,
case
--using t1.num<>t2.num because current row can refer to itself
when exists (select 1 from cte t1 where t1.Task=t2.Task and
t1.Taskname=t2.TaskName and t1.num<>t2.num)
then 'Duplicate'
else
'No Duplicate'
end as flag
from cte t2
Если в вашей таблице нет дубликатов в пределах одной файловой группы, и вам нужно найти разницу только между группами файлов A и B, тогда вы можете использовать этот запрос:
select File,Task,TaskName,
case
when exists (select 1 from Table t1 where t1.Task=t2.Task and
t1.Taskname=t2.TaskName and t1.File<>t2.File)
then 'Duplicate'
else
'No Duplicate'
end as flag
from Table t2
Вы можете использовать window function count
для подсчета задач, TaskName в файловой группе.Но сначала вам нужно удалить дубликаты внутри каждой группы, а затем посчитать значения, как если бы они были в одной группе.
Если вам нужно сравнить для 2 файлов A и B, вы можете попробовать этот запрос:
Select File, Task,TaskNane,case when countVal>1 then 'Duplicate' else 'No
Duplicate' and as flag
From
(
Select count(*)over (partition by file_gr, Task, TaskName) countVal
From
(
--add new accessorial column as if there's one group
Select *, case when File='B' then 'A' else 'A' end as file_gr
From
(
--remove duplicate within each group A and B
Select distinct File, Task, TaskName from Table
) X
) Y
) Z