Как зайти в Даркнет?!
25th January, 01:11
6
0
Как в tkinter из поля ввода Entry получить значение в одну переменную и обновить строку кнопкой, затем получить ещё одно введённое значение и затем сложить их. Ниже пример кода
21st July, 19:00
895
0
Программа, которая создает фейковые сервера в поиске игровых серверов CS 1.6 Steam
21st March, 17:43
948
0
Очень долго работает Update запрос Oracle
27th January, 09:58
914
0
не могу запустить сервер на tomcat HTTP Status 404 – Not Found
21st January, 18:02
905
0
Где можно найти фрилансера для выполнения поступающих задач, на постоянной основе?
2nd December, 09:48
938
0
Разработка мобильной кроссплатформенной военной игры
16th July, 17:57
1724
0
период по дням
25th October, 10:44
3955
0
Пишу скрипты для BAS только на запросах
16th September, 02:42
3720
0
Некорректный скрипт для закрытия блока
14th April, 18:33
4613
0
прокидывать exception в блоках try-catch JAVA
11th March, 21:11
4381
0
Помогите пожалуйста решить задачи
24th November, 23:53
6086
0
Не понимаю почему не открывается детальное описание продукта
11th November, 11:51
4351
0
Нужно решить задачу по программированию на массивы
27th October, 18:01
4396
0
Метода Крамера С++
23rd October, 11:55
4309
0
помогите решить задачу на C++
22nd October, 17:31
4002
0
Помогите решить задачу на python с codeforces
22nd October, 11:11
4492
0
Python с нуля: полное руководство для начинающих
18th June, 13:58
2599
0
Лучший способ инкапсулировать сложную логику курсора Oracle PL/SQL в виде представления?
Я написал код PL/SQL для денормализации таблицы в форму much-easer-to-query. Код использует временную таблицу для выполнения некоторой части своей работы, объединяя некоторые строки из исходной таблицы вместе.
Логика записывается как конвейерная табличная функция, следуя шаблону из связанной статьи. Табличная функция использует объявление PRAGMA AUTONOMOUS_TRANSACTION для разрешения временного манипулирования таблицей, а также принимает входной параметр курсора, чтобы ограничить денормализацию определенными значениями ID.
Затем я создал представление для запроса табличной функции, передавая все возможные значения ID в качестве курсора (другие варианты использования функции будут более ограничительными).
Мой вопрос: действительно ли все это необходимо? Неужели я совершенно упустил из виду гораздо более простой способ сделать то же самое?
Каждый раз, когда я касаюсь PL / SQL, у меня создается впечатление, что я печатаю слишком много.
Обновление: я добавлю эскиз таблицы, с которой имею дело, чтобы дать всем представление о денормализации, о которой я говорю. В таблице хранится история заданий сотрудников, каждое из которых содержит строку активации и (возможно) строку завершения. У сотрудника может быть несколько одновременных заданий, а также одна и та же работа снова и снова в несмежных диапазонах дат. Например:
| EMP_ID | JOB_ID | STATUS | EFF_DATE | other columns...
| 1 | 10 | A | 10-JAN-2008 |
| 2 | 11 | A | 13-JAN-2008 |
| 1 | 12 | A | 20-JAN-2008 |
| 2 | 11 | T | 01-FEB-2008 |
| 1 | 10 | T | 02-FEB-2008 |
| 2 | 11 | A | 20-FEB-2008 |
Запрос на то, чтобы выяснить, кто работает, когда в какой работе, является нетривиальным. Итак, моя функция денормализации заполняет временную таблицу только диапазонами дат для каждого задания, для любого EMP_ID s, переданного через курсор. Прохождение через EMP_ID с 1 и 2 приведет к следующим результатам:
| EMP_ID | JOB_ID | START_DATE | END_DATE |
| 1 | 10 | 10-JAN-2008 | 02-FEB-2008 |
| 2 | 11 | 13-JAN-2008 | 01-FEB-2008 |
| 1 | 12 | 20-JAN-2008 | |
| 2 | 11 | 20-FEB-2008 | |
( END_DATE позволяет NULL s для заданий,которые не имеют заранее определенной даты окончания.)
Как вы можете себе представить, эта денормализованная форма намного проще для запроса, но для ее создания-насколько я могу судить-требуется временная таблица для хранения промежуточных результатов (например, записей заданий, для которых была найдена строка активации, но не termination...yet). Использование конвейерной табличной функции для заполнения временной таблицы и последующего возврата ее строк-это единственный способ, который я понял, как это сделать.
Я думаю, что один из способов приблизиться к этому-использовать аналитические функции...
Я создал тестовый случай с помощью:
create table employee_job (
emp_id integer,
job_id integer,
status varchar2(1 char),
eff_date date
);
insert into employee_job values (1,10,'A',to_date('10-JAN-2008','DD-MON-YYYY'));
insert into employee_job values (2,11,'A',to_date('13-JAN-2008','DD-MON-YYYY'));
insert into employee_job values (1,12,'A',to_date('20-JAN-2008','DD-MON-YYYY'));
insert into employee_job values (2,11,'T',to_date('01-FEB-2008','DD-MON-YYYY'));
insert into employee_job values (1,10,'T',to_date('02-FEB-2008','DD-MON-YYYY'));
insert into employee_job values (2,11,'A',to_date('20-FEB-2008','DD-MON-YYYY'));
commit;
Я использовал функцию lead для получения следующей даты, а затем завернул все это в подзапрос, чтобы получить записи "A" и добавить конечную дату, если она есть.
select
emp_id,
job_id,
eff_date start_date,
decode(next_status,'T',next_eff_date,null) end_date
from
(
select
emp_id,
job_id,
eff_date,
status,
lead(eff_date,1,null) over (partition by emp_id, job_id order by eff_date, status) next_eff_date,
lead(status,1,null) over (partition by emp_id, job_id order by eff_date, status) next_status
from
employee_job
)
where
status = 'A'
order by
start_date,
emp_id,
job_id
Я уверен, что есть несколько случаев использования, которые я пропустил, но вы поняли идею. Аналитические функции - это ваш друг :)
EMP_ID JOB_ID START_DATE END_DATE
1 10 10-JAN-2008 02-FEB-2008
2 11 13-JAN-2008 01-FEB-2008
2 11 20-FEB-2008
1 12 20-JAN-2008
Вместо того, чтобы иметь входной параметр в качестве курсора, Я бы имел табличную переменную (не знаю, есть ли у Oracle такая вещь, я-парень TSQL) или заполнил другую временную таблицу значениями ID и присоединился к ней в представлении/функции или там, где вам нужно.
Единственное время для курсоров, по моему честному мнению, это когда вы должны петлять. И когда вам нужно сделать цикл, я всегда рекомендую сделать это вне базы данных в логике приложения.
Это звучит так,как будто вы даете некоторую согласованность чтения здесь ie: это будет возможно для содержимого вашей временной таблицы, чтобы быть несинхронизированным с исходными данными, если у вас есть одновременное изменение данных модификации.
Не зная ни требований, ни сложности того, чего вы хотите достичь. Я бы попытался
- чтобы определить представление, содержащее (возможно, сложную) логику в SQL, в противном случае я бы добавил некоторые PL/SQL в смесь с;
- Конвейерная табличная функция, но с использованием типа коллекции SQL (вместо временной таблицы). Вот простой пример: http://asktom.oracle.com/pls/asktom/f?Р=100:11:0::::P11_QUESTION_ID:4447489221109
Номер 2 даст вам меньше движущихся частей и решит вашу проблему согласованности.
Мэтью Батлер
Настоящая проблема здесь - это дизайн таблицы "write-only", под которым я подразумеваю, что в нее легко вставить данные, но сложно и неэффективно получить полезную информацию из нее! Ваша таблица "temporary" имеет структуру, которую должна была иметь таблица "permanent" в первую очередь.
Не могли бы вы это сделать:
- Создайте постоянную таблицу с лучшей структурой
- Заполните его, чтобы он соответствовал данным в первой таблице
- Определите триггер базы данных для исходной таблицы, чтобы с этого момента синхронизировать новую таблицу
Затем вы можете просто выбрать из новой таблицы, чтобы выполнить свой отчет.
Я не могу не согласиться с вами, HollyStyles. Я тоже когда-то был парнем TSQL и нахожу некоторые особенности Oracle более чем немного озадачивающими. К сожалению, временные таблицы не так удобны в Oracle, и в этом случае другая существующая логика SQL ожидает прямого запроса таблицы, поэтому я даю ей это представление вместо этого. В этой системе действительно нет никакой прикладной логики, которая существует вне базы данных.
Oracle разработчики, похоже, используют курсоры гораздо охотнее, чем я думал. Учитывая рабскую & дисциплинирующую природу PL/SQL,, это тем более удивительно.
Самое простое решение-это:
Создайте глобальную временную таблицу , содержащую только IDs, который вам нужен:
CREATE GLOBAL TEMPORARY TABLE tab_ids (id INTEGER) ON COMMIT DELETE ROWS;Заполните временную таблицу нужным вам параметром IDs.
Используйте операцию EXISTS в своей процедуре для выбора строк, которые находятся только в таблице IDs:
SELECT yt.col1, yt.col2 FROM your\_table yt WHERE EXISTS ( SELECT 'X' FROM tab_ids ti WHERE ti.id = yt.id )
Вы также можете передать разделенную запятыми строку IDs в качестве параметра функции и проанализировать ее в таблицу. Это выполняется одним SELECT. Хотите узнать больше-спросите меня, как :-) но это должен быть отдельный вопрос.