Limit same data entries - sql

Im new to sql and i have two tables, one for fridges and one for food. Only 5 items of food can be stored into one fridge, so i was wondering if there is a way to limit the food table to only have 5 of the same fridge_id entries?

There is no straightforward way to enforce such a constraint.
The best I can think of is:
have a (redundant) column food_count on the fridges table
define an AFTER INSERT OR UPDATE OR DELETE trigger on the food table that updates food_count whenever something changes
add a check constraint on the fridges table that limits food_count to 5

Related

How to implement cascading deletes in one -> many *from the many side*

I have a use case where multiple rows in table A are aggregated down to a single row in table B. We represent the origin of rows in table B with a foreign key column in table A, saying "as a row, I contributed to X row in table B".
We want to find the best solution so that once every row from table A which contributed to table B has been deleted, deleted the row in table B as an orphan.
I'm not sure if there's some way to use ON DELETE CASCADE to handle this. But I'm guessing not and that maybe triggers are the best option.
I can't just purge all orphans on a schedule because the changes need to be persisted very soon after occurring.
Using the given schema, what our best option? Alternatively, is there some other schema that better sets us up for the scenario I gave?

How do I add a primary key to a column that may contain null or empty values?

Background info:
Table A has 100 rows in it representing inventory on a shelf. I want to make column boxCode a primary key but I can't because the empty rows all have boxCode of empty string.
Table B has a variable amount of rows based on the actual inventory. I want to make column boxCode a foreign key linked to Table A.
Problem:
Currently I perform 2 SQL queries to make the above operations occur but the action isn't atomic. I update table A followed by updating table B but there is a small period of time where the tables information is out of sync with each other. This is causing issues with our API. Is there a way in SQL to add or delete rows from Table B when I UPDATE Table A? I can guarantee I only ever UPDATE Table A if that makes a difference.

Postgresql Locking Rows on a Key/Foreign Key

I'm using postgresql. I have 3 tables.
Table A has an ID column that's a Primary Key
Table B and Table C have ID columns that are foreign key references to A's ID.
In a single process, I would like to lock any rows that have a particular ID and then possibly delete rows and insert rows with that ID in B and C
My current approach is
SELECT FOR UPDATE on A on the ID.
Then I try to delete and insert rows in B and C.
commit/end
Unfortunately, my code deadlocks trying to do the insert.
What am I doing wrong? What is the proper way to prevent other processes from adding, removing, or updating rows with a given ID in B and C (until I am done with my transaction)?
Thanks in advance!
It looks I was doing things correctly from the start. My issue was that I was accidentally creating two different database connections in my code. So, from postgresql's perspective, there were two different transactions - hence the deadlocking.

Incremental load for Updates into Warehouse

I am planning for an incremental load into warehouse (especially for updates of source tables in RDBMS).
Capturing the updated rows in staging tables from RDBMS based the updates datetime. But how do I determine which column of a particular row needs to be updated in the target warehouse tables?
Or do I just delete a particular row in the warehouse table (based on the primary key of the row in staging table) and insert the new updated row?
Which is the best way to implement the incremental load between the RDBMS and Warehouse using PL/SQL and SQL coding?
In my opinion, the easiest way to accomplish this is as follows:
Create a stage table identical to your host table. When you do your incremental/net-change load, load all changed records into this table (based on whatever your "last updated" field is)
Delete the records from your actual table based on the primary key. For example, if your primary key is customer, part, the query might look like this:
delete from main_table m
where exists (
select null
from stage_table s
where
m.customer = s.customer and
m.part = s.part
);
Insert the records from the stage to the main table.
You could also do an update existing records / insert new records, but either way that's two steps. The advantage of the method I listed is that it will work even if your tables have partitions and the newly updated data violates one of the original partition rules, whereas an update would not accomplish that. Also, the syntax is much simpler as your update would have to list every single field, whereas the delete from / insert into allows you list only the primary key fields.
Oracle also has a merge clause that will update if it exists or insert if it does not. I honestly don't know how that would be impacted if you had partitions.
One major caveat. If your updates include deletes -- records that need to be deleted from the main table, none of these will resolve that and you will need some other way to handle that. It may not be necessary, depending on your circumstances, but it's something to consider.

Oracle SQL merge tables without specifying columns

I have a table people with less than 100,000 records and I have taken a backup of this table using the following:
create table people_backup as select * from people
I add some new records to my people table over time, but eventually I want to merge the records from my backup table into people. Unfortunately I cannot simply DROP my table as my new records will be lost!
So I want to update the records in my people table using the records from people_backup, based on their primary key id and I have found 2 ways to do this:
MERGE the tables together
use some sort of fancy correlated update
Great! However, both of these methods use SET and make me specify what columns I want to update. Unfortunately I am lazy and the structure of people may change over time and while my CTAS statement doesn't need to be updated, my update/merge script will need changes, which feels like unnecessary work for me.
Is there a way merge entire rows without having to specify columns? I see here that not specifying columns during an INSERT will direct SQL to insert values by order, can the same methodology be applied here, is this safe?
NB: The structure of the table will not change between backups
Given that your table is small, you could simply
DELETE FROM table t
WHERE EXISTS( SELECT 1
FROM backup b
WHERE t.key = b.key );
INSERT INTO table
SELECT *
FROM backup;
That is slow and not particularly elegant (particularly if most of the data from the backup hasn't changed) but assuming the columns in the two tables match, it does allow you to not list out the columns. Personally, I'd much prefer writing out the column names (presumably those don't change all that often) so that I could do an update.