在 temp table 中搜索时的条件 AND 语句

Conditional AND statement when searching in temp table

我正在编写一个存储过程来通过管理面板搜索客户table。 我大部分时间都在使用它,当我传递 CustomerRoles(分隔的客户角色 ID)时,我得到了那些角色中的客户 returned.

但是,如果我不传递任何客户角色(所以是一个空字符串),我不会得到任何记录,但我希望它传递给 return 所有角色。

这是我关心的部分

    AND (@CustomerRoles IS null OR EXISTS (
        SELECT [Customer_Id], [CustomerRole_Id] FROM [Test].[dbo].[Customer_CustomerRole_Mapping] crm with (NOLOCK) 
        WHERE c.Id = crm.Customer_Id AND crm.[CustomerRole_Id] IN (SELECT CustomerRoleId FROM #FilteredCustomerRolesIds)))

我可以确认在未搜索 CustomerRoles 时将空值传递到存储过程。

我想我需要某种空值检查或合并表达式,但不确定如何去做。

这是我的完整存储过程

USE [Test]
GO
/****** Object:  StoredProcedure [dbo].[CustomerLoadAllPaged]    Script Date: 10/2/2020 8:20:52 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO


--new stored procedure
ALTER PROCEDURE [dbo].[CustomerLoadAllPaged]
(
    @CustomerRoles nvarchar(MAX) = null,
    @CustomerEmail nvarchar(MAX) = null,
    @FirstName nvarchar(MAX) = null,
    @LastName nvarchar(MAX) = null,
    @PageIndex int = 0, 
    @PageSize int = 2147483644,
    @TotalRecords int = null OUTPUT
)
AS
BEGIN
    create table #TempCust (RowNum int identity(1,1), id int);
    create index #IK_tempcust on #TempCust (RowNum);

    SET @CustomerRoles = isnull(@CustomerRoles, '') 
    CREATE TABLE #FilteredCustomerRolesIds
    (
        CustomerRoleId int not null
    )
    INSERT INTO #FilteredCustomerRolesIds (CustomerRoleId)
    SELECT CAST(data as int) FROM [nop_splitstring_to_table](@CustomerRoles, ',')
    DECLARE @CustomerRoleIdCount int    
    SET @CustomerRoleIdCount = (SELECT COUNT(1) FROM #FilteredCustomerRolesIds)

    -- Insert statements for procedure here
    --select all
    INSERT INTO #TempCust ([id])
        SELECT c.[Id] 
        FROM [Test].[dbo].[Customer] c with (NOLOCK)

    LEFT join [Test].[dbo].[Address] a with (NOLOCK) on a.Id = c.BillingAddress_Id and (
        coalesce(@CustomerEmail,'') <> ''
        or coalesce(@FirstName,'') <> ''
        or coalesce(@LastName,'') <> ''
    )

    /*LEFT join [Test].[dbo].[Customer_CustomerRole_Mapping] crm with (NOLOCK) on c.Id = crm.Customer_Id and (
        coalesce(@CustomerRoles,'') <> ''
    )*/

    WHERE (@CustomerEmail IS null OR c.[Email] LIKE CONCAT('%',@CustomerEmail,'%'))
    AND (@FirstName IS null OR a.[FirstName] LIKE CONCAT('%',@FirstName,'%'))
    AND (@LastName IS null OR a.[LastName] LIKE CONCAT('%',@LastName,'%'))
    --AND (crm.[CustomerRole_Id] IN (SELECT CustomerRoleId FROM #FilteredCustomerRolesIds))

    AND (@CustomerRoles IS null OR EXISTS (
        SELECT [Customer_Id], [CustomerRole_Id] FROM [Test].[dbo].[Customer_CustomerRole_Mapping] crm with (NOLOCK) 
        WHERE c.Id = crm.Customer_Id AND crm.[CustomerRole_Id] IN (SELECT CustomerRoleId FROM #FilteredCustomerRolesIds)))

    --ORDER BY c.[CreatedOnUtc] DESC;
    
    --paging
    DECLARE @PageLowerBound int
    SET @PageLowerBound = @PageSize * @PageIndex

    -- Return the paged records
    select [Id] --note select * can produce unexpected results
      ,[CustomerGuid]
      ,[Username]
      ,[Email]
      ,[Password]
      ,[PasswordFormatId]
      ,[PasswordSalt]
      ,[AdminComment]
      ,[IsTaxExempt]
      ,[AffiliateId]
      ,[VendorId]
      ,[HasShoppingCartItems]
      ,[Active]
      ,[Deleted]
      ,[IsSystemAccount]
      ,[SystemName]
      ,[LastIpAddress]
      ,[CreatedOnUtc]
      ,[LastLoginDateUtc]
      ,[LastActivityDateUtc]
      ,[BillingAddress_Id]
      ,[ShippingAddress_Id]
    from [Test].[dbo].[Customer] cust with (NOLOCK)
    where cust.[Id] in (
      select id
      from #TempCust tc
      --Where (tc.RowNum > @PageLowerBound) -- best to use offset like below, which is faster and recommended
    )
    ORDER BY cust.[CreatedOnUtc] DESC
    OFFSET @PageLowerBound ROWS FETCH NEXT @PageSize ROWS ONLY;
    
    --total records
    select @TotalRecords = count(*) from #TempCust;

    DROP TABLE #TempCust
    DROP TABLE #FilteredCustomerRolesIds
END

因为您通过以下行确保 @CustomerRoles 永远不会 null

SET @CustomerRoles = ISNULL(@CustomerRoles, '');

您需要与空字符串进行比较而不是 null 例如

AND (
  -- @CustomerRoles IS NULL -- Change to empty string check since it is never null
  @CustomerRoles = ''
  OR EXISTS (
    SELECT [Customer_Id], [CustomerRole_Id]
    FROM [Test].[dbo].[Customer_CustomerRole_Mapping] crm WITH (NOLOCK) 
    WHERE c.Id = crm.Customer_Id AND crm.[CustomerRole_Id] IN (SELECT CustomerRoleId FROM #FilteredCustomerRolesIds)
  )
)

顺便说一句,你不应该使用 nolock 提示,除非它绝对需要性能。

空字符串与 NULL 不同。如果传递的是空字符串,则需要与 '' 进行比较。或者,也许您想安全起见并考虑两种可能性:

AND (@CustomerRoles IS null OR
     @CustomerRoles = '' OR
     EXISTS ( . . . )
    )