Oracle Delete and Insert - sql

I want to update the categories linked to a row. A row can be linked to multiple categories. To visually represent this, please take a look at the following simplified scenarios:
Object Table
id name
----------
1 Chair
2 Computer
Category Table
id category
--------------
90 Asset
100 Furniture
200 Electronics
300 Garbage
Linking Table
obj cat
---------
1 90
1 100
2 90
2 200
So I have those values in the database right now. But now I decided to update the Chair record to be both 100 | Furniture and 300 | Garbage.
How do I go about doing this efficiently? I know I can delete all of the associated links, then add the new links but there must be a more efficient way for me to do this.

There are a couple of different options you could take:
Update the existing rows if the number of rows in the Linking Table isn't changing. In this case, you could update the row with 1 90 to be 1 300. The challenge here is ensuring the number of rows to remove is equal to the number you plan on inserting.
Delete the ones no longer valid and insert new ones for the rows missing. Note that in this case, the 1 100 row would still stay intact just like the first case though this doesn't have the requirement of the # of rows to delete = # of rows to insert.
Nuke n Pave would be what you initially suggest of deleting all the data and starting over again that could be overkill.

Related

Handling CustomField Insert - Which option is efficient and easier to maintain

We have the following Table structure:
User Table
UserId CompanyId FullName Email
1 1 Alex alex#alex.com
2 1 Sam sam#sam.com
3 2 Rohit rohit#rohit.com
CustomField Table
CustomFieldId CompanyId Name Type
1 1 DOB Datetime
2 1 CompanySize Number
3 2 LandingPage Text
CustomFieldValue Table
UserId CustomFieldId DatetimeValue NumberValue TextValue
1 2 01-01-2020
1 2 10
1 3 Home
2 1
2 2 20
2 3 Product
Please consider the following facts:
There are millions of users in a particular CompanyId
When displaying a particular user in the UI we need to show all the Custom Fields that an end customer can fill up.
How to handle CustomFieldValues table in this case? We are considering the following options
When a new CustomField row is created for a particular CompanyId have a After Insert Trigger to create all corresponding rows in CustomFieldValue table for all users.
This I think would have an initial cost of creating so many rows for each Custom Field in the CustomFieldValue Table. (This may also lock up the table and users of the application would have to wait till all the inserts are done).
Same issue for deleting all CustomFieldValue rows when a CustomField row is deleted from a Company
But easier for UI and backend developers as they don't need to worry about whether a CustomFieldValue doesn't have an entry for a Custom Field that has been created for a Company
Don't create CustomFieldValue rows when a CustomField is added to the Company. Create the CustomFieldValue whenever user fills up the relevant input field in the UI view
This would have negligible insert cost and users would not have to wait for insert or delete to complete in CustomFieldValue table for all the users in a particular company.
The downside is that developers would have to make sure that relevant CustomFields are displayed in the frontend even though no relevant records yet exist in the CustomFieldValue table.
On each Custom Field input update by the end user, the developers would have to first check if a corresponding CustomFieldValue row exits, if so - store the updated value, if not - create the CustomFieldValue row.
Kindly suggest a solution which is efficient and easier to maintain.

deleting from two tables in single script in sql

I have three tables xx_1 , xx_2, xx_3 such that :
xx_1
id obj_version_num location
1 x ubudu
2 x bali
3 x india
xx_2
id name grade
1 abc band 1
2 xyz band 2
3 gdgd band 3
xx_3 has :
Name details col1 p_id
abc A HDHD 10
xyz B HDHD 20
gdgd C HDHD 30
smith D HDHD 40
I want to delete data from xx_1 and xx_2 if the name is smith in xx_3
Currently i am doing :
delete from xx_1
where id in (select distinct id from xx_2 t ,xx_3 k
where t.name=k.name
and k.name ='Smith')
and then
delete from xx_2
where name ='Smith'
Is there anyway i can delete data from both these table together ? without creating two separate scripts ?
There is no way to delete from many tables with a single statement, but the better question is why do you need to delete from all tables at the same time? It sounds to me like you don't fully understand how transactions work in Oracle.
Lets say you login and delete a row from table 1, but do not commit. As far as all other sessions are concerned, that row has not been deleted. If you open another connection and query for the row, it will still be there.
Then you delete from tables 2, 3 and then 4 in turn. You still have not committed the transaction, so all other sessions on the database can still see the deleted rows.
Then you commit.
All at the same time, the other sessions will no longer see the rows you deleted from the 4 tables, even though you did the deletes in 4 separate statements.
EDIT after edit in question:
You can define the foreign keys on the 3 child tables to "ON DELETE CASCADE". Then when you delete from the parent table, all associated rows from the 3 child tables are also deleted.
You cannot delete from multiple tables in a single statement, primary key or not.

SQL Server "pseudo/synthetic" composite Id(key)

