我有以下表结构:
dbo.Owner
OwnerID OwnerName
1 John
2 Marie
3 Alex
和dbo.Pet
PetID PetTag Status OwnerID
1 A341 Active 1
2 A342 Inactive 1
3 A343 Active 2
4 A345 Active 2
我需要归还所有只有活跃宠物或没有宠物的主人。
所以在上面这个例子中,我需要返回所有者2(所有宠物都有效)和所有者3(无宠物)
我将使用Entity Framework在C#中提取数据,但是纯SQL就足够了。
这是我到目前为止所提出的:
select mi.* from Owner o
join Pet p
on o.OwnerID= p.OwnerID
where o.Status='Active'
union select * from Owner
where OwnerID not in (select OwnerID from Pet)
现在,上面的查询有效,但它包含了OwnerID = 1.而且我想知道是否有办法在没有联合的1个查询中执行此操作。
答案 0 :(得分:5)
如果Status
的唯一值为“有效”和“无效”,则实际上可以简化查询。当你说:
我需要归还所有只有活跃宠物或没有宠物的主人。
然后实际转换为:
我需要归还所有没有非活动宠物的主人。
然后您的查询变得更加容易。
在实体框架查询中:
owners = context.Owners
.Where(o => !o.Pets.Any(p => p.Status == "Inactive"))
.ToList();
由此生成的SQL查询是:
SELECT
[Extent1].[OwnerID] AS [OwnerID],
[Extent1].[OwnerName] AS [OwnerName]
FROM [dbo].[Owners] AS [Extent1]
WHERE NOT EXISTS (SELECT
1 AS [C1]
FROM [dbo].[Pets] AS [Extent2]
WHERE ([Extent1].[OwnerID] = [Extent2].[OwnerID]) AND (N'Inactive' = [Extent2].[Status])
)
或者删除杂乱:
SELECT
OwnerID,
OwnerName
FROM Owners o
WHERE NOT EXISTS (SELECT
1
FROM Pets p
WHERE (o.OwnerID = p.OwnerID AND p.Status = 'Inactive')
)
如果您有更多状态值,则可以使用(实体框架):
owners = context.Owners
.Where(o => o.Pets.Any(p => p.Status == "Active") || !o.Pets.Any())
.Where(o => !o.Pets.Any(p => p.Status == "Inactive" /* || p.Status == "Lost" and any other values */))
.ToList();
将生成SQL查询:
SELECT
[Extent1].[OwnerID] AS [OwnerID],
[Extent1].[OwnerName] AS [OwnerName]
FROM [dbo].[Owners] AS [Extent1]
WHERE (( EXISTS (SELECT
1 AS [C1]
FROM [dbo].[Pets] AS [Extent2]
WHERE ([Extent1].[OwnerID] = [Extent2].[OwnerID]) AND (N'Active' = [Extent2].[Status])
)) OR ( NOT EXISTS (SELECT
1 AS [C1]
FROM [dbo].[Pets] AS [Extent3]
WHERE [Extent1].[OwnerID] = [Extent3].[OwnerID]
))) AND ( NOT EXISTS (SELECT
1 AS [C1]
FROM [dbo].[Pets] AS [Extent4]
WHERE ([Extent1].[OwnerID] = [Extent4].[OwnerID]) AND (N'Inactive' = [Extent4].[Status])
))
您需要对性能进行测试,并且可能有更好的方法,但它会提供所需的结果。它确实假设你有外键/导航属性。
答案 1 :(得分:4)
select o.*
from dbo.owner o
where not exists(
select *
from dbo.pet p
where p.ownerid=o.ownerid and
p.status='Inactive'
);
答案 2 :(得分:3)
SELECT OwnerID, OwnerName
FROM Owner
WHERE OwnerID NOT IN (
SELECT OwnerID from Pet
WHERE Status='Inactive'
这个简单的查询可以做到这一点。
OwnerId OwnerName
2 Marie
3 Alex
如果您想选择至少一个ACTIVE或NO PET的所有者,请使用以下查询。
SELECT o.OwnerID o.OwnerName
FROM Owner o
LEFT JOIN Pet p
ON o.OwnerID= p.OwnerID
AND (p.Status='Active'
OR p.OwnerID is NULL)
OwnerId OwnerName
1 John
2 Marie
3 Alex
此查询将返回OWNER名称,直到该所有者的所有宠物都是非活动
现在换另一个案例..
如果您的表有可能在Pets Table中将OwnerId设为NULL。 请使用以下查询。 (MySQL的)
SELECT OwnerID, OwnerName
FROM Owner
WHERE OwnerID NOT IN (
SELECT IFNULL(OwnerID,0) from Pet
WHERE Status='Inactive');
在子查询中添加了IFNULL()。
答案 3 :(得分:2)
有趣的是,可以通过LEFT JOIN执行此操作。我不知道这是否与其他答案建议的NOT EXISTs查询表现不同。
CREATE TABLE [Owner] (
OwnerID int PRIMARY KEY,
OwnerName nvarchar(50)
);
INSERT INTO [Owner]
VALUES
(1, 'John'),
(2, 'Marie'),
(3, 'Alex');
CREATE TABLE Pet (
PetID int PRIMARY KEY,
PetTag nvarchar(10),
Status nvarchar(30),
OwnerID int FOREIGN KEY REFERENCES [Owner](OwnerID)
);
INSERT INTO Pet
VALUES
(1,'A341','Active', 1),
(2,'A342','Inactive', 1),
(3,'A343','Active', 2),
(4,'A345','Active', 2);
SELECT * FROM [Owner];
SELECT * FROM Pet;
SELECT
o.*
FROM
[Owner] o
LEFT JOIN Pet p
ON o.OwnerID = p.OwnerID
AND p.Status <> 'Active'
WHERE
p.OwnerID IS NULL;
DROP TABLE Pet, [Owner];
答案 4 :(得分:1)
select DISTINCT
o.Id
FROM Owner o
LEFT JOIN Pet p ON o.OwnerID= p.OwnerID
where p.Status='Active' OR p.OwnerID IS NULL
答案 5 :(得分:1)
SELECT DISTINCT RESULT FROM (
SELECT CASE WHEN POID is NULL
THEN OID
WHEN OID NOT IN (SELECT DISTINCT
OwnerID from Pet
WHERE Status='Inactive')
THEN OID
END AS RESULT
FROM (
SELECT O.OwnerID as OID, P.OwnerID as POID
FROM Owner o
LEFT JOIN Pet p
ON o.OwnerID= p.OwnerID
) T
)T2 WHERE RESULT IS NOT NULL
答案 6 :(得分:0)
有趣的是,尽管您将其标记为实体框架,但大多数答案都没有提供实体框架为您提供的简化。
Owners
和Pets
之间存在一对多的关系。每个Owner
都有零个或多个Pets
,每个Pet
只属于一个Owner
。
如果您已为one-to-many relationship正确配置了实体框架类,则它们将类似于:
class Owner
{
public int Id {get; set;}
// every Owner has zero or more Pets:
public virtual ICollection<Pet> Pets {get; set;}
... // other properties
}
class Pet
{
public int Id {get; set;}
// every Pet belongs to exactly one Owner, using foreign key:
public int OwnerId {get; set;}
public Owner Owner {get; set;}
}
class MyDbConnection : DbConnection
{
public DbSet<Owner> Owners {get; set;}
public DbSet<Pet> Pets {get; set;}
}
这足以让实体框架认识到您设计了一对多关系。只要需要,实体框架就会为您做正确的连接。
我需要归还所有只有活跃宠物或没有宠物的主人。
这与以下相同:
我需要归还所有没有非活动宠物的主人
(自我注意:没有宠物的主人,肯定没有非活动宠物!)
如果您正确设置了类,则查询将更具可读性。您可以考虑集合,而不是使用ID
相互关联的表using (var dbConnection = new MyDbConnection())
{
var requestedOwners = dbConnection.Owners // Give me all Owners
.Where(owner => !owner.Pets.Any() // that have no Pets at all
|| owner.Pets.All(pet => pet.Status == Active)); // or have only active Pets
}
实体框架将认识到这需要一个连接,并将其转换为正确的内连接。
第二个查询更简单,可能更快,因为只要找到非活动Owner
,您就可以继续下一个Pet
var ownersWithoutInactivePets = dbContext.Owners // give me all Owners
.Where(owner => !owner.Pets // that don't have
.Any(pet => pet.Status == Inactive); // any inactive Pets
同样,实体框架将为您进行连接