SQL 服务器:使用存在于连接中使用的 table

SQL Server: Use exists on a table used in join

假设我有一个 table WorkItems,其中包含工作项、它们的状态和描述。还有两个tablePersonsWorkItemPersonLinks分别有工作项分配给他们的人的数据和哪个项目分配给哪个人的数据。模式是这样的 -

Create table WorkItems 
(
    Id int not null primary key,
    Description varchar (100),
    Status varchar (30),
    IfValid bit not null,
)

Create table Persons
(
    Id int not null primary key,
    Name varchar (100),
    IfValid bit not null
)

Create table WorkItemPersonLinks
(
    Id int not null primary key,
    WorkItemId int foreign key references WorkItems(Id),
    PersonId int foreign key references Persons(Id),
    IfValid bit not null
)

这是一些示例数据 -

insert into workItems values
(1, 'Go Fishing', 'To do', 1), 
(2, 'Play video game', 'Done', 1), 
(3, 'Cook Dinner', 'In progress', 1), 
(4, 'Purchase Groceries', 'Done', 1)

insert into Persons values
(1, 'Tom', 1), (2, 'Dick', 1), (3, 'Harry', 1)    

insert into WorkItemPersonLinks values
(1, 1, 1, 1), (2, 2, 2, 1), (3, 3, 3, 1), (4, 4, 2, 1),
(5, 2, 1, 1), (6, 3, 2, 1), (7, 3, 1, 1), (8, 4, 3, 1)

这就是我想要的,假设我有一个输入参数 @viewOption,它可以取 my(仅我的工作项)、done(所有已完成的项)的可能值, not done(带 Status <> 'done' 的工作项)和 all(所有工作项)和另一个参数 @userId,它可以有一个 int 值并且可以是任何一个来自 Persons table。因此,假设用户 (Tom) 只想查看 his 个任务,在这种情况下 @viewOption = 'my'@userId = 1(Tom 在 Persons table 中的 ID。

更新

一个工作项目可以分配给多个人。因此,即使 @viewOption 设置为 my,查询也应该 return 分配给该项目的其他人(除了用户)的数据,而不仅仅是他自己的数据。

我很难完成的查询如下 -

declare @viewOption varchar(10) = 'my'
declare @userId int = 1

select p.Name, wi.Description, wi.status from WorkItems wi
inner join WorkItemPersonLinks wpl on wi.Id = wpl.WorkItemId 
inner join Persons p on wpl.PersonId = p.Id
where wi.IfValid = 1 and wpl.IfValid = 1 and p.IfValid = 1 and ((@viewOption = 'my' and exists(select 1 from wpl where wpl.PersonId = @userId))
   or (@viewOption = 'all')
   or (@viewOption = 'done' and wi.Status = 'done')
   or (@viewOption = 'not done' and wi.Status <> 'done'))

这个错误 Invalid object name 'wpl 据我所知是由于 exists 子句的上下文无效引起的。我可以通过在 @viewOption 上使用 case 语句来使它工作,但我想在提交查询之前仔细检查更好(和更优雅)的方法。

下面的方法行得通吗?如果我理解正确,如果传入的 UserID 存在于搜索查询中(其中 ViewOption 为 "My"),您希望查看查询结果。我已经使用 IF 语句完成此操作以选择 运行 的最佳查询,希望它对你有用

declare @viewOption varchar(10) = 'my'
declare @userId int = 1

IF @viewOption = 'my' AND @userid IN (
    SELECT DISTINCT
        wpl.PersonId
    FROM
        WorkItems wi
        inner join WorkItemPersonLinks wpl on wi.Id = wpl.WorkItemId 
        inner join Persons p on wpl.PersonId = p.Id)
BEGIN
    SELECT
        p.Name,
        wi.Description,
        wi.status
    FROM
        WorkItems wi
        INNER JOIN WorkItemPersonLinks wpl on wi.Id = wpl.WorkItemId 
        INNER JOIN Persons p on wpl.PersonId = p.Id
    WHERE
        wi.IfValid = 1
        AND wpl.IfValid = 1
        AND p.IfValid = 1
END

IF @viewOption IN ('all', 'done', 'not done')
BEGIN
    SELECT
        p.Name,
        wi.Description,
        wi.status
    FROM
        WorkItems wi
        INNER JOIN WorkItemPersonLinks wpl ON wi.Id = wpl.WorkItemId 
        INNER JOIN Persons p ON wpl.PersonId = p.Id
    WHERE
        (@viewOption = 'all')
       OR (@viewOption = 'done' AND wi.Status = 'done')
       OR (@viewOption = 'not done' AND wi.Status <> 'done')
END

您需要在那里使用 table 名称而不是上面的本地别名,并且还要引用工作项:

select p.Name, wi.Description, wi.status 
from WorkItems wi
inner join WorkItemPersonLinks wpl on wi.Id = wpl.WorkItemId 
inner join Persons p on wpl.PersonId = p.Id
where wi.IfValid = 1 and wpl.IfValid = 1 and p.IfValid = 1 and 
   ((@viewOption = 'my' and exists 
     (select * from WorkItemPersonLinks w2 
      where w2.WorkItemId = wi.Id and w2.PersonId = @userId))
   or (@viewOption = 'all')
   or (@viewOption = 'done' and wi.Status = 'done')
   or (@viewOption = 'not done' and wi.Status <> 'done'));

请试试这个:

select p.name
    ,wi.description
    ,wi.status
from workitems wi
inner join workitempersonlinks wpl on wi.id = wpl.workitemid
inner join persons p on wpl.personid = p.id
where wi.ifvalid = 1
    and wpl.ifvalid = 1
    and p.ifvalid = 1
    and (
            (@viewoption = 'my' and wi.id in (select [WorkItemId] from  workitempersonlinks where PersonId =  @userid))
        or  (@viewoption = 'all')
        or  (@viewoption = 'done' and wi.status = 'done')
        or  (@viewoption = 'not done' and wi.status <> 'done')
    )