PLSQL Procedure to change data across a full database - plsql

I've been asked to write a PLSQL procedure to 'clean up' codes in a database. The codes are varchar2 and are something like 00000001. They are used everywhere in the application. My new employer wants me to make the codes more readable as in turn the 00000001 into just 1 for everywhere they are used.
My question is how would one even go about that? I asked for clarification and it's still not clear and for fear of looking foolish I won't ask again. Any guidance would be welcome

let me start by saying that that sounds like a VERY BAD IDEA!!!!
if you persist it sound like you will need to use dynamic sql with the basic process of...
query all_tab_cols to get a list of columns( im hoping all your columns that use these codes have a naming standard.. ie xxx_CD )
loop over tab/cols to see if your value is there
update values in that table
...
profit ?
however then you get stuck by realities.. if the code is in a foreign key you cant just update it. you'd have to create a new parent record.. update all children to new parent then delete old parent.
you'd need to be very clear on what you are trying to achieve.. and more importantly, is there any value in it?
i suggest you start with a single codevalue to scope out the size of project.
manually start writing the updates you'd need for that 1 codevalue and then try to start automating it.

Related

Function of Rows, Rowsets in PeopleCode

I'm trying to get a better understanding of what Rows and Rowsets are used for in PeopleCode? I've read through PeopleBooks and still don't feel like I have a good understanding. I'm looking to get more understanding of these as it pertains to Application Engine programs. Perhaps walking through an example may help. Here are some specific questions I have:
I understand that Rowsets, Row, Record, and Field are used to access component buffer data, but is this still the case for stand alone Application Engine programs run via Process Scheduler?
What would be the need or advantage to using these as opposed to using SQL objects/functions (CreateSQL, SQLExec, etc...)? I often see in AE programs where the CreateRowset object is instantiated and uses a .Fill method with a SQL WHERE Clause and I don't quite understand why a SQL was not used instead.
I've seen in PeopleBooks that a Row object in a component scroll is a row, how does a component scroll relate to the row? I've seen references to rows having different scroll levels, is this just a way of grouping and nesting related data?
After you have instantiated the CreateRowset object, what are typical uses of it in the program afterwards? How would you perform logic (If, Then, Else, etc..) on data retrieved by the rowset, or use it to update data?
I appreciate any insight you can share.
You can still use Rowsets, Rows, Records and fields in stand alone Application Engines. Application Engines do not have component buffer data as they are not running within the context of a component. Therefore to use these items you need to populate them using built-in methods like .fill() on a rowset, or .selectByKey() on a record.
The advantage of using rowsets over SQL is that it makes the CRUD easier. There are built-in methods for selecting, updating, inserting and deleting. Additionally you don't have to worry about making a large number of variables if there were multiple fields like you would with a SQL object. Another advantage is when you do the fill, the data is read into memory, where if you looped through the SQL, the SQL cursor would be open longer. The rowset, row, record and field objects also have a lot of other useful methods such as allowing you to executeEdits (validation) or copy from one rowset\row\record to another.
This question is a bit less clear to me but I'll try and explain. If you have a Page, it would have a level 0 row. It then could have multiple Level 1 rowsets. Under each of those it could have a level 2 rowsets.
Level0
/ \
Level1 Level1
/ \ / \
Level2 Level2 Level2 Level2
If one of your level1 rows had 3 rows, then you would find 3 rows in the Rowset associated with that level1. Not sure I explained this to answer what you need, please clarify if I can provide more info
Typically after I create a rowset, I would loop through it. Access the record on each row, do some processing with it. In the example below, I look through all locked accounts and prefix their description with LOCKED and then updated the database.
.
Local boolean &updateResult;
local integer &i;
local record &lockedAccount;
Local rowset &lockedAccounts;
&lockedAccounts = CreateRowset(RECORD.PSOPRDEFN);
&lockedAccounts.fill("WHERE acctlock = 1");
for &i = 1 to &lockedAccounts.ActiveRowCount
&lockedAccount = &lockedAccounts(&i).PSOPRDEFN;
if left(&lockedAccount.OPRDEFNDESCR.value,6) <> "LOCKED" then
&lockedAccount.OPRDEFNDESCR.value = "LOCKED " | &lockedAccount.OPRDEFNDESCR.value;
&updateResult = &lockedAccount.update();
if not &updateResult then
/* Error handle failed update */
end-if;
end-if;
End-for;

Check if record already exists when doing a buffer-copy

