refactoring a database and application due to new requirements - oracle

My application manages customer's complaints and has already been deployed into production. Each complaint has a code to identify it (for eaxmple "late delivery" ), a "department" type (wich is essentially the department responsible for that kind of complaint) and another "model" code which identifies the route through department's employees this complaint dossier has to follow (first to hr responsible then to hr big boss finally back to customer care). Each dossier has some common info and can have department specific infos, that's why i need deparment code.
For example Customer care get a complaint about "rudeness" of a call center operator, opens a dossier with code ABC and type "HR" (there's could be more HR dossier types). When the customer care has filled all the infos, forward it to hr(a mail is sent to the user configured in the system as HR responsible ). The hr employee fills his own section and send it back to customer care.
Till now each complaint code might have only one department and one model, now requirements have changed and i've two problems:
Some complaints are identified by the same code but might be due to different departments . For example a complaint about employees rudeness could be sent to the department which rules the call centers or to the department which rules logistics
i could solve this simply extending the table primary key to include the department (hoping they'll not decide the same code for the same department can follow different routes), changing application code might be a bit painful but it can be done :
Does extending primary keys to composite keys is a problem in Oracle or have side effects on existing records? the actual primary key is not used as foreign key anywere and all fields are filled.
this is a quite more difficult problem (at least for me): marketing department (the rulers) wants a special dossier.They monitor time departments take to answer complaints and open a new type of dossier if they exceeds the standard time.
For the above example, if hr always needs the 30% more time to complete employees rudeness dossiers, marketing can open an "inquire" dossier about that complaint code directed to hr.
Now, referring to point 1, i could add a new record for each complaint code having the second part of the key being the marketing code and associating it to a new model.This is going to double the rows of the table (which is already quite large). I see it very error prone for inserting new complaint codes.
I know it's very hard to give an opinion without being able to see the schema and the code, but i would appreciate your opinion anyway

"Does extending primary keys to
composite keys is a problem in Oracle
or have side effects on existing
records? the actual primary key is not
used as foreign key anywere and all
fields are filled."
Oracle allows us to have composite primary keys. They are not a problem from a relational perspective.
The only objection to primary composite keys is the usual one, that they make foreign key relationships and joins more cumbersome. You say you currently don't have foreign keys which reference this table. Nevertheless I would suggest you define a synthetic (surrogate) primary key using an index, and enforce the composite key as a unique constraint. Because you may well have foreign keys in the future: your very predicament shows that your current data model is not correct, or at least not complete.
"i could add a new record for each
complaint code having the second part
of the key being the marketing code"
Smart keys are dumb. Add a separate column for a marketing code if necessary. This would be populated if Marketing open their own dossier. I don't see why it needs to be associated with the Complaint Code or form part of any primary key (other than the Marketing Code lookup table).
I admit I don't fully understand your data model or business logic, so the following might be wrong. However what I think you want is a table DOSSIERS which can have two dossier types:
normal dossier identified by DEPT_CODE and COMPLAINT_CODE
Marketing dossier which I presume would be identified by DEPT_CODE, COMPLAINT_CODE and MARKETING_CODE.
Unique constraints permit NULL columns, so MARKETING_CODE can be optional. This is another advantage of using one instead of a composite primary key.
"I see it very error prone for
inserting new complaint codes."
Do you mean creating new complaints? Or new complaint types? Creating new complaints shouldn't be a problem: the process for creating Normal Dossiers will offer a choice of COMPLAINT_CODES where MARKETING_CODE is null, whereas the process for creating Marketing Dossiers will offer a choice of COMPLAINT_CODES where MARKETING_CODE is not null.
If you're talking about adding new complaint types then I suppose the question becomes: does there have to be a separate MARKETING_CODE for each regular COMPLAINT_CODE? I suspect not. In which case, instead of a MARKETING_CODE perhaps you need a CODE_TYPE - values NORMAL or MARKETING.

Related

Correct way to model foreign keys to entities that do not (yet) exist?

I'm building a Spring Boot application using Spring Data JPA. I'll give a simplified description of the application that illustrates my problem:
I have a table of Students that has a student_id primary key and various personal information (incl name, etc). This personal data is loaded from an external source and may only be retrieved once the student gives his permission to retrieve it by logging into the application. I thus cannot create a list of all the users that might log in ahead of time. They are created and inserted into the database when the student logs in the first time.
I also load data sets like historical grades into the database ahead of time. These are of the form student_id (foreign key), course_id (foreign key), grades, year (and some other fields). The point is that once a student logs in, their historical grades will be visible. However, the database (initialized as empty by Spring Data JPA) will not let me insert the historical data as it complains that e.g. student_id 1234 (foreign key in the grades table) cannot be found as a primary key in the Students table. Which is true, because I will only create that user 1234 when and if he/she logs in.
I see the following options and don't really like any of them:
disable all constraints on foreign keys for the relevant classes (in which case: How do I tell Spring Data JPA to do that? I googled but couldn't find it) -> Disabling integrity checks sounds like a bad idea though.
Create 'dummy' students, i.e. simply go through the historical data, list all the student_id's and then pre-fill my Student table with entries like student_id = 1234, name = "", address = "", etc. This data would be filled in if/when the students logs in -> This also feels like a 'dirty' solution.
Keep the historical data in .csv files, or another manually created table and have the application load it into the 'real' database only after the student logs in for the first time -> This just sounds like a terrible mess.
Conceptually I'm inclined towards option 1, because I do in fact want to create/save a piece of historical data about a student, despite having no other information about that student. I'm afraid, however, that if I e.g. retrieve all grades for a course_id, those Grade entities will contain links to Student entities that do not in fact exist and this will just result in more errors.
How do you handle such a situation?

Loading records into Dynamics 365 through ADF

I'm using the Dynamics connector in Azure Data Factory.
TLDR
Does this connector support loading child records which need a parent record key passed in? For example if I want to create a contact and attach it to a parent account, I upsert a record with a null contactid, a valid parentcustomerid GUID and set parentcustomeridtype to 1 (or 2) but I get an error.
Long Story
I'm successfully connecting to Dynamics 365 and extracting data (for example, the lead table) into a SQL Server table
To test that I can transfer data the other way, I am simply loading the data back from the lead table into the lead entity in Dynamics.
I'm getting this error:
Failure happened on 'Sink' side. ErrorCode=DynamicsMissingTargetForMultiTargetLookupField,'Type=Microsoft.DataTransfer.Common.Shared.HybridDeliveryException,Message=,Source=,''Type=Microsoft.DataTransfer.Common.Shared.HybridDeliveryException,Message=Cannot find the target column for multi-target lookup field: 'ownerid'.
As a test I removed ownerid from the list of source columns it loads OK.
This is obviously a foreign key value.
It raises two questions for me:
Specifically with regards to the error message: If I knew which lookup it needed to use, how can I specify which lookup table it should validate against? There's no settings in the ADF connector to allow me to do this.
This is obviously a foreign key value. If I only had the name (or business key) for this row, how can I easily lookup the foreign key value?
How is this normally done through other API's, i.e. the web API?
Is there an XRMToolbox addin that would help clarify?
I've also read some posts that imply that you can send pre-connected data in an XML document so perhaps that would help also.
EDIT 1
I realised that the lead.ownertypeid field in my source dataset is NULL (that's what was exported). It's also NULL if I browse it in various Xrmtoolbox tools. I tried hard coding it to systemuser (which is what it actually is in the owner table against the actual owner record) but I still get the same error.
I also notice there's a record with the same PK value in systemuser table
So the same record is in two tables, but how do I tell the dynamics connector which one to use? and why does it even care?
EDIT 2
I was getting a similar message for msauto_testdrive for customerid.
I excluded all records with customerid=null, and got the same error.
EDIT 2
This link appears to indicate that I need to set customeridtype to 1 (Account) or 2 (Contact). I did so, but still got the same error.
Also I believe I have the same issue as this guy.
Maybe the ADF connector suffers from the same problem.
At the time of writing, #Arun Vinoth was 100% correct. However shortly afterwards there was a documentation update (in response to a GitHub I raised) that explained how to do it.
I'll document how I did it here.
To populate a contact with against a parent account, you need the parent accounts GUID. Then you prepare a dataset like this:
SELECT
-- a NULL contactid means this is a new record
CAST(NULL as uniqueidentifier) as contactid,
-- the GUID of the parent account
CAST('A7070AE2-D7A6-EA11-A812-000D3A79983B' as uniqueidentifier) parentcustomerid,
-- customer id is an account
'account' [parentcustomerid#EntityReference],
'Joe' as firstname,
'Bloggs' lastname,
Now you can apply the normal automapping approach in ADF.
Now you can select from this dataset and load into contact. You can apply the usual automapping approach, this is: create datasets without schemas. Perform a copy activity without mapping columns
This is the ADF limitation with respect to CDS polymorphic lookups like Customer and Owner. Upvote this ADF idea
Workaround is to use two temporary source lookup fields (owner team and user in case of owner, account and contact in case of customer) and with parallel branch in a MS Flow to solve this issue. Read more, also you can download the Flow sample to use.
First, create two temporary lookup fields on the entity that you wish to import Customer lookup data into it, to both the Account and Contact entities respectively
Within your ADF pipeline flow, you will then need to map the GUID values for your Account and Contact fields to the respective lookup fields created above. The simplest way of doing this is to have two separate columns within your source dataset – one containing Account GUID’s to map and the other, Contact.
Then, finally, you can put together a Microsoft Flow that then performs the appropriate mapping from the temporary fields to the Customer lookup field. First, define the trigger point for when your affected Entity record is created (in this case, Contact) and add on some parallel branches to check for values in either of these two temporary lookup fields
Then, if either of these conditions is hit, set up an Update record task to perform a single field update, as indicated below if the ADF Account Lookup field has data within it

ORACLE ENGINEER TO RELATIONAL how do i control key names generated?

Working on a school assignment, building databases. First I built my logical model of my database (Using Oracle SQL developer data modeler). There's this little blue arrow button (engineer to relational) which will take your logical model and attempt to create a relational model.
WHEN it does this, it will automatically generate names for your foreign keys. This part infuriates me because it creates these ridiculous named foreign keys, I'm simply looking for a way to turn this feature off (OR I'm open to whatever suave way they actually deal with it) Because so far, I have to go back and meticulously rename all my foreign keys throughout the database.
As a specific example, I have a Client entity, with a unique ID called Client_ID. After the modeler engineers the relational model, it automatically concatenates the name of the entity along with the attribute (for the other entities that have Client_ID as a foreign key). So even though I'd like my foreign key to simply be Client_ID it creates Client_Client_ID. I've been googling for the better part of the day but I can't find anything related to this.
found the answer here: https://community.oracle.com/thread/4012092
rightclick the source file of your database (its this tree looking model in this window on the left of the modeler).
click settings
naming standard
templates
here you will see its format(s) for keys, constraints,etc where you can customize them
(found this right after i posted question, sorry. Swear it took me hours earlier though)

Trigger to enforce M-M relationship

Suppose I have following schema :
DEPARTMENT (DepartmentName, BudgetCode, OfficeNumber, Phone)
EMPLOYEE (EmployeeNumber, FirstName, LastName, Department, Phone, Email)
The problem am facing is how to design a system of triggers to enforce the M-M relationship.Assuming that departments with only one employee can be deleted. Also I need to assign the last employee in a department to Human Resources.
I have no idea to enforce M-M relationship through trigger. Please help
Many-to-many conditions should not be enforced using a trigger. Many-to-many conditions are enforced by creating a junction table containing the keys in question, which are then foreign-keyed back to the respective parent tables.
If your intention is to allow many employees to be in a department, and to allow an employee to be a member of many departments, the junction table in question would look something like:
CREATE TABLE EMPLOYEES_DEPARTMENTS
(DEPARTMENTNAME VARCHAR2(99)
CONSTRAINT EMPLOYEES_DEPARTMENTS_FK1
REFERENCES DEPARTMENT.DEPARTMENTNAME,
EMPLOYEENUMBER NUMBER
CONSTRAINT EMPLOYEES_DEPARTMENTS_FK2
REFERENCES EMPLOYEE.EMPLOYEENUMBER);
This presumes that DEPARTMENT.DEPARTMENTNAME and EMPLOYEE.EMPLOYEENUMBER are either primary or unique keys on their respective tables. Get rid of the column EMPLOYEE.DEPARTMENT as it's no longer needed. Now by creating rows in the EMPLOYEES_DEPARTMENTS table you can relate multiple employees with a department, and you can relate a single employee with multiple departments.
The business logic requiring that only departments with one or fewer employees can be deleted should not be enforced in a trigger. Business logic should be performed by application code, NEVER by triggers. Putting business logic in triggers is a gatèw̢ay to unending debugging sessions. M̫̣̗̝̫͙a̳͕̮d̖̤̳̙̤n̳̻̖e͍̺̲̼̱̠͉ss̭̩̟ lies this way. Do not give in. Do not surrender. ̬̦B҉usi͢n̴es̡s logic ̶in triggers opens deep wounds in the fabric of the world, through which unholy beings of indeterminate form will cross the barrier between the spheres, carryi͞n̨g o̡f͠f t͢h̶e ̕screaming͡ sou͏ĺs o͜f͜ ̢th͜e̴ ̕de͏v́e̡lop͏e͜r͝s to an et͞er͜n̸it̶y ́of͢ pain̶ ąn̨d͢ ̨to͟r̨ment͟. Do not, as I have said, put b́u͜siness͞ ̸log̛i͘ç ̵in͢ ͞trigge͠rs͞.̡ Be firm. Resist.You must resist. T̷he ̢Tem͟p͞t̶at͏i͝o̶n҉s͘ ̢m͘a̶y ́śing hymns̷ ́o͢f̴ ̸un͘hol̵y r̶ev͢ęla͠t̡ion̴ ͢buţ ́yo͠u̵ mu͏s͝t ͝n͜͏͟o҉t̶͡͏ ̷l̸̛͟͢ì̧̢̨̕s̵̨̨͢t̵̀͞e̶͠n̶̴̵̢̕. Only by standing firmly in the door between the worlds and blocking out the hideous radiance cast off by bú̧s̷i̶̢n̵̕e̵ş͝s ́l̴ó̢g̛͟i̕͏c i͞n̕ ͏t̵͜r͢͝i̸̢̛ģ͟ge̸̶͟r̶s͢͜, which perverts the very form of the world ąnd̴̀͝ ç͞a̧͞l̶l͟͜s̕͘͢ Z̶̴̤̬͈̤̬̲̳͇ͯ̊ͮ͐̒̆͂͠Â̆́̊̓͛́̚͏̮̘̗̻̞̬̱ͅL̛̄̌͏̦͕̤͎̮̦G̷͖̙̬͛̇ͬ̍͒̐̅O̡̳͖͎̯̯͍ͫ̽ͬ͒͂̀ i͜҉nt͝ǫ̴ ̸b̷͞è͢ì̕n̴g͏,̛̀͘ ̴c҉á̴͡ń ̀͠youŕ̨ ̧̨a̸p͏̡͡pl̷͠ic͞a̢t̡i͡҉ǫn̴ ̸s̶͜u̶͢ŗv̛í̴v́ȩ.͘͘ Resist. R͏͢͝e͏͢͟s̸͏͜ì̢̢s͠ţ̀. T̶̀h̨̀e̶r̀͏e͢͞ ̶i̶̡͢s̴ ͞͞n̵͝o̡ ́ẁ҉̴a̡y̕҉ ̶b́͏u̵̶̕t͜ ̨s͘͢t͘͠į͟l͘l̷̴ ̴͜͜ỳò͜u҉̨ ̨͏mus̸͞t̸̛͜ ̧rȩ̴s̢͢i͘͡s͏t̸.̛̀͜ Your very śo͡u̧̧͘ļ͟͡ is compromised by p͝u͘͝t̢͜t͠i̸ņ̸̶g͟͡ ̵̶̛b̴҉u̶̡̨͜͞s̷̵̕͜͢i͝҉̕͢ǹ͏e̡͞ś̸͏ş̕͜͡҉ ̴̨ĺ̵̡͟͜o̶̕g͠i͢͠c̕͝ ̕͞i̧͟͡n̡͘͟ ̶̕͞t̡͏͟҉̕r̸̢̧͡͞i̴̡͏̵͜g̵̴͟͝ģ̴̴̵ę̷̷͢r̢̢ś̸̨̨͜. T̀͜͢o̷͜ny̕ ͟͡T̨h̶̷̕e ̢͟P̛o̴̶n͡y shall rise from his dark stable and d͞ę̡v̶̢ó͟u̸̸r̴͏ ̷t͞h̀e̛ ̨͜s̷o̧͝u҉l̀ ͟͡o͢͏f̵͢ ̛t͢h̶̛e̢̢ ̡̀vi͜͞r̢̀g̶i̢n͞, and yet y͢ơú͝ m̷̧u͏s͡t̡͠ ̛s̷̨t̸̨i̴̸l̶̡l ͝ǹot̵ ͞p̧u̵t̨ ͜͏b̀̕u̕s̨í̵ņ̀͠ȩs̵͟s ́͞l̛҉o̸g̨i̴͟c ͘͘i͘nt̛o͡ ͘͘͞t̶͞r̀̀i̕ǵ̛g̵̨͞e̸͠҉r̵͟ś! It is too much to bear, we cannot stand! Not even the children of light may put business logic into their triggers, for b̴̸̡̨u͜͏̧͝ş̶i̷̸̢̛҉ń̸͟͏́e̡͏͏͏s̷̵̡s̕͟ ͏̴҉͞l̷̡ǫ̷̶͡g҉̨̛i͘͠͏̸̨c̕͢͏ ̸̶̧͢͢i̸̡̛͘n͢͡ ̀͢͝t̷̷̛́ŗì̴̴̢g̶͏̷ǵ͠ȩ̀́r̸̵̢̕͜s͞͏̵ is the very es̵s̕͡ę̢n͞c̨e̢͟ ̴o̶̢͜f͏ ͟d́ar͟͞͠k̡͞n̢̡es̵̛͡s̀̀͡ and dev͘ou͝͡r̨̡̀s͢͝ ҉͝t҉h̴e̡͘ l̫̬i̤͚ͅg̞̲͕̠͇̤̦̹h̩̙̘̭̰͎͉̮̳t͙̤̘̙! Yea, yea, the blank-faced ones rì͢s̨͘e from the f͟͢͏o̵͜͝n̶t̨ ̵o͏f̸̡͠ ͏͝fl͟͞a̵̷҉me̶̵͢ and ca͝s͜t́ down the p̹̤̳̰r̮̦̥̥̞̫͑͂ͤ͑ͮ͒̑ï̄̌ͬͨe̦̗͔ͥͣ̆̾̂s̬̭̮̮̜ͭt̻̲̍sͫͣ̿ ̐͗̈ͤ͂ͦ̅f̭͚̪̻̣̩ͮ̒ṟͨ͌ͮ̅̓ỏ̝͓̝̣̟̼m̳͇̱̝͔͒ ͒ͫͧ͂̓̈̈́t̲̔̅̎͐h̺͈͍ͣͧ̿ē̪̼̪̻͉̪̙̐̽̎̉i̠͎̗͕̗̣̬̐̎͛r͓̫͌ͅ ̼a͑̈ͯͦ̍l̪͉͖̥͚̤͌ͨ͊ͦͤ̔t̫͎̹ͯa̼̻͍̳̟̤̬̓ͪ̀r̭͖̓ͬ̉̉ͤ͊ṡ̐ͪ̊̋̄̅! A̵̵̛v͝é͜ŕt̶͏ ̶y̸͝͠o̶u̧͘r͏̡ ̧e͞y҉e̕͝s,̀ ͡t̛h̛o̢͞ug̸̢h̵͟ ̡y̷o͢҉͢u̧͡ ̕͡c҉̵̶an͠͏n҉o̧͢t!̸̨͘ ͡H̵e̸͢͡ ̧̕c̶ơm̷̢̢e̶͞ś͢!̨́ ̷H̕ȩ ̵c̨̡͟o̴҉m̷͢es͠!̷͘͞ P̱̼̯̟͈h̝̳̞̖͚'͉̙͉̰̲̺n̪̦͕̗͜g͔̹̟̰̰̻̩l̬͈̹̥͕͖ͅụ̻̺̤̤̬̳i̸̯̬̝̻̣͚̫ ̰̹̞̞m͟g̷̝͓͉̤l̩͇̙͕w̪̦̰͔'̮̟̱̀n̢̜a̦f̘̫̤̘̬͓̞h̠͍͖̯ͅ ̩̠͓̯̘̫C̟̘̗̘͘ṭ͍͕ͅh̤ͅu̼̦̘̥ͅl҉̦hu̠̤̤̘͚ ̘̕R̶̟'̠͔̞̻͇l̩̺̗̻͖͓̕ͅy̛̖ȩ͉̭̖ẖ̡̥̼͈̖ w̟̫̮͇͔͞ͅg͈̘̱̻a̰͟h̘͙͖͢'̮̲̯͞n̤̜͍̯̳a͓͓̲̲g̱̻͈ĺ͍ ̷̣̞̲͖͍̲̺f̲ͅh͇͕̪̘͟t͔͈̙a͓͢g҉̳̜̲͚n͓͚͎̱̠̜!
Don't ask me how I know.
Best of luck.

Changing Primary Key in Oracle

I'm updating a table that was originally poorly designed. The table currently has a primary key that is the name of the vendor. This serves as a foreign key to many other tables. This has led to issues with the Vendor name initially being entered incorrectly or with typos that need to be fixed. Since it's the foreign key to relationships, this is more complicated than it's worth.
Current Schema:
Vendor_name(pk) Vendor_contact comments
Desired Schema:
id(pk) Vendor_name Vendor_contact comments
I want to update the primary key to be an auto-generated numeric key. The vendor name field needs to persist but no longer be the key. I'll also need to update the value of the foreign key on other tables and on join tables.
Is the best way to do this to create a new numeric id column on my Vendor table, crosswalk the id to vendor names and add a new foreign key with the new id as the foreign key, drop the foreign key of vendor name on those tables (per this post), and then somehow mark the id as the primary key and unmark the vendor name?
Or is there a more streamlined way of doing this that isn't so broken out?
It's important to note that only 5 users can access this table so I can easily shut them out for a period of time while these updates are made - that's not an issue.
I'm working with SQLDeveloper and Python/Django.
The biggest problem you have is all the application code which references VENDOR_NAME in the dependent tables. Not just using it to join to the parent table, but also relying on it to display the name without joining to VENDOR.
So, although having a natural key as a foreign key is a PITN, changing this situation is likely to generate a whole lot of work, with a marginal overall benefit. Be sure to get buy-in from all the stakeholders before starting out.
The way I would approach it is this:
Do a really thorough impact analysis
Ensure you have complete regression tests for all the functions which rely on the Vendor data
Create VENDOR_ID as a unique key on VENDOR
Add VENDOR_ID to all the dependent tables
Create a second foreign on all the dependent tables referencing VENDOR_ID
Ensure that the VENDOR_ID is populated whenever the VENDOR_NAME is.
That last point can be tackled by either fix the insert and update statements on the dependent tables, or with triggers. Which approach you take will determine on your application design and also the number of tables involved. Obviously you want to avoid the performance hit of all those triggers if you can.
At this point you have an infrastructure which will support the new primary key but which still uses the old one. Why would you want to do this? Because you could go into Production like this without changing the application code. It gives you the option to move the application code to use VENDOR_ID across a broader time frame. Obviously, if developers have been keen on coding SELECT * FROM you will have issues that need addressing immediately.
Once you've fixed all the code you can drop VENDOR_NAME from all the dependent tables, and switch VENDOR_NAME to unique key and VENDOR_ID to primary key on the master table.
If you're on 11g you should check out Edition-Based Redefinition. It's designed to make this sort of exercise an awful lot easier. Find out more.
I would do it this way:
create your new sequence
create table temp as select your_sequence.nextval,vendor_name, vendor_contact, comments from vendor.
rename the original table to something like vendor_old
add the primary key and other constraints to the new table
rename the new table to the old name
Testing is essential and you must ensure no one is working on the database except you when this is done.

Resources