Sorry but I don't know how to call in the Title what I need.
I want to create an unique key where each two digits of the number identify other table PK. Lets say I have below Pks in this 3 tables:
Id Company Id Area Id Role
1 Abc 1 HR 1 Assistant
2 Xyz 2 Financial 2 Manager
3 Qwe 3 Sales 3 VP
Now I need to insert values in other table, I know that I may do in 3 columns and create a Composite Key to reach integrity and uniqueness as below:
Id_Company Id_Area Id_Role ...Other_Columns.....
1 2 1
1 1 2
2 2 2
3 3 3
But I was thinking in create a single column where each X digites identify each FK. So the above table 3 first columns become like below (suposing each digit in an FK)
Id ...Other_Columns.....
121
112
222
333
I don't know how to call it and even if it's stupid but it makes sense for me, where I can select for a single column and in case of need some join I just need to split number each X digits by my definition.
It's called a "smart", "intelligent" or "concatenated" key. It's a bad idea. It is fragile, leads to update problems and impedes the DBMS. The DBMS and query language are designed for you to describe your application via base tables in a straightforward way. Use them as they were intended.

How to merge two identical database data to one?

Two customers are going to merge. They are both using my application, with their own database. About a few weeks they are merging (they become one organisation). So they want to have all the data in 1 database.
So the two database structures are identical. The problem is with the data. For example, I have Table Locations and persons (these are just two tables of 50):
Database 1:
Locations:
Id Name Adress etc....
1 Location 1
2 Location 2
Persons:
Id LocationId Name etc...
1 1 Alex
2 1 Peter
3 2 Lisa
Database 2:
Locations:
Id Name Adress etc....
1 Location A
2 Location B
Persons:
Id LocationId Name etc...
1 1 Mark
2 2 Ashley
3 1 Ben
We see that person is related to location (column locationId). Note that I have more tables that is referring to the location table and persons table.
The databases contains their own locations and persons, but the Id's can be the same. In case, when I want to import everything to DB2 then the locations of DB1 should be inserted to DB2 with the ids 3 and 4. The the persons from DB1 should have new Id 4,5,6 and the locations in the person table also has to be changed to the ids 4,5,6.
My solution for this problem is to write a query which handle everything, but I don't know where to begin.
What is the best way (in a query) to renumber the Id fields also having a cascade to the childs? The databases does not containing referential integrity and foreign keys (foreign keys are NOT defined in the database). Creating FKeys and Cascading is not an option.
I'm using sql server 2005.
You say that both customers are using your application, so I assume that it's some kind of "shrink-wrap" software that is used by more customers than just these two, correct?
If yes, adding special columns to the tables or anything like this probably will cause pain in the future, because you either would have to maintain a special version for these two customers that can deal with the additional columns. Or you would have to introduce these columns to your main codebase, which means that all your other customers would get them as well.
I can think of an easier way to do this without changing any of your tables or adding any columns.
In order for this to work, you need to find out the largest ID that exists in both databases together (no matter in which table or in which database it is).
This may require some copy & paste to get a lot of queries that look like this:
select max(id) as maxlocationid from locations
select max(id) as maxpersonid from persons
-- and so on... (one query for each table)
When you find the largest ID after running the query in both databases, take a number that's larger than that ID, and add it to all IDs in all tables in the second database.
It's very important that the number needs to be larger than the largest ID that already exists in both databases!
It's a bit difficult to explain, so here's an example:
Let's say that the largest ID in any table in both databases is 8000.
Then you run some SQL that adds 10000 to every ID in every table in the second database:
update Locations set Id = Id + 10000
update Persons set Id = Id + 10000, LocationId = LocationId + 10000
-- and so on, for each table
The queries are relatively simple, but this is the most work because you have to build a query like this manually for each table in the database, with the correct names of all the ID columns.
After running the query on the second database, the example data from your question will look like this:
Database 1: (exactly like before)
Locations:
Id Name Adress etc....
1 Location 1
2 Location 2
Persons:
Id LocationId Name etc...
1 1 Alex
2 1 Peter
3 2 Lisa
Database 2:
Locations:
Id Name Adress etc....
10001 Location A
10002 Location B
Persons:
Id LocationId Name etc...
10001 10001 Mark
10002 10002 Ashley
10003 10001 Ben
And that's it! Now you can import the data from one database into the other, without getting any primary key violations at all.
If this were my problem, I would probably add some columns to the tables in the database I was going to keep. These would be used to store the pk values from the other db. Then I would insert records from the other tables. For the ones with foreign keys, I would use a known value. Then I would update as required and drop the columns I added.

Insert to particular location in Oracle DB table?

Suppose I have a table containing the following data:
Name | Things
-------------
Foo | 5
Bar | 3
Baz | 8
If I want to insert a row, so that the final state of the table is:
Name | Things
-------------
Foo | 5
Qux | 6
Bar | 3
Baz | 8
Is this possible?
I understand we don't typically rely on the order of rows in a table, but I've inherited some code that does precisely that. If I can insert to a location, I can avoid a significant refactor.
As you say, you can't rely on the order of rows in a table (without an ORDER BY).
I would probably refactor the code anyway - there's a chance it will break with no warning at some point in the future - surely better to deal with it now under controlled circumstances?
I would add a FLOAT column to the table and if you wanted to insert a row between the rows whose value in that column was 7.00000 and 8.000000 respectively, your new row would have value 7.50000. If you then wanted to insert a row between 7.00000 and 7.50000 the new row would get 7.25000, and so on. Then, when you order by that column, you get the columns in the desired order. Fairly easy to retrofit. But not as robust as one likes things to be. You should revoke all update/insert permissions from the table and handle I/O via a stored procedure.