0

我将列表传递到我的存储过程中,以便用户可以选择他们的产品线、制造商和类别来进行搜索。他们不必提供此条件,如果不提供,则搜索会发生在所有这些产品线、制造商和/或类别中。我有两种策略,我正在尝试决定哪种策略更有效。

策略#1 是我尽量避免使用的动态 SQL,但在阅读了我正在考虑使用的 Sommarskog 文章之后。例子...

IF @productLines IS NOT NULL 

BEGIN
     CREATE TABLE #TempProductLines (lineID uniqueidentifier)

     INSERT INTO @TempProductLines
     SELECT gID FROM dbo.f_ConvertGuidList_To_Table(@productLines) --varchar list of Guid values
END   

SET @sql = "SELECT * FROM tblRL_PRoducts p "
IF @proudctLInes IS NOT NULL
SET @sql = @sql + " JOIN tblRL_PRoductLines pl ON p.prodID=pl.prodID "

SET @sql = @sql + " WHERE....."   --- where clause

EXEC sp_executesql @sql, @paramlist,... params

策略 #2,避免使用 LEFT JOIN 的动态 SQL

CREATE TABLE #TempProductLines (lineID uniqueidentifier)

INSERT INTO @TempProductLines
SELECT gID FROM dbo.f_ConvertGuidList_To_Table(@productLines) --varchar list of Guid values

SELECT * 
FROM tblRL_PRoducts p
 LEFT JOIN #TempProductLines pl ON p.prodID=pl.prodID

WHERE 
   (
     (
       @productLInes IS NOT NULL
       AND
       pl.lineID IS NOT NULL
     )
     OR
     @productLines IS NULL
   )
   AND
   (
     .... rest of WHERE clause
   )

实际上,我最终会在上面有 7 个块用于搜索中使用的不同潜在列表。

4

1 回答 1

0

我使用“MYCOUNT = 0 或存在”技巧。

你可以在这里完整地看到它:

http://www.sqlservercentral.com/articles/Stored+Procedures/thezerotonparameterproblem/2283/

哇。我需要为非 OPENXML 更新它并使用存在而不是“IN”子句。

下面是该代码的更现代版本。只需针对现有的 Northwind 数据库运行它。

/*  START TSQL CODE */

/*  Stored Procedure Definition */

Use Northwind
GO


IF EXISTS 
    (
    SELECT * FROM INFORMATION_SCHEMA.ROUTINES
    WHERE ROUTINE_TYPE = N'PROCEDURE' and ROUTINE_SCHEMA = N'dbo' and ROUTINE_NAME = N'uspOrderDetailsGetByXmlParams'  
    )
BEGIN
    DROP PROCEDURE [dbo].[uspOrderDetailsGetByXmlParams]
END


GO

CREATE Procedure dbo.uspOrderDetailsGetByXmlParams(
@parametersXML XML
)
AS

