2008-10-15 5 views
9

저는 직원 데이터베이스를 쿼리 할 작업에 대한 응용 프로그램을 만들고 있습니다. 최종 사용자는 표준 이름/부서 기준에 따라 검색하는 기능을 원하지만 건강 부서에서 근무하는 "James"라는 이름을 가진 모든 사람들을 쿼리 할 수있는 유연성을 원합니다. 필자가 피하고자하는 한 가지 점은 저장 프로 시저에 매개 변수 목록을 가져 와서 실행할 SQL 문을 생성하면 SQL 문을 내부 수준에서 열 수 있기 때문입니다.선택적으로 열을 검색 할 저장 프로 시저를 어떻게 만듭니 까?

이 작업을 수행 할 수 있습니까? 그들이 제공 한 후 특정 필드를 검색하려면 다음 호출자가 비트 플래그를 제공 할 것이다 내 첫번째 생각이 같은 쿼리 뭔가를 작성했다

+0

는 내가 목표 테이블에 NULL 데이터 값을 많이 가지고 있기 때문에 케이드 루의 솔루션은 나에게 가장 일한 여기에 언급 싶었지만, 나는 모든 데이터가 있다면 유착이 어떻게 작동하는지 잘 볼 수있는 내 열, 그래서 BoltBait의 솔루션에 upvote 확실히 장점을 보증합니다. –

+1

아론 버트 랜드 (Aaron Bertrand)는 이것을 "주방 싱크 절차"라고 부르며 http://sqlsentry.tv/the-kitchen-sink-procedure/ 및 http : // blogs에서 볼 수있는 이런 유형의 문제를 다루는 좋은 생각을 갖고 있습니다. .sqlsentry.com/aaronbertrand/backtobasics-updated-kitchen-sink-example /. – JamieSee

답변

16

를 작성하는 방법에 대한 몇 가지 도움말을 제공 곳 읽어야한다, 총알을 물고 동적 SQL 경로를 통해 이동해야 나의 선호하는 방법은 다음과 같습니다 SP의 이러한 종류의 쉽게 코드를 생성 할 수 있습니다 (그리고 테이블 변경 재생성)

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

.

정확한 의미 체계 또는 검색 의미론을 원한다면 숫자를 처리 할 수있는 몇 가지 옵션이 있습니다.

+0

부서 ID 필드는 어떻게 작동합니까? int에 '%'를 사용할 수 있습니까? 아니면 다른 구문을 지정할 수 있습니까? –

+0

정확한 의미 체계 또는 검색 의미론을 원한다면 숫자를 처리 할 수있는 몇 가지 옵션이 있습니다. –

+0

방금 ​​절차에 대한 업데이트를 보았습니다. 감사!!! –

-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 코드도 기꺼이 살펴보고 그에 맞게 조정할 것입니다.

+0

나는 부정적인 표를받는이 쿼리에 무엇이 잘못되었는지 궁금한가요? –

+0

@Teomanshipahi 내 쿼리의 문제점은 두 개의 변수, 필드를 검색하기위한 비트 및 매개 변수 자체가 필요하다는 것입니다. 이는 매우 큰 저장 프로 시저 변수 바인딩을 만듭니다. 병합을 사용하면 쿼리하려는 각 필드에 대해 단일 변수를 사용할 수 있습니다. 나는이 스레드가 얼마나 오래된지를 고려하여 내 자신의 대답을 삭제해야한다고 생각한다.^D –

9

이러한 유형의 검색을 구현하는 가장 효율적인 방법은 저장 프로 시저입니다. 여기에 표시된 문은 필수 매개 변수를 받아들이는 프로 시저를 만듭니다. 매개 변수 값이 제공되지 않으면 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

. 잘 작동한다.

+0

나는 이것들이 잘 작동한다고 생각하지 않는다. 이러한 술어는 SARGable이 아니기 때문에 테이블 스캔의 상당 부분을 차지합니다. –

+0

값이 NULL로 설정되었다고 할 때, 열 이름에서 NULL을 검색한다는 의미입니까 아니면 무시됩니다. 필자가 볼 수있는 유일한 관심사는 SchoMo의 성을 가진 사람들을 찾고있는 것입니다. 이름이 "Joe"인 것은 값이 NULL이 아니기 때문에 제외 될 것입니다. –

+0

