How do I create a stored procedure that will optionally search columns?

前端 未结 10 677
醉话见心
醉话见心 2020-12-08 08:30

I\'m working on an application for work that is going to query our employee database. The end users want the ability to search based on the standard name/department criteria

相关标签:
10条回答
  • 2020-12-08 09:12

    Erland Sommarskog's article Dynamic Search Conditions in T-SQL is a good reference on how to do this. Erland presents a number of strategies on how to do this without using dynamic SQL (just plain IF blocks, OR, COALESCE, etc) and even lists out the performance characteristics of each technique.

    In case you have to bite the bullet and go through the Dynamic SQL path, you should also read Erland's Curse and Blessings of Dynamic SQL where he gives out some tips on how to properly write dynamic SQLs

    0 讨论(0)
  • 2020-12-08 09:12

    It can be done, but usually these kitchen-sink procedures result in some poor query plans.

    Having said all that, here is the tactic most commonly used for "optional" parameters. The normal approach is to treat NULL as "ommitted".

    SELECT
      E.EmployeeID,
      E.LastName,
      E.FirstName
    WHERE
      E.FirstName = COALESCE(@FirstName, E.FirstName) AND
      E.LastName = COALESCE(@LastName, E.LastName) AND
      E.DepartmentID = COALESCE(@DepartmentID, E.DepartmentID)
    

    EDIT: A far better approach would be parameterized queries. Here is a blog post from one of the world's foremost authorities in this domain, Frans Bouma from LLBLGen Pro fame:

    Stored Procedures vs. Dynamic Queries

    0 讨论(0)
  • 2020-12-08 09:14

    The most efficient way to implement this type of search is with a stored procedure. The statement shown here creates a procedure that accepts the required parameters. When a parameter value is not supplied it is set to NULL.

    CREATE PROCEDURE ps_Customers_SELECT_NameCityCountry
    @Cus_Name varchar(30) = NULL,
    @Cus_City varchar(30) = NULL,
    @Cus_Country varchar(30) =NULL
    AS
    SELECT Cus_Name,
           Cus_City,
           Cus_Country
    FROM Customers
    WHERE Cus_Name = COALESCE(@Cus_Name,Cus_Name) AND
          Cus_City = COALESCE(@Cus_City,Cus_City) AND
          Cus_Country = COALESCE(@Cus_Country,Cus_Country)
    

    Taken from this page: http://www.sqlteam.com/article/implementing-a-dynamic-where-clause

    I've done it before. It works well.

    0 讨论(0)
  • 2020-12-08 09:15

    Using the COALESCE method has a problem in that if your column has a NULL value, passing in a NULL search condition (meaning ignore the search condition) will not return the row in many databases.

    For example, try the following code on SQL Server 2000:

    CREATE TABLE dbo.Test_Coalesce (
        my_id   INT NOT NULL IDENTITY,
        my_string   VARCHAR(20) NULL )
    GO
    INSERT INTO dbo.Test_Coalesce (my_string) VALUES (NULL)
    INSERT INTO dbo.Test_Coalesce (my_string) VALUES ('t')
    INSERT INTO dbo.Test_Coalesce (my_string) VALUES ('x')
    INSERT INTO dbo.Test_Coalesce (my_string) VALUES (NULL)
    GO
    DECLARE @my_string  VARCHAR(20)
    SET @my_string = NULL
    SELECT * FROM dbo.Test_Coalesce WHERE my_string = COALESCE(@my_string, my_string)
    GO
    

    You will only get back two rows because in the rows where the column my_string is NULL you are effective getting:

    my_string = COALESCE(@my_string, my_string) =>
    my_string = COALESCE(NULL, my_string) =>
    my_string = my_string =>
    NULL = NULL
    

    But of course, NULL does not equal NULL.

    I try to stick with:

    SELECT
         my_id,
         my_string
    FROM
         dbo.Test_Coalesce
    WHERE
         (@my_string IS NULL OR my_string = @my_string)
    

    Of course, you can adjust that to use wild cards or whatever else you want to do.

    0 讨论(0)
  • 2020-12-08 09:15

    Copying this from my blog post:

    USE [AdventureWorks]
    GO
    
    CREATE PROCEDURE USP_GET_Contacts_DynSearch
    (
        -- Optional Filters for Dynamic Search
        @ContactID          INT = NULL, 
        @FirstName          NVARCHAR(50) = NULL, 
        @LastName           NVARCHAR(50) = NULL, 
        @EmailAddress       NVARCHAR(50) = NULL, 
        @EmailPromotion     INT = NULL, 
        @Phone              NVARCHAR(25) = NULL
    )
    AS
    BEGIN
        SET NOCOUNT ON
    
        DECLARE
            @lContactID         INT, 
            @lFirstName         NVARCHAR(50), 
            @lLastName          NVARCHAR(50), 
            @lEmailAddress      NVARCHAR(50), 
            @lEmailPromotion    INT, 
            @lPhone             NVARCHAR(25)
    
        SET @lContactID         = @ContactID
        SET @lFirstName         = LTRIM(RTRIM(@FirstName))
        SET @lLastName          = LTRIM(RTRIM(@LastName))
        SET @lEmailAddress      = LTRIM(RTRIM(@EmailAddress))
        SET @lEmailPromotion    = @EmailPromotion
        SET @lPhone             = LTRIM(RTRIM(@Phone))
    
        SELECT
            ContactID, 
            Title, 
            FirstName, 
            MiddleName, 
            LastName, 
            Suffix, 
            EmailAddress, 
            EmailPromotion, 
            Phone
        FROM [Person].[Contact]
        WHERE
            (@lContactID IS NULL OR ContactID = @lContactID)
        AND (@lFirstName IS NULL OR FirstName LIKE '%' + @lFirstName + '%')
        AND (@lLastName IS NULL OR LastName LIKE '%' + @lLastName + '%')
        AND (@lEmailAddress IS NULL OR EmailAddress LIKE '%' + @lEmailAddress + '%')
        AND (@lEmailPromotion IS NULL OR EmailPromotion = @lEmailPromotion)
        AND (@lPhone IS NULL OR Phone = @lPhone)
        ORDER BY ContactID
    
    END
    GO
    
    0 讨论(0)
  • 2020-12-08 09:20

    While the COALESCE trick is neat, my preferred method is:

    CREATE PROCEDURE ps_Customers_SELECT_NameCityCountry
        @Cus_Name varchar(30) = NULL
        ,@Cus_City varchar(30) = NULL
        ,@Cus_Country varchar(30) = NULL
        ,@Dept_ID int = NULL
        ,@Dept_ID_partial varchar(10) = NULL
    AS
    SELECT Cus_Name
           ,Cus_City
           ,Cus_Country
           ,Dept_ID
    FROM Customers
    WHERE (@Cus_Name IS NULL OR Cus_Name LIKE '%' + @Cus_Name + '%')
          AND (@Cus_City IS NULL OR Cus_City LIKE '%' + @Cus_City + '%')
          AND (@Cus_Country IS NULL OR Cus_Country LIKE '%' + @Cus_Country + '%')
          AND (@Dept_ID IS NULL OR Dept_ID = @DeptID)
          AND (@Dept_ID_partial IS NULL OR CONVERT(varchar, Dept_ID) LIKE '%' + @Dept_ID_partial + '%')
    

    These kind of SPs can easily be code generated (and re-generated for table-changes).

    You have a few options for handling numbers - depending if you want exact semantics or search semantics.

    0 讨论(0)
提交回复
热议问题