Sql 如果左外联接为真,如何交叉应用

Sql 如果左外联接为真,如何交叉应用,sql,sql-server,tsql,Sql,Sql Server,Tsql,我有一个名为serviceEntry的表和一个名为ServiceEntryPart的表,它与后者有一对多的关系。问题是我只想在左外语句为真时交叉应用 因此,如果我传递一个部件id和一个服务类型id,它应该只在有真正匹配的地方重新运行记录,所发生的是,如果传递一个部件id和一个服务类型id,而该id对于包含该部件的特定记录来说并不存在,我得到的结果不是部件id传递,而是包含该服务类型的记录。如果我通过了零件的正确维修类型,那么我会得到正确的结果 ServiceEntry ID XYZ XYZ S

我有一个名为serviceEntry的表和一个名为ServiceEntryPart的表,它与后者有一对多的关系。问题是我只想在左外语句为真时交叉应用

因此,如果我传递一个部件id和一个服务类型id,它应该只在有真正匹配的地方重新运行记录,所发生的是,如果传递一个部件id和一个服务类型id,而该id对于包含该部件的特定记录来说并不存在,我得到的结果不是部件id传递,而是包含该服务类型的记录。如果我通过了零件的正确维修类型,那么我会得到正确的结果

ServiceEntry
ID
XYZ
XYZ

ServiceEntrPart    Sample Data
ID                 1
ServiceEntrID      10
ServiceEntryPart   1,2,3

   IF (@SelectedSystemIDs = '')                        
      begin        
          SET @SelectedSystemIDs = NULL         
      END         

IF (@SelectedPartsIDs = '')                        
  begin        
      SET @SelectedPartsIDs = NULL         
  END         

IF(@UserRoleID = 1)    
 BEGIN     
  SET @PlatformID = 1     
  END  

IF(@UserRoleID = 2)  
BEGIN  
SET @PlatformID = 2  
END  

IF (@UserRoleID = 3)    
BEGIN    
SET @PlatformID = 12    
END   

IF(@UserRoleID = 4)
BEGIN 
SET @PlatformID = 3
END

IF(@UserRoleID = 5)
BEGIN 
SET @PlatformID = 4
END

IF(@UserRoleID = 6)
BEGIN 
SET @PlatformID = NULL
END
--SET @Reconciled = 'R'

IF(@Reconciled='R')                            
 set @ReconciledValue=1                            
ELSE IF(@Reconciled='N')                            
 set @ReconciledValue=0   
ELSE IF(@Reconciled = 'A')
 set @ReconciledValue = null                         

--SET @ServiceTypes = '9'

IF @ServiceTypes = ''                        
  SET @ServiceTypes = NULL                          

IF @ServiceTypes IS NULL                   
  SET @flag = 2                  
 ELSE                    
 set @flag = 100                  

 IF (@SelectedSystemIDs = '')                    
    begin    
      SET @SelectedSystemIDs = NULL     
    END  

  Select     
   se.ID as ServiceEntryID,    
   se.ServiceDateTime,
   se.ReasonForFailure,
   se.ActionTaken,
   se.VerificationPerformed,
   se.TSBNumber,
   se.ISANumber,
   (SELECT     
  CAST(ID AS varchar(6)) + ' ~ ' + PartDescriptionWithParent FROM [RunLogTest].[dbo].[Part]       
    where id= sep.PartID) as PartDescriptionWithParent ,       
   (SELECT SystemFullName from System WHERE ID=se.SystemID
   )as SystemName,    
   se.Reconciled,
   se.CreatedDate,
   se.ClosedDate,
   se.UpdatedDate,
   se.ServiceHours,
   se.ServiceMinutes     
   FROM     
   [ServiceEntry] se left outer JOIN  
   ServiceEntryPart sep  ON se.ID = sep.ServiceEntryID   
   INNER JOIN SystemModule ON sep.SystemModuleID = SystemModule.ID  
   INNER JOIN System ON SystemModule.SystemID = System.ID 
   CROSS apply
   dbo.SplitStrings_Moden(sep.ServiceTypeIDs, N',') M2
   JOIN  dbo.SplitStrings_Moden(@ServiceTypes, N',') P ON (M2.Item = P.Item   or @ServiceTypes IS NULL)
   where se.ID=ServiceEntryID AND (se.Active = 1)
   AND (@ReconciledValue IS NULL OR se.Reconciled = @ReconciledValue)
   AND (@SelectedSystemIDs IS NULL OR  se.SystemID IN(select  * from dbo.SplitInts_RBAR_1(@SelectedSystemIDs, ',')))
   AND (@SelectedPartsIDs IS NULL or sep.PartID IN(select * from dbo.SplitInts_RBAR_1(@SelectedPartsIDs, ',')))
   AND (se.ServiceDateTime between @StartDate and @EndDate)
   AND ((@PlatformID IS NULL) OR  (System.PlatformID = @PlatformID) OR (@PlatformID = 12 AND System.PlatformID <= 2))  
   order by se.CreatedDate desc

如果没有任何能力来测试这一点,我将提出两种方法,其中一种很少使用,因此您可能希望忽略它

您在se和sep之间形成了一个外部联接,因此要保留该外部联接关系,您需要确保任何与sep的联接都允许外部联接。这将需要更多的左连接和外部应用,如下所示:

-- common approach
FROM [ServiceEntry] se
      LEFT OUTER JOIN ServiceEntryPart sep
                  ON se.ID = sep.ServiceEntryID
      LEFT OUTER JOIN JOIN SystemModule
                  ON sep.SystemModuleID = SystemModule.ID
      LEFT OUTER JOIN JOIN System
                  ON SystemModule.SystemID = System.ID
      OUTER APPLY dbo.SplitStrings_Moden(sep.ServiceTypeIDs, N',') M2
      LEFT OUTER JOIN dbo.SplitStrings_Moden(@ServiceTypes, N',') P
                  ON (M2.Item = P.Item OR @ServiceTypes IS NULL)
或未经测试!您可以使用较少使用的方法,该方法涉及移动ON语句序列。这会改变操作的优先级,在这里我用括号来强调这一点。实际上,执行括号内的联接是为了构造一个派生表,然后该派生表外部联接到se

虽然我相信两者都可以,但第一种选择可能是最容易维护的,因为大多数人更容易掌握

但是,请注意,如果@SelectedPartsIDs不为null,where子句中有一个条件将使所有外部联接无效:

  AND (@SelectedPartsIDs IS NULL
        OR sep.PartID IN (
              SELECT * FROM dbo.SplitInts_RBAR_1(@SelectedPartsIDs, ',')
                         )
      )

在左连接之后要小心内部连接…您将se连接到sep,然后在sep=systemmodule上内部连接systemmodule。se LEFT中的记录连接到sep,但未找到任何内容会导致所有sep字段为空。如果将该空sep值内部联接到另一个表,它将按照标准内部联接规则删除该记录。如果要在结果中删除null sep记录,那么左连接后面的两个内部连接都应该是左连接
  AND (@SelectedPartsIDs IS NULL
        OR sep.PartID IN (
              SELECT * FROM dbo.SplitInts_RBAR_1(@SelectedPartsIDs, ',')
                         )
      )
...
FROM dbo.[ServiceEntry] se
    left outer JOIN (
        dbo.ServiceEntryPart sep
        CROSS apply dbo.SplitStrings_Moden(sep.ServiceTypeIDs, N',') M2
    ) ON se.ID = sep.ServiceEntryID
...