Dillie-O, 왜 COALESCE 명령을 사용하여이 기능이 작동하는지 확인하십시오 (또는 내 게시물에 제공된 링크를 따르십시오).이런 유형의 성능에 관해서는 ... 제가 구현 한 시스템은 1 ~ 2 백만 행이 있었고 정상적으로 작동했습니다. 그것은 전혀 느리게 보이지 않았다. YMMV. – BoltBait

2

이 작업을 수행 할 수는 있지만 대개 이러한 주방 싱크 절차로 인해 쿼리 계획이 잘못되었습니다.

모든 것을 말하자면, 여기에 "선택적"매개 변수로 가장 일반적으로 사용되는 전술이 있습니다. 정상적인 접근 방식은 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) 

편집 : 중 파 더 좋은 방법은 매개 변수가있는 쿼리 될 것이다. 다음 LLBLGen 프로 명성에서이 도메인에서 세계 최고의 기관 중 하나에서 블로그 게시물, 프랑스어 보우마입니다 :

Stored Procedures vs. Dynamic Queries

+0

이전 대답에서는 이러한 것들이 잘 작동하지 않는다고 했습니까? 글 머리 기호를 물었거나, 입력을 살핍 적으로 처리하고 AdHoc 쿼리를 작성하거나, 모든 다른 옵션에 대해보다 전문화 된 절차를 작성했다고 생각하십니까? –

+0

이것이 ORM (Object Relational Model) 시스템이 유행을 그리는 이유 중 하나입니다. 대부분 동적 쿼리 생성을 사용하지만 주입 문제가 발생하지 않도록 매개 변수화를 사용합니다. 매개 변수가있는 쿼리를 확인하십시오. 이 경우에 당신을 더 잘 섬길 수 있습니다. –

5

ERLAND Sommarskog의 기사 Dynamic Search Conditions in T-SQL이 작업을 수행하는 방법에 대한 좋은 참고가된다. Erland는 동적 SQL (단순한 IF 블록, OR, COALESCE 등)을 사용하지 않고이 작업을 수행하는 방법에 대한 여러 가지 전략을 제시하고 각 기법의 성능 특성을 나열합니다. 경우

당신은, 당신은 또한 ERLAND의 Curse and Blessings of Dynamic SQL 그가 COALESCE 트릭 깔끔한 동안 제대로 동적 SQL을

+0

그레이트 참조! 나는 항상 Erland Sommarskog의 작품을 즐긴다. –

-1

AdHoc 쿼리를 통해 NULL/COALESCE 메서드를 사용하고 성능 문제가 없는지 테스트합니다.

인덱싱 된 열에서 검색 할 때 테이블 검색을 수행하기 때문에 실행 속도가 느린 것으로 밝혀지면 일반 검색 저장 프로 시저에 항상 이러한 특정 인덱스가있는 검색을 허용하는 추가 검색 저장 프로 시저를 보완 할 수 있습니다 전지. 예를 들어 CustomerID 또는 성/이름으로 검색하는 특수 SP를 가질 수 있습니다.

+0

검색 화면에 30 개의 필드가있는 CRM 응용 프로그램을 사용했습니다. 순열은 거기서 너에게 작용한다. ORM은이 영역에서 빛납니다. –

+0

각 순열마다 다른 SP를 만들 것을 제안하는 것은 아닙니다. (그것은 2^30 개의 저장 프로 시저가 될 것입니다). 사용자가 CustomerID로 검색하는 경우 특별한 사례 SP가있는 것이 합리적이라고 생각하지 않습니까? – Aheho

+0

다시 말하지만, CustomerID가있는 경우 COALESCE 메서드가 차선의 쿼리 계획을 생성한다는 사실을 알게 된 경우에만이 제안을 제안합니다. – Aheho

3

COALESCE 메서드를 사용하면 열에 NULL 값이 있으면 NULL 검색 조건 (검색 조건 무시)이 많은 데이터베이스의 행을 반환하지 않는다는 점에서 문제가 있습니다.

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 인 행이 점점 효과가 다시 두 행을 얻을 것이다 :

예를 들어, SQL Server에서 다음 코드 2000를 시도

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) 

는 물론, 당신이 당신이 원하는 와일드 카드 또는 어떤 다른 사람을 사용하여 조정할 수 있습니다.

+0

잘 설명합니다. –

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 
-3

이름 테이블의로 시작하는 모든 직원 데이터를 삽입하는 절차를 쓰기?

0

Generic @Search Parameter를 사용하여 검색을 위해 값을 전달할 수 있습니다.

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 
관련 문제