Цикл по значениям столбцов таблицы

#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
  

Demo

Комментарии:

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