BEGIN

    SET NOCOUNT ON


    /* build a table (variable) to store the xml-based result set (for specific orderid's) */
    DECLARE @orderCount int
    DECLARE @orders TABLE ( /* used to track which specific OrderID's you want */
    OrderID int
    )

    DECLARE @customerCount int DECLARE @customers TABLE ( /* used to track which specific customers you want  */
    CustomerID varchar(5) 
    )

    declare @dateOrderDateAfter datetime /* used to track with orders with OrderDate after you want */
    declare @dateOrderDateBefore datetime /* used to track with orders with OrderDate before you want */

    /* build a table (table-variable) to store the xml-based result set (for specific Countries) */
    DECLARE @customerCountryCount int DECLARE @customerCountry TABLE ( /* used to track which specific Countries you want */
    CountryName varchar(15) )


    /* Start XML usage */  
    /* Only incur the penalty of XML parsing, if XML was specified */
    if (@parametersXML IS NOT NULL) AND (Datalength(@parametersXML) > 10 ) 
        /* Only process the xml If the xml exists, and it has at least 10 chars. 10 is just a somewhat */ 
        /* arbritrary number, saying, that an xml doc with <10 chars doesn't have a whole lot going for it */ /* || DataLength is used for Text datatype  */

    BEGIN


        /*  (Do not forget that XML (and xpaths below) are CASE SENSITIVE, no matter what your database collation happens to be.) */
        INSERT INTO @orders ( OrderID )
        SELECT T.parameter.value('(OrderID)[1]', 'INT') AS OrderID
        FROM @parametersXML.nodes('ParametersDS/Order') AS T(parameter);

        INSERT INTO @customers (CustomerID)
        SELECT T.parameter.value('(CustomerID)[1]', 'varchar(5)') AS CustomerID
        FROM @parametersXML.nodes('ParametersDS/Customer') AS T(parameter);

        /* Note, a single scalar value below */
        SELECT @dateOrderDateBefore = (
        SELECT T.parameter.value('(OrderDateBefore)[1]', 'datetime') AS OrderDateBefore
        FROM @parametersXML.nodes('ParametersDS/SingleValueParam') AS T(parameter) );

        /* Note, a single scalar value below */
        SELECT @dateOrderDateAfter =  (
        SELECT T.parameter.value('(OrderDateAfter)[1]', 'datetime') AS OrderDateAfter
        FROM @parametersXML.nodes('ParametersDS/SingleValueParam') AS T(parameter) );

        INSERT INTO @customerCountry (CountryName)
        SELECT T.parameter.value('(CountryName)[1]', 'varchar(15)') AS CountryName
        FROM @parametersXML.nodes('ParametersDS/CustomerCountry') AS T(parameter);

    END 
    /* End XML usage */


    /* These count variables help distinquish between when a parameter is and isn't specified */
    select @orderCount = count(*) from @orders 
    select @customerCount = count(*) from @customers 
    select @customerCountryCount = count(*) from @customerCountry 
    /* Note, if the xml doesn't supply any dates, @dateOrderDateBefore and @dateOrderDateAfter will remain null  */

    /* */
    /* Debugging queries */
    /*
    select * from @orders 
    select * from @customers 
    print @dateOrderDateBefore 
    print @dateOrderDateAfter 
    select * from @customerCountry 
    */

    /* Above are the variables and variable-tables for parameters */
    /**/

    DECLARE @ordersWhichMetCriteriaTable TABLE ( /* used to track the orderid's we're interested in */
    OrderID int ) 

    /* A new variable table holds (just) the OrderID's which meet the input parmeters. 
     You'll see the use of the @ordersWhichMetCriteriaTable later. 
     */

    Insert into @ordersWhichMetCriteriaTable 
    SELECT 
        OrderID 
    FROM 
        Orders o 
    /* Note, this below join to the Customers table is only necessary because of the Country */
    /* if you didn't want to retrieve the Customer.Country column, you could leave this join out */
    INNER JOIN Customers c 
        ON o.CustomerID = c.CustomerID 
    WHERE 
                /* the parentheses play an important role, so be careful altering them */
        /* */
        (
            (@orderCount = 0) 
            OR
            ( exists (select null from @orders innerVariableTable where innerVariableTable.OrderID = o.OrderID ))
        ) 

        /* */
        AND 
        (
            (@customerCount = 0) 
            OR
            ( exists (select null from @customers innerVariableTable where innerVariableTable.CustomerID = o.CustomerID ))
        ) 

        /* */
        AND (( @dateOrderDateBefore IS NULL ) OR (o.OrderDate <= @dateOrderDateBefore )) 

        /* */
        AND (( @dateOrderDateAfter IS NULL ) OR (o.OrderDate >= @dateOrderDateAfter )) 

        /* */
        AND 
            /*CountryName is a string, so watch the case sensitivity, get around this by using UPPER() function */
            (
                (@customerCountryCount = 0) 
                OR
                ( exists (select null from @customerCountry innerVariableTable where UPPER(innerVariableTable.CountryName) = UPPER(c.Country)  ))
            ) 
    /*  ORDER BY is unnecessary here */



    /* Below are 3 queries/result sets we're interested in. Notice the piggyback off the @ordersWhichMetCriteriaTable every time. */ 
    /* */
    /* */

    /* ResultSet #1 */
    /* All Customer Information (for the specific orders in the @ordersWhichMetCriteriaTable table) */
    SELECT 
        c.CustomerID, c.CompanyName,c.ContactName,c.ContactTitle,c.[Address],c.City,c.Region,c.PostalCode,c.Country ,c.Phone,c.Fax 
    FROM 
        Customers c 
        JOIN Orders o ON c.CustomerID = o.CustomerID 
    WHERE 
        exists (select null from @ordersWhichMetCriteriaTable innerHolder where innerHolder.OrderID = o.OrderID )
    ORDER BY 
        c.CustomerID 

    /* */
    /* ResultSet #2 */ 
    /*All Order Information (for the specific orders in the @ordersWhichMetCriteriaTable table) */
    SELECT o.OrderID,o.CustomerID,o.EmployeeID,o.OrderDate,o.RequiredDate,o.ShippedDate,o.ShipVia ,o.Freight,o.ShipName,o.ShipAddress,o.OrderID,o.CustomerID,o.EmployeeID,o.OrderDate 
    FROM 
        Orders o 
     WHERE 
        exists (select null from @ordersWhichMetCriteriaTable innerHolder where innerHolder.OrderID = o.OrderID )
    ORDER BY 
        o.CustomerID , o.OrderID 

    /* */
    /* ResultSet #3 */
    /* All Order Detail Information (for the specific orders in the @ordersWhichMetCriteriaTable table) */
     SELECT od.OrderID,od.ProductID,od.UnitPrice,od.Quantity,od.Discount 
     FROM 
        [Order Details] od 
     WHERE 
        exists (select null from @ordersWhichMetCriteriaTable innerHolder where innerHolder.OrderID = od.OrderID )
     ORDER BY 
        od.OrderID 


