I have to delete a product and its images. Images are in seperate table and productId is acting as foreign key.
Here is the single queries to do so.
string deleteImages = #"DELETE FROM [ProductsImages] WHERE ProductId IN (SELECT ProductId FROM [Products] WHERE ProductId = #ProductId)";
string deleteProduct = #"DELETE FROM [Products] WHERE ProductId = #ProductId";
db.ExecuteNonQuery(deleteImages);
db.ExecuteNonQuery(deleteProduct);
I am not getting the way to avoid writing 2 different queries, Is there any help to delete cascade without alter command?
This is something you can define in the database. Just define the foreign key relationship between Products and ProductsImages as "ON DELETE CASCADE". Deleting the product will then automatically delete all associated ProductImages.
If you don't want to change the index, you can avoid two round trips by performing multiple operations in one command:
string deleteStuff = #"
DELETE FROM [ProductsImages] WHERE ProductId = #ProductId;
DELETE FROM [Products] WHERE ProductId = #ProductId;"
db.ExecuteNonQuery(deleteStuff);
DELETE p.*, i.*
FROM Products p
LEFT JOIN ProductImages i ON p.ProductId = i.ProductId
WHERE p.ProductId = #ProductId
EDIT
Not supported by SQL Server
Related
I have this line of code as my query in C#:
cmd.CommandText = "SELECT *
FROM product
LEFT JOIN category ON product.category_id = category.id
WHERE product.id = #productId";
The product table has a column called name which I need.
This is the line I use in my application to retrieve it.
product.ProductName = reader.GetString(reader.GetOrdinal("\"product\".\"name\""));
The error I'm getting is
System.IndexOutOfRangeException: Field not found
on that line.
reader.GetOrdinal("name");
Firstly the resultset does not have a field named "product"."name", but rather one named "name". Consider that if you were to try to select from that resultset within PostgreSQL it would be the same case:
SELECT "product"."name" FROM
(SELECT *
FROM product
LEFT JOIN category ON product.category_id = category.id
WHERE product.id = #productId) subquery
Doesn't work, but:
SELECT "name" FROM
(SELECT *
FROM product
LEFT JOIN category ON product.category_id = category.id
WHERE product.id = #productId) subquery
Does.
Secondly, don't use the PostgreSQL escaping on the name of the field.
I have 7 tables and each table will contain an entry for a particular product.I want to check whether all 7 tables contains entry for a particular ID(eg: 4562). ie, data exists or not.I am using SQL server 2008.Please help me to write a query to check the status.
Try the following command (example for 3 tables T1,T2,T3). It returns 1 if ID = 4562 exists in ALL tables and 0 if at least one table miss this ID.
SELECT
CASE WHEN
(
EXISTS(SELECT ID FROM T1 WHERE ID=4562)
AND EXISTS(SELECT ID FROM T2 WHERE ID=4562)
AND EXISTS(SELECT ID FROM T3 WHERE ID=4562)
)
THEN 1
ELSE 0
END AS [ID_Exists_in_all_tables]
SQLFiddle demo
If you do a basic join rather than left join, the product will only appear if it's in all of the tables.
select * from tab1
join tab2 on tab2.id = tab1.id
join tab3 on tab3.id = tab1.id
join tab4 on tab4.id = tab1.id
join tab5 on tab5.id = tab1.id
Where tab1.id = 1234
etc etc
Using Entity Framework, how do you tell if Delete Cascade is enabled for a table, before removing any records from it?
public partial class DataContext : DbContext
{
public DbSet<Building> Buildings { get; set; }
public DbSet<Room> Rooms { get; set; }
}
DataContext context;
Building building;
// Will this start a DELETE CASCADE, removing Rooms within the Building?
context.Buildings.Remove(building);
This is for a generic function, so I can use DbSet<T> or DbContext but not T.
Need to do the test at runtime, just before the call to Remove().
Can you detect a DELETE CASCADE before doing the delete, and if so, how?
You could pretty easily use a t-sql function or query that gives you the information you're after. Try wrapping the following with whatever predicates you want (e.g. WHERE PK.TABLE_NAME = 'My Table' AND C.DELETE_RULE = 'CASCADE'. If a record a exists, then you've got the information you need.
SELECT
FK_TableName = FK.TABLE_SCHEMA + '.' + FK.TABLE_NAME,
FK_ColumnName = CU.COLUMN_NAME,
PK_TableName = PK.TABLE_SCHEMA + '.' + PK.TABLE_NAME,
PK_ColumnName = PT.COLUMN_NAME,
ConstraintName = C.CONSTRAINT_NAME,
DeleteRule = C.DELETE_RULE
FROM
INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS C
INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS FK
ON C.CONSTRAINT_NAME = FK.CONSTRAINT_NAME
INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS PK
ON C.UNIQUE_CONSTRAINT_NAME = PK.CONSTRAINT_NAME
INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE CU
ON C.CONSTRAINT_NAME = CU.CONSTRAINT_NAME
INNER JOIN (
SELECT
i1.TABLE_NAME,
i2.COLUMN_NAME
FROM
INFORMATION_SCHEMA.TABLE_CONSTRAINTS i1
INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE i2
ON i1.CONSTRAINT_NAME = i2.CONSTRAINT_NAME
WHERE
i1.CONSTRAINT_TYPE = 'PRIMARY KEY'
) PT ON PT.TABLE_NAME = PK.TABLE_NAME;
You could then wrap that into a DbSet extension and call it like context.Set<MyEntity>().UsesCascadeDelete() which fires the above query with your predicates and whatever else you want.
Because EF can run TSQL queries very easily I would still consider them a 'part' of EF.
Would 'Read FK Metadata' or 'Check an entity for FK usage' be helpful? It seems there are a couple of ways to try, though I have not tried either.
I usually check manually in the mappings files and code repositories with that knowledge in mind. Maybe the previous Stackoverflow answers will enable you to create something more generic if you need.
There are two tables:
Table1 : UserID Name Job
Table2 : BookID Book Car UserID
I load these two tables in one wpf datagrid:
da.SelectCommand = new SqlCommand("select Table1.UserID, Table1.Name, Table1.Job, Table2.Book, Table2.Car from Table1 inner join Table2 on Table1.UserID = Table2.UserID");
I want to delete one row from Table2 by DataGrid:
SqlCommand com = new SqlCommand("delete from Table2 where BookID=#BookID)",con);
but not work,
How can I do it?
You say "It must delete a book from a certain user not all books.".
You have to know user id for which the books must be delete.
If you want to delete users books, do this:
delete from Table2 where userid in (user_id1,user_id1, etc .....);
But you are large rows to delete, use bulk delete mechanism.
If you don't have user ids and have book ids, you have to do this:
Delete From Table2 where bookid in (book_id1,book_id2, etc ..);
Or Delete From Table2 where bookid =? //according your development language, you set "?" parameter. I don't know C# syntaxe.
You have to use the below way to delete the rows
DELETE FROM table2
WHERE userid = (SELECT userid
FROM table1);
Are you expecting something like this?
DELETE FROM B WHERE BOOKID IN (SELECT BOOKID FROM B,A WHERE B.USERID=A.USERID AND B.BOOK='ABCD');
I've ran into an issue when trying to do multi-mapping using Dapper, for pagination queries.
Because I am using a nested query in this pagination scenario, there are multiple tables within the nested query that I must join to get my multi-mapped data, but some of these tables will share some fields of the same name which you can see in my example query below (e.g. id, displayname and email):
q = #"select * from (select p.id, p.title, p.etc...,
u1.id, u1.displayname, u1.email,
u2.id, u2.displayname, u2.email,
t.id, t.name,
row_number() over (order by " + sort.ToPostSortSqlClause() + ") as rownum" +
" from posts p" +
" join users u1 on p.owneruserid = u1.id" +
" join users u2 on p.lastediteduserid = u2.id" +
" join topics t on p.topicid = t.id" +
") seq where seq.rownum between #pLower and #pUpper";
In the example above you can see that within the nested query, there are going to be problems with the fields id (appears in the posts table, both users table joins and the topics table join), and also displayname and email (appear in both users table joins).
The only workaround I have thought of so far involves casting each of these 'problem' fields as a different name, but this then involves the very messy process of creating dummy properties in the affected models, so multimapping can map into these, and editing the 'real' properties in my models to also check the dummy property for a value if the real value has not been set.
Also, in the above scenario I would have to create x dummy properties where x is the number of joins I may have on the same table within a query (in this example, 2 joins on the same Users table, therefore requiring 2 uniquely named dummy properties just for Dapper mapping purposes).
This is obviously not ideal and I'm sure would have knock on problems and more untidyness as I created more of these multi-mapping pagination queries.
I'm hoping there is nice, clean solution to this problem?
There are 2 options I can think of:
option 1: join back to your extended properties outside of your nested query:
select s.*, t1.*, t2.* from
(
select s.*, ROW_NUMBER() OVER (order by somecol) AS RowNumber from Something s
) as X
left join Table t1 on Id = x.SomeId
left join Table t2 on Id = x.SomeOtherId
option 2: Extend SqlBuilder to handle column aliasing:
select s.*, /**unalias(Table,t1)**/, /**unalias(Table,t2)**/ from
(
select s.*, /**alias(Table,t1)**/, /**alias(Table,t2)**/ ROW_NUMBER() OVER (order by somecol) AS RowNumber from Something s
left join Table t1 on Id = x.SomeId
left join Table t2 on Id = x.SomeOtherId
) as X
Then define the alias macro to query and cache a list of columns from the db using INFORMATION_SCHEMA.COLUMNS and simply add a 'column as column_t1` string for each column.
Unalias can do the reverse quite simply.