9

私は、従業員データベースを照会する仕事用のアプリケーションに取り組んでいます。エンド ユーザーは、標準の名前/部門の基準に基づいて検索できる機能を望んでいますが、健康部門で働く "James" というファーストネームを持つすべての人を柔軟に照会できることも望んでいます。私が避けたいことの 1 つは、単純にストアド プロシージャにパラメーターのリストを取り、実行する SQL ステートメントを生成させることです。これは、内部レベルでの SQL インジェクションへの扉を開くためです。

これはできますか?

4

10 に答える 10

19

トリックはきちんとしてCOALESCEいますが、私の好みの方法は次のとおりです。

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 + '%')

この種の SP は、簡単にコードを生成 (およびテーブル変更のために再生成) できます。

正確なセマンティクスまたは検索セマンティクスが必要かどうかに応じて、数値を処理するためのいくつかのオプションがあります。

于 2008-10-15T17:16:24.160 に答える
10

このタイプの検索を実装する最も効率的な方法は、ストアド プロシージャを使用することです。ここに示すステートメントは、必要なパラメーターを受け入れるプロシージャーを作成します。パラメータ値が指定されていない場合は、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)

このページからの抜粋: http://www.sqlteam.com/article/implementing-a-dynamic-where-clause

以前やったことがあります。それはうまくいきます。

于 2008-10-15T17:00:29.047 に答える
6

Erland Sommarskog の記事Dynamic Search Conditions in T-SQLは、これを行う方法についての良い参考資料です。Erland は、動的 SQL (単純な IF ブロック、OR、COALESCE など) を使用せずにこれを行う方法について多くの戦略を提示し、各手法のパフォーマンス特性をリストアップしています。

やむを得ず動的 SQL パスを通過する必要がある場合は、Erland のCurse and Blessings of Dynamic SQLも読む必要があります。ここでは、動的 SQL を適切に記述する方法に関するヒントがいくつか紹介されています。

于 2008-10-15T17:10:28.043 に答える
3

COALESCE メソッドを使用すると、列に NULL 値がある場合に NULL 検索条件を渡す (つまり、検索条件を無視する) と、多くのデータベースで行が返されないという問題があります。

たとえば、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

列 my_string が NULL である行では効果的に取得できるため、2 行しか返されません。

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

しかしもちろん、NULL は NULL と同じではありません。

私は固執しようとします:

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

もちろん、それを調整して、ワイルドカードを使用したり、その他のやりたいことをしたりできます。

于 2008-10-15T18:14:18.180 に答える
3

実行することはできますが、通常、これらのキッチンシンクの手順では、クエリプランが不十分になります。

とはいえ、「オプションの」パラメーターに最も一般的に使用される戦術は次のとおりです。通常のアプローチは、NULL を「省略」として扱うことです。

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)

編集: はるかに優れたアプローチは、パラメーター化されたクエリです。これは、この分野における世界有数の権威の 1 人である、LLBLGen Pro で有名な Frans Bouma のブログ投稿です。

ストアド プロシージャと動的クエリ

于 2008-10-15T17:03:02.190 に答える
0

私のブログ投稿からこれをコピーします:

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
于 2015-02-12T05:56:34.640 に答える
0

ジェネリック @Search パラメーターを使用して、検索用に任意の値を渡すことができます。

GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: --
-- Create date:
-- Description: --
-- =============================================
CREATE PROCEDURE [dbo].[usp_StudentList]
    @PageNumber INT    = 1, -- Paging parameter
    @PageSize   INT    = 10,-- Paging parameter
    @Search  VARCHAR(MAX) = NULL, --Generic Search Parameter
    @OrderBy VARCHAR(MAX) = 'FirstName', --Default Column Name 'FirstName' for records ordering
    @SortDir VARCHAR(MAX) = 'asc' --Default ordering 'asc' for records ordering
AS
BEGIN
    SET NOCOUNT ON;

    --Query required for paging, this query used to show total records
    SELECT COUNT(StudentId) AS RecordsTotal FROM Student

    SELECT Student.*, 
        --Query required for paging, this query used to show total records filtered
        COUNT(StudentId) OVER (PARTITION BY 1) AS RecordsFiltered 
    FROM Student
    WHERE 
    --Generic Search 
    -- Below is the column list to add in Generic Serach
    (@Search IS NULL OR Student.FirstName LIKE '%'+ @Search +'%')
    OR (@Search IS NULL OR Student.LastName LIKE '%'+ @Search +'%')
    --Order BY
    -- Below is the column list to allow sorting
    ORDER BY 
    CASE WHEN @SortDir = 'asc' AND @OrderBy = 'FirstName' THEN Student.FirstName END,
    CASE WHEN @SortDir = 'desc' AND @OrderBy = 'FirstName' THEN Student.FirstName  END DESC,
    CASE WHEN @SortDir = 'asc' AND @OrderBy = 'LastName' THEN Student.LastName END,
    CASE WHEN @SortDir = 'desc' AND @OrderBy = 'LastName' THEN Student.LastName  END DESC,
    OFFSET @PageSize * (@PageNumber - 1) ROWS FETCH NEXT @PageSize ROWS ONLY;
END
于 2018-01-17T12:52:26.353 に答える
-1

私の最初の考えは、このようなクエリを書くことでした...

SELECT EmpId, NameLast, NameMiddle, NameFirst, DepartmentName
  FROM dbo.Employee
       INNER JOIN dbo.Department ON dbo.Employee.DeptId = dbo.Department.Id
 WHERE IdCrq IS NOT NULL
       AND
       (
          @bitSearchFirstName = 0
          OR
          Employee.NameFirst = @vchFirstName
       )
       AND
       (
          @bitSearchMiddleName = 0
          OR
          Employee.NameMiddle = @vchMiddleName
       )
       AND
       (
          @bitSearchFirstName = 0
          OR
          Employee.NameLast = @vchLastName
       )
       AND
       (
          @bitSearchDepartment = 0
          OR
          Department.Id = @intDeptID
       )

...特定のフィールドを検索する場合は呼び出し元にビットフラグを提供させ、検索する場合は値を提供しますが、これがずさんな WHERE 句を作成しているのか、それともWHERE 句に CASE ステートメントを使用することで問題を解決できます。

ご覧のとおり、この特定のコードは T-SQL にありますが、喜んで PL-SQL / MySQL コードもいくつか見て、それに応じて適応させます。

于 2008-10-15T16:59:26.067 に答える
-1

アドホック クエリでは NULL/COALESCE メソッドを使い続け、パフォーマンスの問題がないことを確認するためにテストします。

インデックス付きの列を検索しているときにテーブル スキャンを実行しているためにクエリの実行が遅いことが判明した場合は、これらのインデックス付きフィールドでの検索を可能にする追加の特定のストアド プロシージャで、汎用検索ストアド プロシージャをいつでも補足できます。たとえば、CustomerID または姓/名で検索する特別な SP を持つことができます。

于 2008-10-15T17:18:36.107 に答える
-3

名前が A で始まるすべての従業員データをテーブルに挿入する手順を記述しますか??

于 2016-02-17T06:55:19.203 に答える