使用SQL更新多对多表

使用SQL更新多对多表,sql,sql-server,many-to-many,Sql,Sql Server,Many To Many,我有一张放动物的桌子 CREATE TABLE Animals ( AnimalId int NOT NULL, Color int NOT NULL, Breed int NOT NULL, Genre int NOT NULL, ); 和一个完全相同的表,但所有内容都是可选的(除了键) 最后是多对多表: CREATE TABLE AnimalsExpenses ( ExpenseId int NOT NULL FOREIGN KEY REFERENCES Expenses(ExpenseI

我有一张放动物的桌子

CREATE TABLE Animals
(
AnimalId int NOT NULL,
Color int NOT NULL,
Breed int NOT NULL,
Genre int NOT NULL,
);
和一个完全相同的表,但所有内容都是可选的(除了键)

最后是多对多表:

CREATE TABLE AnimalsExpenses
(
ExpenseId int NOT NULL FOREIGN KEY REFERENCES Expenses(ExpenseId),
AnimalId int NOT NULL FOREIGN KEY REFERENCES Animals(AnimalId),
);
记录(a,e)应放在表上,如果

((SELECT Color FROM Animals WHERE AnimalId = a) = (SELECT Color FROM Expenses WHERE ExpenseId = e)
OR (NULL) = (SELECT Color FROM Expenses WHERE ExpenseId = e))
AND
((SELECT Breed FROM Animals WHERE AnimalId = a) = (SELECT Breed FROM Expenses WHERE ExpenseId = e)
OR (NULL) = (SELECT Breed FROM Expenses WHERE ExpenseId = e))
AND
((SELECT Genre FROM Animals WHERE AnimalId = a) = (SELECT Genre FROM Expenses WHERE ExpenseId = e)
OR (NULL) = (SELECT Genre FROM Expenses WHERE ExpenseId = e))
…怎么会是一个更新动物费用的查询?也就是说:它删除不应该在n-m表中的记录,并添加需要在那里的记录

例如:

------ Animals -------------------
 AnimalId  Color  Breed  Genre
----------------------------------
     1      1       1      1
     2      1       1      2
     3      1       2      2

----- Expenses -------------------
 ExpenseId  Color  Breed  Genre
----------------------------------
     1       NULL   NULL   NULL      (applies to every animal)
     2       NULL    2     NULL      (applies to animals of breed 2)
     3         1     2      2        (applies exactly to animal 3)

----- AnimalsExpenses -------------------------------------------
  AnimalId   ExpenseId   Is it ok?
-----------------------------------------------------------------
      1        1         yes, because "expense 1" applies to all
      2        1         yes, because "expense 1" applies to all
      3        1         yes, because "expense 1" applies to all

      1        2         no, breed doesnt match
      2        2         no, breed doesnt match
      3        2         yes, because "expense 2" matches breed with "animal 3"

      1        3         no, breed and genre doesnt match
      2        3         no, breed doesnt match
      3        3         yes, everything matches

为什么不直接截断表,然后运行

Insert into AnimalsExpenses
select a.AnimalId
  , e.ExpenseId
  from Animals a
  inner join Expenses e on a.Breed = ISNULL(e.Breed, a.Breed) 
          AND a.Color = ISNULL(e.Color, a.Color) 
          AND a.Genre = ISNULL(e.Genre, a.Genre) 

我建议您以这种方式重写
WHERE
标准:

ISNULL(Expenses.Color, Animals.Color) = Animals.Color
AND ISNULL(Expenses.Breed, Animals.Breed) = Animals.Breed
AND ISNULL(Expenses.Genre, Animals.Genre) = Animals.Genre

再看看
COALESCE

您使用的是哪家SQL供应商?我可能会在应用程序层而不是在database.SQL服务器中强制执行此操作。我使用LINQ/Entity Framework进行了此更新,但速度太慢了。您是否可以包含一些示例数据,并向我们展示一个允许和禁止的条目是什么样子?我已经给出了一个示例。您的逻辑是,
Animals
表的所有列都具有相同的值,还是品种匹配?否则会丢弃记录吗?解释“应用于所有”的含义。Truncate表示删除所有行?我会试试。。。听起来是个好答案。它在1000只动物和20个开支(aprox)情况下的性能如何?@sports Truncate意味着删除所有行,这是一个命令。应该不会太糟糕。顺便说一下,我更新了答案,ORs需要更新
ISNULL(Expenses.Color, Animals.Color) = Animals.Color
AND ISNULL(Expenses.Breed, Animals.Breed) = Animals.Breed
AND ISNULL(Expenses.Genre, Animals.Genre) = Animals.Genre