END

GO 


/* */
/*  The user stored procedure definition is above, the use of the user stored procedure is below.  */
/*  (Put the below code in a new Query Analyser window) */
/*  "How to Use" the procedure above. (Put this code in a new Query Analyser window.) */

/* */

Use Northwind
GO

/* no parameters */
print 'No Filters, Just Give me back all the Data'
EXEC uspOrderDetailsGetByXmlParams '
<ParametersDS>
</ParametersDS>
'

GO


/* just CustomerID */
print 'Filter on specific Customers'
EXEC uspOrderDetailsGetByXmlParams '
<ParametersDS>

 <Customer>
  <CustomerID>CENTC</CustomerID>
 </Customer>
 <Customer>
  <CustomerID>GROSR</CustomerID>
 </Customer>


</ParametersDS>
'


GO



/* Order Dates (Before) */
print 'Filter on the OrderDates being Before'
EXEC uspOrderDetailsGetByXmlParams '
<ParametersDS>
 <SingleValueParam>
  <OrderDateBefore>7/7/1996</OrderDateBefore>
 </SingleValueParam>
</ParametersDS>
'

GO

/* Order Dates (After) */
print 'Filter on the OrderDates being After'
EXEC uspOrderDetailsGetByXmlParams '
<ParametersDS>
 <SingleValueParam>
  <OrderDateAfter>5/5/1998</OrderDateAfter>
 </SingleValueParam>
</ParametersDS>
'

GO


/* Order Dates (both) */
print 'Filter on the OrderDates being (before and after) the input dates'
EXEC uspOrderDetailsGetByXmlParams '
<ParametersDS>
 <SingleValueParam>
  <OrderDateBefore>12/31/1997</OrderDateBefore>
  <OrderDateAfter>1/1/1997</OrderDateAfter>
 </SingleValueParam>
</ParametersDS>
'

GO





print 'Filter on specific OrderIDs'
EXEC uspOrderDetailsGetByXmlParams '
<ParametersDS>

 <Order>
  <OrderID>10265</OrderID>
 </Order>
 <Order>
  <OrderID>10267</OrderID>
 </Order>
 <Order>
  <OrderID>10269</OrderID>
 </Order>

</ParametersDS>
'


GO

/* Specific Countries */
print 'Filter on specific Countries'
EXEC uspOrderDetailsGetByXmlParams '
<ParametersDS>

 <CustomerCountry>
  <CountryName>Austria</CountryName>
 </CustomerCountry>

 <CustomerCountry>
  <CountryName>Belgium</CountryName>
 </CustomerCountry>


</ParametersDS>
'
GO



/* Specific Countries */
print 'Filter on specific Countries and OrderDate'
EXEC uspOrderDetailsGetByXmlParams '
<ParametersDS>

 <CustomerCountry>
  <CountryName>AustriA</CountryName>
 </CustomerCountry>

 <CustomerCountry>
  <CountryName>BelgiuM</CountryName>
 </CustomerCountry>

 <SingleValueParam>
  <OrderDateBefore>2/28/1997</OrderDateBefore>
  <OrderDateAfter>1/1/1997</OrderDateAfter>
 </SingleValueParam>

</ParametersDS>
'







print 'Order ID that does not exist'
EXEC uspOrderDetailsGetByXmlParams '
<ParametersDS>

 <Order>
  <OrderID>-9999</OrderID>
 </Order>


</ParametersDS>
'


GO

/*  END TSQL CODE  */
于 2013-11-11T21:03:22.767 回答