Looking for a way to write the following LinQ to entities query as a T-SQL statement.
repository.ProductShells.Where(x => x.ShellMembers.Any(sm => sm.ProductID == pid)).ToList().ForEach(x => repository.ProductShells.Remove(x));
The below is obviously not correct but I need it to delete respective ProductShell object where
any ShellMember contains a ProductID equal to the passed in variable pid. I would presume this would involve a join statement to get the relevant ShellMembers.
repository.Database.ExecuteSqlCommand("FROM Shellmembers WHERE ProductID={0} DELETE FK_ProductShell", pid);
I have cascade delete enabled for the FK_ShellMembers_ProductShells foreign key, so when I delete the ProductShell it will delete all the ShellMembers that are associated with it. I am going to pass this statement to System.Data.Entity Database.ExecuteSqlCommand method.
You should always show table structures and foreign key linkages.
However, it should look something like this.
This assumes the link between the two tables is productshell.shellid=shellmembers.shellid
delete productshell
where shellid in (
select shellid
from shellmembers
where productid={0}
)
It can also be written as a join
delete productshell
from productshell
join shellmembers on productshell.shellid=shellmembers.shellid
where shellmembers.productid={0}
Related
When I tried to delete something in my DB2, this message appeared:
-532 THE RELATIONSHIP constraint-name RESTRICTS THE DELETION OF ROW WITH RID X rid-number
What does this error mean and how can I resolve it?
What is the correct way to delete from my DB2? This is how I'm doing it now:
DELETE FROM LN_WIP WHERE NUM IN (500018605, 500018605, 500018605 ); –
Yep, you are most likely trying to delete a parent row, that has children rows. Please read IBM Error Codes.
There is a foreign key relationship that is preventing the deletion of the parent row.
To find out which FK is preventing you from deleting the row, first you can list all the exported foreign keys in that table:
select
substr(tabname,1,20) table_name,
substr(constname,1,20) fk_name,
substr(REFTABNAME,1,12) parent_table,
substr(refkeyname,1,20) pk_orig_table,
fk_colnames
from syscat.references where reftabname = 'LN_WIP';
Please post the result of this query. One of these is the culprit FK.
I have version logic in tables. So, each table contains 'is_deleted' and 'version' fields. ('version' field is referenced to single table with all versions)
table1(id, field1_1, field1_2, is_deleted, version[fk to versions.id])
table2(id, field2_1, field2_2, table1_id, is_deleted, version[fk to versions.id])
versions(id, main_version)
When I get records from db I use where clause for each of referenced table and for table itself. Something like:
SELECT * FROM table1 AS t1
WHERE (
(
(t1.id, t1."version") IN
(SELECT sub_t1.id, max(sub_t1."version") FROM table AS sub_t1 GROUP by sub_t1.id)
)
AND t1.is_deleted IS FALSE
)
For MySQL you can change condition for 'is_deleted' to
is_deleted = 0
Now, I'm adding new tables and I want to use foreign keys, but foreign key can reference only unique column, but id is not unique (it is kept through versions) and I can't use complex key, because new version created only when smth changed and only for that record.
Should I omit FK or should I add additional table with only one column id for each of versioned tables? Will adding such tables offer some benefit except for data integrity? Adding such tables will make logic more complicated.
So, should I live it untouched or make smth like this:
table1_ids(id)
table1_versions(id, table1_id[fk to table1_ids.id], ...)
table2_versions(id, ..., table1_id[fk to table1_ids.id],...)
table2_ids(id)
Can you rather create schema for every version ?
It will be much more clean solution.
I'm trying to use set up a database for a school project, and I'm using triggers to set up referential integrity for one table. I have a table, Addresses, which stores the address for People, Studios, and Directors. Then I have a table called Address Reference. This table points to the Address table, and it has a two fields, the ReferenceID and the TableName to show which table and row this address is for. I have a Constraint so TableName will always be valid.
I'm trying to set up a trigger to make sure any rows inserted are valid, which I can do, I'm just trying to improve it. My code would look like this:
SELECT *
FROM inserted
WHERE ReferenceID IN
(SELECT PersonID
FROM inserted.TableName)
However I found I needed to use dynamic sql. So I was thinking something like this:
SELECT *
FROM inserted
WHERE ReferenceID IN
(EXEC('SELECT PersonID FROM' + inserted.TableName))
Which didn't work, even when I removed the exec.
I'm doing this in SQL Server Management Studio With SQL Server 11.0.3128
Let me know if you need any more information. I've looked around, and I haven't found any answers to this question that work.
This is a poor way to maintain referential integrity. There are a number of ways you could approach this.
The first would be to have an address table, then multiple tables to contain the links, e.g.
CREATE TABLE StudioAddress
( StudioID INT NOT NULL,
AddressID INT NOT NULL,
CONSTRAINT PK_StudioAddress__StudioID_AddressID PRIMARY KEY (StudioID, AddressID),
CONSTRAINT FK_StudioAddress__StudioID FOREIGN KEY (StudioID) REFERENCES Studio (StudioID),
CONSTRAINT FK_StudioAddress__AddressID FOREIGN KEY (AddressID) REFERENCES Address (AddressID)
);
This maintains your referenctial integrity without needing triggers, and still caters for a 1 to many relationship.
Another option would be to have 3 nullable columns in your address table (StudioID, PersonID, DirectorID), each with a foreign key to the relevant table, you can the add a check constraint to ensure only one of the 3 fields is populated (if this is required).
I much prefer the first option though, it is much cleaner, and also allows for the same address to be used for multiple things.
ADENDUM
If this has to be done using triggers, then I think you would need to use something like this:
IF EXISTS( SELECT 1
FROM inserted i
WHERE NOT EXISTS
( SELECT 1
FROM People p
WHERE p.PersonID = i.ReferenceID
AND i.TableName = 'People'
UNION ALL
SELECT 1
FROM Studios s
WHERE s.StudioID = i.ReferenceID
AND i.TableName = 'Studios'
UNION ALL
SELECT 1
FROM Directors d
WHERE d.DirectorID = i.ReferenceID
AND i.TableName = 'Directors'
)
)
BEGIN
ROLLBACK TRANSACTION;
RAISERROR('Referential integrity error', 16, 1);
END
This essentially checks that for all inserted/updated rows a record exists with the relevant ID in the relevant table.
I still stand by my earlier answer though, that this is a terrible approach, and I would question any syllabus this is on!
So I have two tables:
Bookmarks has a few columns [id, etc.]
Person_Bookmark has 2 columns [personId, bookmarkId]
Bookmarks represents links to other websites. All valid bookmarks have an id. The Person_Bookmark table has a bunch of personIds and their bookmarks, shown as bookmarkId.
Here's my pseudocode:
> let x = integer list of all bookmarkId's from Person_Bookmark
>
> for each x {
> if ('select * from 'Bookmarks' where 'id' = x returns 0 rows) {
> delete from 'person_bookmark' where 'bookmarkId' = x
> }
> }
Please advise me how to convert to a Postgres [edit] SQL script.
#Jan mentioned foreign keys already, but his advice is incomplete.
Seems like you want to delete all associations to a bookmark that does not exist (any more).
Define a foreign key constraint in the form of:
ALTER TABLE person_bookmarks
ADD CONSTRAINT pb_fk FOREIGN KEY (bookmarkid) REFERENCES bookmarks (id)
ON UPDATE CASCADE
ON DELETE CASCADE;
This only allows values in person_bookmarks.bookmarkid that exist in bookmarks.id.
ON UPDATE CASCADE changes corresponding values in person_bookmarks.bookmarkid when you change an entry in bookmarks.id
ON DELETE CASCADE deletes corresponding rows in person_bookmarks.bookmarkid when you change an entry in bookmarks.id.
Other options are available, read the manual.
The ON DELETE CASCADE clause does automatically, what you are trying to fix manually. Before you can add the fk constraint you'll have to fix it manually once:
DELETE FROM person_bookmarks pb
WHERE NOT EXISTS (SELECT 1 FROM bookmarks b WHERE b.id = pb.bookmarkid);
-- OR NOT EXISTS (SELECT 1 FROM persons p WHERE p.id = pb.personid);
Deletes all rows with non-existing bookmarkid. Uncomment the last line to get rid of dead persons, too.
This works in SQL Server - not sure about MySQL...
delete pb
from
person_bookmark pb
where not exists (select 1 from booksmarks b where b.id = pb.bookmarkid)
Another version of #Derek's reply:
DELETE FROM person_bookmark
WHERE bookmarkid NOT IN (SELECT id FROM bookmarks)
The need to do this implies that you have no foreign key indexes between your tables. I strongly advise you to do so. The drawback (or feature) lies in that when you for example delete a person (I'm guessing this table exists from your example), you have to delete all associated data first, otherwise the server will throw an error.
Something like this:
DELETE FROM person_Bookmark WHERE personid = #personid
DELETE FROM person_SomeOtherTable WHERE personid = #personid
DELETE FROM person WHERE id = #personid
The advantage though is that you'll have no orphan rows in your database, and you can't enter erroneous data by mistake (store a bookmark for a person that doesn't exist).
Assuming that all foreign keys have the appropriate constraint, is there a simple SQL statement to delete rows not referenced anywhere in the DB?
Something as simple as delete from the_table that simply skip any rows with child record?
I'm trying to avoid manually looping through the table or adding something like where the_SK not in (a,b,c,d).
You might be able to use the extended DELETE statement in 10g that includes error logging.
First use DBMS_ERRLOG to create a logging table (which is just a copy of the original table with some additional prefixing columns: ORA_ERR_MESG$, ..., ORA_ERR_TAG$)
execute dbms_errlog.create_error_log('parent', 'parent_errlog');
Now, you can use the LOG ERRORS clause of the delete statement to capture all rows that have existing integrity constraints:
delete from parent
log errors into parent_errlog ('holding-breath')
reject limit unlimited;
In this case the "holding-breath" comment will go into the ORA_ERR_TAG$ column.
You can read the full documentation here.
If the parent table is huge and you're only looking to delete a few stray rows, you'll end up with a parent_errlog table that is essentially a duplicate of your parent table. If this isn't ok, you'll have to do it the long way:
Directly reference the child tables (following Tony's solution), or,
Loop through the table in PL/SQL and catch any exceptions (following Confusion's and Bob's solutions).
The easiest way may be to write an application or stored procedure that attempts to delete the rows in the table one-by-one and simply ignores the failures due to foreign key constraints. Afterwards, all rows not under a foreign key constraint should be removed. Depending on the required/possible performance, this may be an option.
No. Obviously you can do this (but I realise you would rather not):
delete parent
where not exists (select null from child1 where child1.parent_id = parent.parent_id)
and not exists (select null from child2 where child2.parent_id = parent.parent_id)
...
and not exists (select null from childn where childn.parent_id = parent.parent_id);
One way to do this is to write something like the following:
eForeign_key_violation EXCEPTION;
PRAGMA EXCEPTION_INIT(eForeign_key_violation, -2292);
FOR aRow IN (SELECT primary_key_field FROM A_TABLE) LOOP
BEGIN
DELETE FROM A_TABLE A
WHERE A.PRIMARY_KEY_FIELD = aRow.PRIMARY_KEY_FIELD;
EXCEPTION
WHEN eForeign_key_violation THEN
NULL; -- ignore the error
END;
END LOOP;
If a child row exists the DELETE will fail and no rows will be deleted, and you can proceed to your next key.
Note that if your table is large this may take quite a while.