Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/307.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如果记录存在,则使用内部联接,否则使用左联接_C#_Sql Server_Entity Framework - Fatal编程技术网

C# 如果记录存在,则使用内部联接,否则使用左联接

C# 如果记录存在,则使用内部联接,否则使用左联接,c#,sql-server,entity-framework,C#,Sql Server,Entity Framework,我有以下表格结构: dbo.所有者 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 我需要归还所有只养宠物或没有宠

我有以下表格结构:

dbo.所有者

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(没有宠物)

我将使用实体框架在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个查询中实现这一点。

试试:

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
这个简单的查询就可以了

OwnerId        OwnerName 
2              Marie
3              Alex
如果您想选择至少有一只宠物处于活动状态或没有宠物的主人,请使用下面的查询

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
此查询将返回所有者名称,直到该所有者的所有宠物处于非活动状态

现在来看另一个例子

如果您的表有可能在Pets表中将OwnerId设置为NULL。 请使用下面的查询。(Mysql)

在子查询中添加了IFNULL()


如果
状态的唯一值是“活动”和“非活动”,实际上可以简化查询。当你说:

我需要归还所有只养宠物或没有宠物的主人

这实际上可以转化为:

我需要归还所有没有闲置宠物的主人

然后您的查询就变得容易多了

在实体框架查询中:

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')
    )

如果状态有更多值,可以使用(实体框架):

这将生成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])
    ))
您可能想测试它的性能,可能有更好的方法,但它会给出期望的结果。但它假定您具有外键/导航属性

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

有趣的是,尽管您将其标记为实体框架,但大多数答案并没有给出实体框架为您提供的简化

所有者
宠物
之间存在一对多关系。每个
所有者
拥有零只或多只
宠物
,每个
宠物
只属于一个
所有者

如果您已为a正确配置了实体框架类,则它们将如下所示:

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;}
}
实体框架将认识到这需要一个连接,并将其转换为正确的内部连接

第二个查询更简单,可能更快,因为只要找到一个不活动的
Pet
,您就可以继续查找下一个
Owner

var ownersWithoutInactivePets = dbContext.Owners   // give me all Owners
    .Where(owner => !owner.Pets                    // that don't have
        .Any(pet => pet.Status == Inactive);       // any inactive Pets

同样,entity framework将为您执行连接

有趣的是,使用左连接也可以执行此操作。我不知道这是否与其他答案建议的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];
创建表[所有者](
OwnerID int主键,
业主名称nvarchar(50)
);
插入[所有者]
价值观
(1,'约翰'),
(2,'玛丽'),
(3,“亚历克斯”);
创建桌面宠物(
PetID int主键,
PetTag nvarchar(10),
nvarchar状态(30),
OwnerID int外键引用[Owner](OwnerID)
);
插入宠物
价值观
(1,'A341','Active',1),
(2,'A342','Inactive',1),
(3,'A343','Active',2),
(4,'A345','Active',2);
从[所有者]中选择*;
从宠物中选择*;
挑选
o*
从…起
[所有者]o
左连接Pet p
在o.OwnerID=p.OwnerID上
和p.状态“活动”
哪里
p、 OwnerID为空;
投桌宠物,[主人];

听一听你简单的英语提问:我需要返回所有只养宠物或没有宠物的主人。你需要一个由那些有活跃宠物和没有宠物的人组成的简单联盟。谢谢Andrei,这应该行得通。但是如果有更多的状态呢?我可以将p.Status='Inactive'更改为p.Status'Active'?如果一个人同时拥有一只活动和一只非活动宠物,会发生什么情况。。我认为您的查询在这个条件下不起作用。两个查询都会忽略这些所有者,这就是问题所指定的。除非我误解了你?一般来说,如果可以的话,避免
不在
中。如果
Pet.OwnerID
列中有空值(即没有主人的宠物),您的查询将变成南瓜。
不存在
版本的@AndreiOdegov不易受此影响。请从OwnerID不在的Owner中选择不同的OwnerName(从状态为“Inactive”的Pet中选择IFNULL(OwnerID,0);我将IFNULL添加到select in NOT in中,它正在工作。另外,由于Owner在OwnerId上是唯一的,因此不需要DISTINCT,它可能会执行不必要的唯一排序。我不会删除该ID,因为多个人可以有相同的名称。删除的是不同的,添加的是不同的id@FarazPV,在MS SQL Server中没有
ifnull()
函数。另外,您是否将解决方案的执行计划与
不存在的执行计划进行了比较?我打赌你用这样的包装会失去吸引力。不正确。这也将返回id为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
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;}
}
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
}
var ownersWithoutInactivePets = dbContext.Owners   // give me all Owners
    .Where(owner => !owner.Pets                    // that don't have
        .Any(pet => pet.Status == Inactive);       // any inactive Pets
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];