Как сравнить две таблицы сотрудников по столбцам в оракуле для каждого сотрудника

Мне нужно сравнить данные в двух таблицах сотрудников Oracle по столбцам и создать такой отчет (сравните Ato B)

Таблица А

+-------+------+---------+
|emp_num| name | a_city  |
+-------+------+---------+  
|  1    | Jo   | Lay     |
|  2    | Paul | Dubai   |
+-------+------+---------+ 

Таблица Б

+-------+------+---------+
|emp_num| name | a_city  |
+-------+------+---------+  
|  1    | Jo   | Sydney  |
+-------+------+---------+ 

После сравнения данных в выводах A и B, как показано ниже.

+----------+----------+-----------+---------------+----------+---------+------------+-------+-------+-------------+
| status   | a_emp_num| b_emp_num | emp_num_match | a_city   | b_city  | city_match | a_name| b_name|  name_match |
+----------+----------+-----------+---------------+----------+---------+------------+-------+-------+-------------+  
| Found    |  1       |  1        |   Matched     |  Lay     |   Lay   | Matched    |  Jo   |   Jo  |  Matched    |
| Not Found|  2       |           |   Not Matched |  Dubai   |         | Not Matched|  Paul |       |  Not Matched|
+----------+----------+-----------+---------------+----------+---------+------------+-------+-------+-------------+  

У меня есть запрос, созданный для сравнения этого

SELECT (CASE
         WHEN A.EMP_NUM IS NULL THEN
          'Found'
         ELSE
          'Not Found'
       END) AS STATUS,
       
       A.EMP_NUM A_EMP_NUM,
       B.EMP_NUM B_EMP_NUM,
       
       (CASE
         WHEN NVL(TRIM(B.EMP_NUM), 0) = NVL(TRIM(B.EMP_NUM), 0) THEN
          'Found'
         ELSE
          'Not Found'
       END) AS EMP_NUM_MATCH
  FROM A, B
 WHERE A.EMP_NUM = B.EMP_NUM(+)

теперь проблема в том, что мне нужно написать оператор case для многих атрибутов, таких как ИМЯ, ВОЗРАСТ, ГОРОД (в реальном случае 400+ атрибутов)

Есть ли способ автоматически создать этот оператор выбора, если мы передадим список столбцов в качестве входных данных? или любой способ сделать это сравнение для всех столбцов в excel без явного написания выбора для каждого из столбцов

ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
1
0
118
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Вы можете использовать LEFT JOIN следующим образом:

select CASE WHEN B.EMP_NUM is NOT null THEN 'Found' ELSE 'Not Found' END AS STATUS,
       A.EMP_NUM A_EMP_NUM,
       B.EMP_NUM B_EMP_NUM,
       CASE WHEN B.EMP_NUM is NOT null THEN 'Match' ELSE 'Mismatch' END AS EMP_NUM_MATCH,
       A.CITY AS A_CITY,
       B.CITY AS B_CITY,
       CASE WHEN A.CITY = B.CITY THEN 'Match' ELSE 'Mismatch' END AS CITY_MATCH,
       A.NAME AS A_NAME,
       B.NAME AS B_NAME,
       CASE WHEN A.NAME = B.NAME THEN 'Match' ELSE 'Mismatch' END AS NAME_MATCH
  from A LEFT JOIN B ON A.EMP_NUM =B.EMP_NUM

Привет. Мой оператор выбора работает нормально... но проблема в том, что у меня есть более 300 столбцов, и столбцы будут меняться, и мне очень сложно написать оператор case для каждого столбца, есть ли способ создать запрос выбора для всех столбцов в таблице или сделать оператор case для всех столбцов в таблице

Vishnu Sajeevan 10.12.2020 10:02

Вы можете использовать USER_TAB_COLS и создать выражения запроса SELECT - CASE WHEN B.EMP_NUM is NOT null THEN 'Found' ELSE 'Not Found' END AS STATUS, A.EMP_NUM A_EMP_NUM, B.EMP_NUM B_EMP_NUM для каждого столбца.

Popeye 10.12.2020 10:10

как включить USER_TAB_COLS в sql, извините, я не уверен в этом

Vishnu Sajeevan 10.12.2020 10:23

Вы не можете добавить USER_TAB_COLS в этот запрос, но вы можете использовать следующий запрос для создания исходного запроса: SELECT 'CASE WHEN B.' || COLUMN_NAME ||' is NOT null THEN ''Match'' ELSE ''Mismatch'' END AS ' || COLUMN_NAME ||'_MATCH, A.' || COLUMN_NAME ||' AS ' || COLUMN_NAME ||', B.' || COLUMN_NAME ||' AS ' || COLUMN_NAME ||',' FROM USER_TAB_COLS WHERE TABLE_NAME = 'YOUR_A_TABLE_NAME' ORDER BY COLUMN_ID; Вы должны скопировать и вставить каждую строку и использовать ее в своем запросе.

Popeye 10.12.2020 10:29
Ответ принят как подходящий

Напишите запрос, который напишет запрос для вас. Что-то вроде этого:

