#sql #oracle
#sql #Oracle
Вопрос:
У меня есть требование найти emplid, имеющий разницу в данных в одной таблице. Таблица состоит из 50-60 столбцов.. Мне нужно проверить, есть ли в каком-либо столбце изменения в данных из предыдущей строки, emplidshould получить сбор, а также, если какой-либо новый сотрудник получит add, который также необходимо забрать..
Я создал базовый запрос, и он работает, но мне нужен какой-то способ достичь той же цели, поскольку я не хочу записывать имя каждого столбца.
Мой запрос:
select
emplid
from
ps_custom_tbl t, ps_custom_tbl prev_t
where
prev_t.emplid = t.emplid
and t.effdt = (select max effdt from ps_custom_tbl t2
where t2.emplid = t.emplid)
and prev_t.effdt = (select max(effdt) from ps_custom_tbl prev_t2
where emplid = prev_t.emplid and effdt < t.effdt)
and (t.first_name prev_t.first_name Or t.last_name prev_t.last_name …. 50 columns);
Не могли бы вы предложить другой способ добиться того же?
Комментарии:
1. Вредные привычки: использование объединений в старом стиле — этот стиль списка таблиц, разделенных запятыми , в старом стиле был заменен на правильный
JOIN
синтаксис ANSI в стандарте SQL ANSI- 92 ( более 25 лет назад), и его использование не рекомендуется2. Вам нужно будет записать имена всех столбцов. Однако вы можете получить их из запроса, например
select 'or (decode(t.' || column_name || ', prev_t.' || column_name || ', ''same'', ''different'') = ''different'')' from user_tab_cols where table_name = 'PS_CUSTOM_TBL'
. Это также означает, что вы можете написать функцию PL / SQL, динамически строящую запрос для извлечения различий.
Ответ №1:
Вы можете использовать МИНУС.
если no_data, то оба совпадают, если есть несколько записей — означает, что есть разница между
create table emp as select * from hr.employees;
insert into emp select employee_id 1000, first_name, last_name, email, phone_number, hire_date, job_id, salary, commission_pct, manager_id,
decode(department_id ,30,70, department_id)
from hr.employees;
select first_name, last_name, email, phone_number, hire_date, job_id, salary, commission_pct, manager_id, department_id
from emp where employee_id <= 1000
minus
select first_name, last_name, email, phone_number, hire_date, job_id, salary, commission_pct, manager_id, department_id
from emp where employee_id > 1000;
Но вы должны перечислить все столбцы, потому что, если у вас, например, разные даты или идентификаторы — они тоже будут сравниваться. Но проще перечислить столбцы в предложении SELECT, а затем написать для всех условие WHERE.
Возможно, это поможет.
— или, если разные таблицы и хотите сравнить все столбцы, просто сделайте
drop table emp;
create table emp as select * from hr.employees;
create table emp2 as
select employee_id, first_name, last_name, email, phone_number, hire_date, job_id, salary, commission_pct, manager_id,
decode(department_id ,30,70, department_id) department_id
from hr.employees;
select * from emp
minus
select * from emp2;
—- ДОБАВИТЬ КРИТЕРИИ ДАТЫ
— да, вы можете добавить критерии даты и с помощью аналитических функций проверить, какой из них более новый, а какой
старше, а затем сравните один с другим. как показано ниже:
drop table emp;
create table emp as select * from hr.employees;
insert into emp
select
employee_id,
first_name,
last_name,
email,
phone_number,
hire_date 1,
job_id,
salary,
commission_pct,
manager_id,
decode(department_id ,30,70, department_id)
from hr.employees;
with data as --- thanks to WITH you retrieve data only once
(select employee_id, first_name, last_name, email, phone_number,
hire_date,
row_number() over(partition by employee_id order by hire_date desc) rn -- distinguish newer and older record,
job_id, salary, commission_pct, manager_id, department_id
from emp)
select employee_id, first_name, last_name, email, phone_number, department_id from data where rn = 1
MIUNUS--- find the differences
select employee_id, first_name, last_name, email, phone_number, department_id from data where rn = 2;
Комментарии:
1. Что касается оператора минус, можно ли применить критерии даты.. При каждом запуске будут загружаться данные сотрудника, поэтому у меня нет этого поля даты, но если для конкретного идентификатора сотрудника не добавлены строки.. Или, скажем, загруженный сотрудник 1sep a, сотрудник 2 sep a не загружен, но загружены b и c.. 3 сентября снова загружен сотрудник A.. Будет ли это возможно.. Как мы привыкли делать критерии effdt..
2. да, вы можете добавить критерии даты. проверьте мой ответ, я его отредактировал. Вы можете использовать WITH для получения данных только один раз, вы можете использовать аналитическую функцию для различения более новой и более старой даты, а также использовать МИНУС для поиска различий
Ответ №2:
Вам придется в некотором смысле записывать все столбцы независимо от того, что вы делаете.
С точки зрения сравнения текущего и предыдущего, вам может показаться, что это проще
select
col1,
col2,
...
lag(col1) over ( partition by empid order by effdt ) as prev_col1,
lag(col2) over ( partition by empid order by effdt ) as prev_col2
...
и тогда сравнение будет выглядеть следующим образом
select *
from ( <query above >
where
decode(col1,prev_col1,0,1) = 1 or
decode(col2,prev_col2,0,1) = 1 or
...
Использование DECODE таким образом решает проблемы с нулевыми значениями.
Комментарии:
1. Спасибо за ответ.. Насколько я понимаю, мне нужно записать все 50 имен столбцов, даже если я использую функцию задержки.. Будет ли работать функция except.. Мне просто нужно знать, есть ли изменения в двух строках..
Ответ №3:
Мое требование — отправлять данные менеджерам, они меняют любые / все / ни одного из данных в столбцах и отправляют обратно мне. Затем я должен определить каждый столбец, который отличается от того, что я отправил, и пометить эти столбцы как измененные, чтобы специалист по проверке центрального офиса визуально сканировал и одобрял / отклонял изменения для интеграции обратно в центральный набор данных.
Конечно, это решение может не соответствовать вашим потребностям, но здесь предлагается структура шаблона, которую вы можете дополнить в соответствии с вашими потребностями, независимо от количества столбцов. В случае вашего вопроса 50-60 столбцов сделают этот SQL-запрос огромным, но в прошлом я с большим успехом писал ужасно длинные запросы. Добавляйте столбцы по несколько за раз, а не все оптом в соответствии с этим шаблоном, и посмотрите, работают ли они на этом пути.
Вы могли бы легко написать pl / sql, чтобы написать этот запрос для вас для рассматриваемых таблиц. Это было бы очень громоздко, если бы вам приходилось сравнивать столбцы из 3 или более таблиц или двунаправленные изменения. Меня интересуют только изменения в одном направлении. Изменил ли человек мои исходные столбцы строк или нет. Если да, то какие столбцы они изменили, и каково было мое значение до и каково их значение после, и больше ничего не показывайте, пожалуйста.
Другими словами, показывайте мне только строки со столбцами, которые имеют изменения с их предыдущими значениями, и ничего больше.
create table thing1 (id number, firstname varchar2(10), lastname varchar2(10));
create table thing2 (id number, firstname varchar2(10), lastname varchar2(10));
insert into thing1 values (1,'Buddy', 'Slacker');
insert into thing2 values (1,'Buddy', 'Slacker');
insert into thing1 values (2,'Mary', 'Slacker');
insert into thing2 values (2,'Mary', 'Slacke');
insert into thing1 values (3,'Timmy', 'Slacker');
insert into thing2 values (3,'Timm', 'Slacker');
insert into thing1 values (4,'Missy', 'Slacker');
insert into thing2 values (4,'Missy', 'Slacker');
commit;
Отменить комментарий прокомментированный select * запрашивает по одному после каждого набора данных, чтобы понять, что содержится в каждом наборе данных на каждом этапе процесса уточнения.
with rowdifferences as
(
select
id
,firstname
,lastname
from thing2
minus
select
id
,firstname
,lastname
from thing1
)
--select * from rowdifferences
,thing1matches as
(
select
t1.id
,t1.firstname
,t1.lastname
from thing1 t1
join rowdifferences rd on t1.id = rd.id
)
--select * from thing1matches
, col1differences as
(
select
id
,firstname
from rowdifferences
minus
select
id
,firstname
from thing1matches
)
--select * from col1differences
, col2differences as
(
select
id
,lastname
from rowdifferences
minus
select
id
,lastname
from thing1matches
)
--select * from col2differences
,truedifferences as
(
select
case when c1.id is not null then c1.id
when c2.id is not null then c2.id
end id
,c1.firstname
,c2.lastname
from col1differences c1
full join col2differences c2 on c1.id = c2.id
)
--select * from truedifferences
select
t1m.id
,case when td.firstname is not null then t1m.firstname end beforefirstname
,td.firstname afterfirstname
,case when td.lastname is not null then t1m.lastname end beforelastname
,td.lastname afterlastname
from thing1matches t1m
join truedifferences td on t1m.id = td.id
;