存储过程WHERE LIKE ID或NAME

时间:2009-12-14 22:26:01

标签: sql sql-server tsql stored-procedures

组, 我正在尝试使用一个变量@Customer创建一个存储过程。我想要做的是在WHERE子句中添加一些内容,说明它是否为数字搜索CustomerID字段,其中输入的数字为LIKE CustomerID ...如果输入了char,则搜索CustomerName字段,其中输入的文本为LIKE CustomerName。以下是我想要做的一个例子:

CREATE PROCEDURE [dbo].[uspGetCustomer] (@Customer VARCHAR(100))

AS

SET NOCOUNT ON

SELECT * 
FROM dbo.Customers
WHERE CASE WHEN ISNUMERIC(@Customer) THEN CustomerID LIKE @Customer + '%'
ELSE CustomerName LIKE @Customer + '%' END

有什么建议吗?

10 个答案:

答案 0 :(得分:4)

我会使用IF语句来实现,因为将该逻辑放在WHERE中会使以后难以阅读:

DECLARE @match = @CustomerID + '%'

IF ISNUMERIC(@CustomerID) = 1 
BEGIN
     SELECT * FROM CUSTOMERS WHERE CustomerID LIKE @match
END ELSE BEGIN
     SELECT * FROM CUSTOMERS WHERE CustomerNAME LIKE @match
END  




更新: 我想知道CustomerID字段是否是INT。如果是这样,那么我会像这样更改查询(并删除@match变量):

    ... WHERE CustomerID = Cast(@CustomerID as INT) --if numeric
    ... WHERE CustomerNAME = @CustomerID + '%'      --if not numeric

但是,如果它是一个奇怪的VARCHAR字段以数字开头并以其他数据结尾,如'11_blah',则LIKE加通配符正常工作

答案 1 :(得分:3)

尝试解决这两个条件的单个SQL语句将导致最差的执行计划。记住SQL必须生成一个单独的计划来满足@variable的任何值。在你的情况下@customerID是数字时,正确的计划是使用CustomerID上的索引。但是当@customerID是一个名称时,正确的访问权限将是CustomerName的索引。鉴于这种困境,优化器可能会选择执行全扫描的计划,即。两种情况都没有优化。

正确的做法是确定应用中的 ,如果是ID或名称,并调用两个单独的存储过程,uspGetCustomerByIDuspGetCustomerByName,根据输入的值。如果你必须通过一个'魔术'API入口点(全能的uspGetCustomer)来做到这一点,那么你已经得到了很好的答案。

答案 2 :(得分:3)

它可能只是我,但使用单个变量来表示两个不同的字段给了我糟糕的练习意志。我会重写这个存储过程以接受两个不同的可空变量(一个int,CustomerID和一个varchar,CustomerName)。它看起来像这样:

CREATE PROCEDURE [dbo].[uspGetCustomer] (
@CustomerID int = null, 
@CustomerName VARCHAR(100) = null)

AS

IF @CustomerID IS NOT NULL BEGIN
     SELECT * FROM Customers WHERE CustomerID = @CustomerID
END ELSE IF @CustomerName IS NOT NULL BEGIN
     SELECT * FROM Customers WHERE CustomerName LIKE @CustomerName
END ELSE
     --error handling, return empty set maybe?
END

如果这不是一个选项,那么你仍然可以使用:

CREATE PROCEDURE [dbo].[uspGetCustomer] (@Customer VARCHAR(100))

AS

DECLARE @NameMatch;

IF ISNUMERIC(@Customer) = 1 BEGIN
     SELECT * FROM Customers WHERE CustomerID = CAST (@Customer AS int)
END ELSE BEGIN
     SET @NameMatch = '%' + @Customer + '%'
     SELECT * FROM Customers WHERE CustomerName LIKE @NameMatch
END

答案 3 :(得分:2)

使用:

CREATE PROCEDURE [dbo].[uspGetCustomer] (@Customer VARCHAR(100))
AS

BEGIN

IF ISNUMERIC(@Customer) = 1
  BEGIN
    SELECT *
      FROM dbo.CUSTOMERS
     WHERE customerid LIKE @Customer + '%'
  END
ELSE
  BEGIN
    SELECT *
      FROM dbo.CUSTOMERS
     WHERE customername LIKE @Customer + '%'
  END

END

答案 4 :(得分:2)

做这样的事情:

CREATE PROCEDURE [dbo].[uspGetCustomer] (
    @CustomerID INT = NULL
    @Customer VARCHAR(100) = NULL
)

AS

SET NOCOUNT ON

IF @CustomerID is not null
BEGIN
    SELECT * FROM dbo.Customers
    WHERE CustomerID = @CustomerID
END
ELSE
BEGIN
    SELECT * FROM dbo.Customers
    WHERE CustomerName LIKE @CustomerID + '%'
END

SET NOCOUNT OFF

答案 5 :(得分:1)

我会保持简单,并假设客户名称永远不会是数字:

SELECT * 
FROM dbo.Customers
WHERE CustomerID LIKE @Customer + '%'
OR CustomerName LIKE @Customer + '%'

或者,如果您确实不希望将数字客户与其名称匹配,则可以检查如下:

WHERE (IsNumeric(@Customer) = 1 AND CustomerID LIKE @Customer + '%')
OR (IsNumeric(@Customer) = 0 AND CustomerName LIKE @Customer + '%')

但是,您如何搜索具有数字名称的客户?顺便说一下......如果你搜索121,这样的搜索会找到客户12

答案 6 :(得分:1)

SELECT  * 
FROM    dbo.Customers
WHERE   ISNUMERIC(@Customer) = 1
        AND CustomerID = CAST(@Customer AS INTEGER)
UNION ALL
SELECT  *
FROM    dbo.Customers
WHERE   NOT ISNUMERIC(@Customer) = 1
        AND CustomerName LIKE @Customer + '%'

这将使用CustomerIDCustomerName

上的相应索引

答案 7 :(得分:0)

我相信这样做会:

WHERE CustomerID LIKE
  CASE WHEN IsNumeric(@Customer) = 1 THEN 
    CustomerID 
  ELSE
    CustomerName + '%'
  END

答案 8 :(得分:0)

哦,就这样做吧....

IF ISNUMERIC(@Customer) THEN
SELECT * FROM .... CustomerID = @Customer

ELSE 
SELECT * FROM ... CustomerName LIKE @Customer 

但是你想让它更易于维护...

declare @basequery NVARCHAR(4000)
declare @params NVARCHAR(4000)

set @base_query = 'select * from dbo.Customers where '

IF ISNUMERIC(@Customer) THEN
  SET @base_query = @base_query + 'customerid = @xCustomer'
  SET @params = '@xCustomer int'
END
ELSE
  SET @base_query = @base_query + 'customerName LIKE @xCustomer + ''%'' '
  SET @params = '@xCustomer nvarchar(1000)'
END

exec sp_execuresql @base_query, @params, @Customer

当然我只会推荐这种动态的sql来进行更复杂的过滤。

答案 9 :(得分:0)

保持简单,每个都有一个索引,在前端确定它是哪一个并设置正确的参数。

CREATE PROCEDURE dbo.getCustomer 
(@CustomerID int = null, 
@CustomerName VARCHAR(100) = null)
AS
SET NOCOUNT ON

SELECT * 
FROM Customers 
WHERE CustomerID = @CustomerID
or CustomerName like @CustomerName + '%'