我希望我的存储过程具有条件联接,如果满足三个/或全部或两个条件之一,那么我们联接两个表(地址到订单)并根据搜索条件从订单表返回结果在地址表中。
这是我的存储过程:
USE [Test]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[OrderLoadAllPaged]
@OrderId int = 0,
@WarehouseId int = 0,
@PaymentMethodSystemName nvarchar(max) = null,
@OrderStatusId int = 0,
@PaymentStatusId int = 0,
@ShippingStatusId int = 0,
@BillingEmail nvarchar(max) = null,
@BillingFirstName nvarchar(max) = null,
@BillingLastName nvarchar(max) = null,
@ShippingMethod nvarchar(max) = null,
@CreatedFromUtc datetime = null,
@CreatedToUtc datetime = null
AS
BEGIN
DECLARE
@sql nvarchar(max)
SET NOCOUNT ON;
SELECT TOP 100 *
FROM [Test].[dbo].[Order] o with (NOLOCK)
LEFT join [Test].[dbo].[Address] a on (a.Id LIKE o.BillingAddressId)
WHERE (@BillingEmail IS null OR a.[Email] LIKE '%@BillingEmail%')
AND (@BillingFirstName IS null OR a.[FirstName] LIKE '%@BillingFirstName%')
AND (@BillingLastName IS null OR a.[LastName] LIKE '%@BillingLastName%')
AND
o.[Deleted] = 0
AND (o.[Id] = @OrderId OR @OrderId = 0)
AND (o.[WarehouseId] = @WarehouseId OR @WarehouseId = 0)
AND (@PaymentMethodSystemName IS null OR o.[PaymentMethodSystemName] = @PaymentMethodSystemName)
AND (o.[OrderStatusId] = @OrderStatusId OR @OrderStatusId = 0)
AND (o.[PaymentStatusId] = @PaymentStatusId OR @PaymentStatusId = 0)
AND (o.[ShippingStatusId] = @ShippingStatusId OR @ShippingStatusId = 0)
AND (@ShippingMethod IS null OR o.[ShippingMethod] = @ShippingMethod)
AND o.[CreatedOnUtc] >= ISNULL(@CreatedFromUtc, '1/1/1900')
AND o.[CreatedOnUtc] < ISNULL(@CreatedToUtc, '1/1/2999')
ORDER BY o.[CreatedOnUtc] DESC
END
这是我在锻炼时遇到的问题:
LEFT join [Test].[dbo].[Address] a on (a.Id LIKE o.BillingAddressId)
WHERE (@BillingEmail IS null OR a.[Email] LIKE '%@BillingEmail%')
AND (@BillingFirstName IS null OR a.[FirstName] LIKE '%@BillingFirstName%')
AND (@BillingLastName IS null OR a.[LastName] LIKE '%@BillingLastName%')
我感觉自己走在正确的轨道上,但遇到了某种超时错误
Execution Timeout Expired. The timeout period elapsed prior to completion of the operation or the server is not responding.
这告诉我查询一定有问题。
如果我删除电子邮件、名字和姓氏参数,查询就会完成。
我可以确认这就是我希望的工作方式,因为我手动编写了查询,这就是我所需要的:
SELECT TOP 100 *
FROM [Test].[dbo].[Order] o
LEFT JOIN [Test].[dbo].[Address] a
ON o.[BillingAddressId] = a.Id
WHERE a.[Email] LIKE '%chris1%' AND a.FirstName LIKE '%chris%' AND a.LastName LIKE '%c%'
ORDER BY o.[CreatedOnUtc]
我的参数以 C# 代码发送到数据库,如下所示:
var pBillingEmail = _dataProvider.GetParameter();
pBillingEmail.ParameterName = "BillingEmail";
pBillingEmail.Value = (!String.IsNullOrEmpty(billingEmail)) ? (object)billingEmail : DBNull.Value;
pBillingEmail.DbType = DbType.String;
var pBillingFirstName = _dataProvider.GetParameter();
pBillingFirstName.ParameterName = "BillingFirstName";
pBillingFirstName.Value = (!String.IsNullOrEmpty(billingFirstName)) ? (object)billingFirstName : DBNull.Value;
pBillingFirstName.DbType = DbType.String;
var pBillingLastName = _dataProvider.GetParameter();
pBillingLastName.ParameterName = "BillingLastName";
pBillingLastName.Value = (!String.IsNullOrEmpty(billingLastName)) ? (object)billingLastName : DBNull.Value;
pBillingLastName.DbType = DbType.String;
有人知道我哪里出了问题吗?
最佳答案
LIKE '%@BillingEmail%'
应该是 LIKE '%' + @BillingEmail + '%'
否则您正在查找包含字符串 '@BillingEmail'
而不是变量的内容。
不幸的是,当您尝试“包含”搜索时,例如like '%somesearchterm% SQL Server 无法使用索引来缩小搜索范围,因此必须读取并检查正在搜索的表中的每条记录。因此它会相当慢。
这种广义搜索很难很好地执行。然而,虽然拥有索引并不能缩小需要搜索的行的范围,但在 BillingEmail
上拥有索引确实可以减少 SQL Server 为了执行搜索而必须加载的数据量,并且可以使性能得到相当显着的提高。这也意味着在您搜索时表本身并未被锁定。
所以你可以考虑添加3个索引,BillingEmail、BillingFirstName、BillingLastName。您需要根据系统的工作方式对此进行自定义,但例如,如果人们通常搜索名字和姓氏,您可以在这两列上使用单个索引。
如果您想在许多列上进行搜索,这不太可扩展。您可以通过创建组合字段来扩展这个想法,例如FullName
在触发器上更新为 FirstName + ' ' + LastName
,然后您可以索引 FullName
。
当您实际执行搜索时,通常可以更好地对一个搜索词进行第一次搜索并将结果(或仅 ID)存储在临时表中,然后针对临时表执行进一步的过滤操作。如果您可以让用户通过初始选择以某种方式缩小搜索范围,这尤其有用。
全文索引也是一种选择。
关于sql-server - 参数化存储过程条件连接,通过 3 个参数在连接表中搜索,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59080065/