DECLARE
   l_str  VARCHAR2 (4000) := 'select ';
BEGIN
   FOR cr IN (  SELECT a.column_name cn
                  FROM user_tab_columns a
                 WHERE a.table_name = 'TABLE_A'
              ORDER BY column_id)
   LOOP
      l_str :=
            l_str
         || 'a.'
         || cr.cn
         || ', b.'
         || cr.cn
         || ', '
         || 'case when nvl(trim(a.'
         || cr.cn
         || '), 0) = nvl  ( trim    ( b . '
         || cr.cn
         || '), 0) then ''match'' else ''mismatch'' end '
         || cr.cn
         || ',';
   END LOOP;

   l_str :=
         RTRIM (l_str, ',')
      || ' from table_a a left join table_b b on a . empno = b . empno ';
   DBMS_OUTPUT.put_line (l_str);
END;
/

Результатом является утверждение SELECT; Я отформатировал его так, чтобы его было легче читать:

SELECT a.EMPNO,
       b.EMPNO,
       CASE
          WHEN NVL (TRIM (a.EMPNO), 0) = NVL (TRIM (b.EMPNO), 0) THEN 'match'
          ELSE 'mismatch'
       END EMPNO,
       a.NAME,
       b.NAME,
       CASE
          WHEN NVL (TRIM (a.NAME), 0) = NVL (TRIM (b.NAME), 0) THEN 'match'
          ELSE 'mismatch'
       END NAME,
       a.CITY,
       b.CITY,
       CASE
          WHEN NVL (TRIM (a.CITY), 0) = NVL (TRIM (b.CITY), 0) THEN 'match'
          ELSE 'mismatch'
       END CITY
  FROM table_a a LEFT JOIN table_b b ON a.empno = b.empno

который - при выполнении - возвращает

     EMPNO      EMPNO EMPNO    NAME NA NAME     CITY  CITY   CITY
---------- ---------- -------- ---- -- -------- ----- ------ --------
         1          1 match    Jo   Jo match    Lay   Sydney mismatch
         2            mismatch Paul    mismatch Dubai        mismatch

Теперь, когда вы знаете «как», сделайте его красивее.

Функции полного соединения и декодирования отлично работают вместе для всех случаев несоответствия в обеих таблицах, поскольку декодирование декодирования хорошо справляется с нулевыми значениями.

select 
  decode(a.empno, b.empno, 'Found', 'NotFound') status
, a.empno "A.EMPNO", b.empno "B.EMPNO"
, decode(a.empno, b.empno, 'Match', 'Mismatch') "EMP_NUM.MATCH"
, a.city "a.CITY", b.city "B.CITY"
, decode(a.city, b.city, 'Match', 'Mismatch') "CITY.MATCH"
, a.name "A.NAME", b.name "B.NAME"
, decode(a.name, b.name, 'Match', 'Mismatch')"NAME.MATCH"
from tableA a
full join tableB b on (a.empno = b.empno)
;

Одним из вариантов динамического поворота ваших данных будет создание функции с использованием функций XMLELEMENT(), XMLAGG() и NVL2() вместе для создания оператора SELECT, такого как

CREATE OR REPLACE FUNCTION get_city_people_info RETURN SYS_REFCURSOR IS
  v_recordset SYS_REFCURSOR;
  v_sql       VARCHAR2(32767);
  v_str       VARCHAR2(32767);
BEGIN
  SELECT RTRIM(DBMS_XMLGEN.CONVERT(
                 XMLAGG( 
                         XMLELEMENT(e,'A.'||column_name||' AS  "a_'||column_name||'",
                                       B.'||column_name||' AS  "b_'||column_name||'", 
                                       DECODE( NVL2(A.'||column_name||',TRIM(A.'||column_name||'),'' ''),
                                               NVL2(B.'||column_name||',TRIM(B.'||column_name||'),'' ''),
                                               ''Matched'',''Not Matched'' ) AS "'||column_name||'_match",')
                        ).EXTRACT('//text()').GETCLOBVAL() ,1),',')
    INTO v_str                    
    FROM 
    (
     SELECT DISTINCT LOWER(c.column_name) AS column_name
       FROM user_tab_cols c
      WHERE c.table_name = 'A' -- considering both tables(A and B) have exactly common columns 
    ); 

  v_sql :=
  'SELECT NVL2(B.emp_num , ''Found'', ''Not Found'') AS "status",'|| v_str ||'
     FROM A
     LEFT JOIN B
       ON B.emp_num = A.emp_num';

  OPEN v_recordset FOR v_sql;
  RETURN v_recordset;
END;
/

который даст тип возвращаемого значения SYS_REFCURSOR, затем вызовите

VAR rc REFCURSOR
EXEC :rc := get_city_people_info;
PRINT rc

из командной строки SQL Developer.

Demo with generated SELECT Statement Within The Function

P.S: Предпочитайте использовать предложения JOIN для ваших запросов, а не старый стиль с запросами табличного типа, разделенными запятыми.

Другие вопросы по теме