Oracle Apex - 使用替代触发器更新视图
这里是顶尖初学者。我的 Oracle 数据库中有一个以下形式的视图:
create or replace view vw_awkward_view as
select unique tab1.some_column1,
tab2.some_column1,
tab2.some_column2,
tab2.some_column3
from table_1 tab1,
table_2 tab2
WHERE ....
我需要“tab1.some_column1”上的“unique”子句,因为它的基础表中有许多条目。我还需要在我的视图中包含“tab1.some_column1”,因为如果没有它,其余数据就没有多大意义。
在 Apex 中,我想在此视图上创建一个报告,并带有用于编辑它的表单(仅更新)。我不需要编辑 tab1.some_column1。只有视图中的其他列需要可编辑。我通常可以使用“instead-of”触发器来实现此目的,但是当视图包含“distinct”、“unique”或“group by”子句时,这看起来不可能。
如果我尝试更新此视图上的行,则会收到以下错误:
ORA-02014: cannot select FOR UPDATE from view with DISTINCT, GROUP BY, etc.
如何避免此错误?我希望我的“替代”触发器启动并执行更新,并且我不需要编辑具有“唯一”子句的列,所以我认为应该可以做到这一点。
Apex beginner here. I have a view in my Oracle database of the form:
create or replace view vw_awkward_view as
select unique tab1.some_column1,
tab2.some_column1,
tab2.some_column2,
tab2.some_column3
from table_1 tab1,
table_2 tab2
WHERE ....
I need the 'unique' clause on 'tab1.some_column1' because it has many entries in its underlying table. I also need to include 'tab1.some_column1' in my view because the rest of the data doesn't make much sense without it.
In Apex, I want to create a report on this view with a form for editing it (update only). I do NOT need to edit tab1.some_column1. Only the other columns in the view need to be editable. I can normally achieve this using an 'instead-of' trigger, but this doesn't look possible when the view contains a 'distinct', 'unique' or 'group by' clause.
If I try to update a row on this view I get the following error:
ORA-02014: cannot select FOR UPDATE from view with DISTINCT, GROUP BY, etc.
How can I avoid this error? I want my 'instead-of' trigger to kick in and perform the update and I don't need to edit the column which has the 'unique' clause, so I think it should be possible to do this.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
我认为你应该能够删除“独特”。
如果 tab2.some_column1、tab2.some_column2、tab2.some_column3 不唯一,那么您希望如何更新它们?
如果它们是唯一的,则整个结果:tab1.some_column1、tab2.some_column1、tab2.some_column2、tab2.some_column3 是唯一的。
当您在 sql 查询中声明“唯一”或“不同”时,它适用于所有列,而不仅仅是“tab1.some_column1”
I think that you should be able to remove the "unique".
if tab2.some_column1, tab2.some_column2, tab2.some_column3 are not unique, then how do you want to update them ?
if they are unique then the whole result: tab1.some_column1, tab2.some_column1, tab2.some_column2, tab2.some_column3 is unique.
When you state in a sql query "unique" or "distinct" it's for all columns not only 'tab1.some_column1'
希望我在这里的问题方向正确;)
您的查询可以通过执行以下操作来实现:
您收到
ORA-02014
错误的原因是因为自动生成的ApplyMRU
过程。此过程将尝试锁定已更改的行:这很糟糕,并且意味着您将无法使用生成的过程。 您必须编写自己的更新流程。
为此,您必须使用 apex_application。
如果这听起来完全陌生,请看一下:
自定义提交流程,以及关于使用 apex_application 数组。
另外,这里有 apex 的操作方法从 2004 年开始,来自 Oracle 本身。它仍然使用大量 htmldb 引用,但其要点就在那里。
(使用
apex_item
接口来构建表单,并控制生成的内容和需要的数组可能是个好主意。)归根结底是:循环数组包含您的项目,并使用提交的值对您的视图进行
UPDATE
。当然,您没有这种方式锁定,也没有办法防止不必要的更新。
您可以自己锁定,例如使用
选择更新
方法。在更新它们之前,您必须锁定要更改的表中的正确行。如果锁定失败,那么您的进程应该失败。至于“丢失更新”的故事:这里您需要检查 MD5 校验和。校验和是从表单中的可编辑列生成的,并放入 html 代码中。提交时,会将该校验和与来自相同列的新生成的校验和进行比较,但与提交时数据库中的值进行比较。如果校验和不同,则意味着页面加载和页面提交之间的记录已更改。您的过程应该会失败,因为记录已被更改,并且您不希望这些记录被覆盖。 (如果您采用
apex_item
方式,请不要忘记包含 MD5_CHECKSUM 调用(或 MD5_HIDDEN)。但重要提示:使用 apex_item 或简单地使用标准表单功能生成的校验和会构建要进行哈希处理的字符串,如 apex_item.md5_hidden,校验和是使用
DBMS_OBFUSCATION_TOOLKIT.MD5
生成的。您可以通过两种方式获取数据库中值的校验和:wwv_flow_item.md5 或使用
dbms_obfuscation
。然而,文档没有提到的是:OTN Apex 关于 MD5 校验和的讨论< /a>.管道被添加到生成的校验和中!不要忘记这一点,否则它会在你脸上爆炸,你会在几天内想知道它到底出了什么问题。
例子:
Hope i'm in the correct direction of your question here ;)
Your query could be achieved by doing something like:
The reason you get the
ORA-02014
error is because of the automatically generatedApplyMRU
process. This process will attempt to lock a (the) changed row(s):That's a bummer, and means you won't be able to use the generated process. You'll have to write your own process which does the updating.
For this, you'll have to use the F## arrays in apex_application.
If this sounds totally unfamiliar, take a look at:
Custom submit process, and on using the apex_application arrays.
Also, here is a how-to for apex from 2004 from Oracle itself. It still uses lots of htmldb references, but the gist of it is there.
(it might be a good idea to use the
apex_item
interface to build up your form, and have control over what is generated and what array it takes.)What it comes down to is: loop over the array containing your items and do an
UPDATE
on your view with the submitted values.Of course, you don't have locking this way, nor a way to prevent unnecessary updates.
Locking you can do yourself, with for example using the
select for update
method. You'd have to lock the correct rows in the table(s) you want to alter, before you update them. If the locking fails, then your process should fail.As for the 'lost update' story: here you'd need to check the MD5-checksums. A checksum is generated from the editable columns in your form and put in the html-code. On submit, this checksum is then compared to a newly generated checksum from those same columns, but with values from the database at that time of submit. If the checksums differ, it means the record has changed between the page load and the page submit. Your process should fail because the record has been altered, and you don't want to have those overwritten. (if you go the
apex_item
way, then don't forget to include an MD5_CHECKSUM call (or MD5_HIDDEN).Important note though: checksums generated by either using apex_item or simply the standard form functionality build up a string to be hashed. As you can see in apex_item.md5_hidden, checksums are generated using
DBMS_OBFUSCATION_TOOLKIT.MD5
.You can get the checksum of the values in the DB in 2 ways: wwv_flow_item.md5 or using
dbms_obfuscation
.However, what the documentation fails to mention is this: OTN Apex discussion on MD5 checksums. Pipes are added in the generated checksums! Don't forget this, or it'll blow up in your face and you'll be left wondering for days what the hell is wrong with it.
Example:
|||'
)) md5
from some_table
获取
some_table
表的一行的校验和,其中第 1,2,5,7,10,12,14 列是可编辑的!最后,它的结构应该是这样的:
从数据库中
(如果生成了 apex_application.g_fcs)如果校验和匹配,
继续更新。如果不是,则此处过程失败。
锁定失败,进程失败,
会火。请确保为更新语句使用正确的值,以便仅更新这一记录
不要在其间提交。要么全有,要么全无。
我几乎觉得我有点太过分了,而且可能感觉有点太多了,但当你知道其中的陷阱时,完成这个定制过程实际上并不难!玩它对我来说非常有见识:p
|||'
)) md5
from some_table
To get the checksum of a row of the
some_table
table, where columns 1,2,5,7,10,12,14 are editable!In the end, this is how it should be structured:
from the database
(apex_application.g_fcs if generated) if the checksums match,
proceed with update. If not, fail process here.
locking fails, fail the process
will fire. Be sure you use correct values for your update statement so that only this one record will be updated
Don't commit inbetween. It's either all or nothing.
I almost feel like i went overboard, and it might feel like it is all a bit much, but when you know the pitfalls it's actually not so hard to pull this custom process off! It was very knowledgable for me to play with it :p
汤姆的回答是处理这个问题的正确方法,但如果我理解正确的话,我认为对你的要求来说是过度的。
最简单的方法可能是在要编辑的表格上创建一个表单。然后让报告编辑链接将用户带到此表单,该表单将仅更新一个表中所需的列。如果您需要显示其他表中的列的值,则在创建链接以将此值传递到表单时很简单,该表单可以包含仅显示项目来显示此值。
The answer by Tom is a correct way of dealing with ths issue but I think overkill for your requirements if I understand correctly.
The easiest way may be to create a form on the table you want to edit. Then have the report edit link take the user to this form which will only update the needed columns from the one table. If you need the value of the column from the other table displayed it is simple when you create the link to pass this value to the form which can contain a display only item to show this.