I have a piece of code which does a Buffer-Copy method, but is there any way to check before doing the buffer copy of the record already exists? I do not want to check 'unique keys' in my data dictionary.
This is the code I have at this moment:
CREATE QUERY hQuery.
hQuery:SET-BUFFERS(hBuffer).
hQuery:QUERY-PREPARE("FOR EACH " + hBuffer:NAME + " NO-LOCK ").
hQuery:QUERY-OPEN().
hQuery:GET-FIRST().
DO WHILE NOT hQuery:QUERY-OFF-END:
DO TRANSACTION ON ERROR UNDO:
hDBBuffer:BUFFER-CREATE().
hDBBuffer:BUFFER-COPY(hBuffer) NO-ERROR.
It is unclear what you are trying to accomplish and why you don't want to check unique keys "in my data dictionary" or even what you mean by that.
Your example code is very sketchy and incomplete, maybe someone else can figure out what you are trying to do and why, but I am at a loss to divine the purpose behind it. The use of handles and dynamic queries is especially puzzling. There doesn't seem to be a reason for that or any need to do that.
None the less, if I were coding a routine to copy a buffer, couldn't look up unique indexes in the dictionary, and wanted to pro-actively avoid potential collisions I might write something like this:
define temp-table oLine like orderLine.
for each orderline no-lock:
find oLine of orderLine no-error.
if not available( oLine ) then create oLine.
buffer-copy orderLine to oline.
end.
(Using static coding to keep the example simple.)
(I wouldn't really use OF - it is on my personal forbidden list, I think it is terrible from a documentation and maintenance perspective.)
I believe, as Tom has mentioned in his reply, it'd be most appropriate to have another dynamic query directed at the hDBBuffer using the BUFFER-FIELDs and BUFFER-VALUEs from hBuffer and check the NUM-RESULTS after you use QUERY-OPEN. Then delete the query for memory purposes.
But yes, you would be looking for the metadata unique keys to achieve that. I understand you don't want to do it, but it's REALLY the best way, can't stress it enough.
Now if you would really like to check for the existence of ALL the record data, look into the BUFFER-COMPARE method. You could create a second dynamic query, then cycle all records there by using buffer-compare to match the entire record you're looking at to the one you're assessing whether to create, or list the ones you wish to include or exclude. This approach is way less performatic, though, please keep that in mind.

Powerapps - get stuck with UpdateContext

I am trying to build a PowerApp to log setup times of our machines by our fitters.
This is what my app looks like:
There are buttons named "Uhrzeit". Pressing these will write the current date and time into the Date/Time fields. I am using the following code:
UpdateContext({Total8:(Text( Now(); "[$-de-DE]dd/mm/yyyy hh:mm:ss" ))})
The Date/Time field is named Total8.
The code is working well but after saving the form and opening a new record the old data is still available in the fields. By clicking on the button "Zeiten zurücksetzen" I can "delete" the old data.
UpdateContext({Total8:""})
Problem: When I open one of the older records the old data is not available in the form. There is only the value of the last record. In the Common Data Service where my records are saved the values are correct.
As an example, I am saving this record:
When I open a new record, the values of the record 1 are still available. This should not be the case if my app worked properly.
For your Information:
If I enter the date/time without tapping the button, saving the record and opening a new record I don't have the problem. I think the "UpdateContext" code is not the code I should use here.
Can anyone help me solve the problem?
I don't think there's a problem with using the contexts in this way -- but remember that a context is just a variable. It isn't automatically linked to a datasource in any special way - so if you set it equal to Now(), it's going to keep that value until you do something different.
When you view an old record, you need to get the data from CDS and update your contexts to match the CDS data. Does this make sense?
Yeah thats my problem.
I want the variable to be linked to a datasource. Or is it possible to write the date/time into the fields without using a context variable?

Generate Number with Validating rule in Access

I have a database in access for institute. there is a [Registers] Table and [Certificates] Table.
I want to give Mark to each of Registers a Mark. I want to set Validation Rule for Each
If [Certificates].[Mark]>70
Then UpdateRecord
SetField
CertificateID "GENERATE AutoNumber"
My Problem is i cant handle the CertificateID Generate with Macro. i cant use DMAX.
looking for a solution to give CertificateID to only Registers who passed the Course.
Tried "After Update" Macro and "After Insert" macro but still didnt success.
is there any other way to give AutoNumber except "DMax"?
Well, i just already found a way but not the best way.
I just added another Table as "Certificates" and renamed current(Certificates) to "Marks".
Tables and Fields
i made a query with Select a "Grade" from Certificates Table and rest from Marks. Whenever i fill a record in Grade table it generate Autonumber for "CertificateID" a new number.
For Validation i set my validation Rule in my form on Grade which i cant fill that field if Marks.Mark is less than 70. ( [Marks].[Mark] < 70)
I know its not a good way.
Still looking for better answer

PL/SQL and Oracle Forms Builder

So I need to put this project together for school, but I'm ONLY allowed to use oracle forms builder.
I'm trying to do a simple query and assign values to the form objects based on what I get from the query, but my form items are coming up as undeclared. Does anyone know how I can modify form attributes like this? This user interface on this program is awful, so doing it through the wizards is something I'd really like to avoid if I can just make things happen in PL/SQL.
Here's what I have:
Still trying to find a working solution.
I've modified my code a bit:
DECLARE
pmrn patient.p_mrn%TYPE;
var_ptuple patient%ROWTYPE;
BEGIN
pmrn := NAME_IN('MRN_FIELD');
SELECT * INTO var_ptuple from patient WHERE patient.p_mrn = pmrn;
:PATIENT_BLOCK.FNAME := var_ptuple.p_fname;
:PATIENT_BLOCK.LNAME := var_ptuple.p_lname;
END;
Using the where on the data block doesn't really suit these purposes because I would like to retrieve the data based on the user input. Ie. the user needs to input the correct user ID to see their records.
Form items can be referred to as bind variables in Forms PL/SQL, e.g.
pmrn := :PATIENT_BLOCK.MRN_FIELD;
:PATIENT_BLOCK.FNAME := var_ptuple.p_fname;
etc.
Be aware, however, that you most probably don't need to write all this code. Just set the block source to be the table and execute a query on it - Forms will take care of loading the records for you.

Resources