2008-10-15 14 views
9

मैं अपने कर्मचारी डेटाबेस से पूछताछ करने वाले काम के लिए एक आवेदन पर काम कर रहा हूं। अंतिम उपयोगकर्ता मानक नाम/विभाग मानदंडों के आधार पर खोज करने की क्षमता चाहते हैं, लेकिन वे स्वास्थ्य विभाग में काम करने वाले "जेम्स" के पहले नाम वाले सभी लोगों के लिए लचीलापन भी चाहते हैं। एक चीज जिसे मैं टालना चाहता हूं, बस संग्रहीत प्रक्रिया को पैरामीटर की एक सूची लेना और निष्पादित करने के लिए एक SQL कथन उत्पन्न करना है, क्योंकि इससे आंतरिक स्तर पर एसक्यूएल इंजेक्शन के लिए दरवाजे खुल जाएंगे।मैं एक संग्रहीत प्रक्रिया कैसे बना सकता हूं जो वैकल्पिक रूप से कॉलम खोजेगा?

क्या यह किया जा सकता है?

+0

मुझे लगता है कि कैड रॉक्स के समाधान मेरे लिए सबसे अच्छा काम किया के बाद से मैं लक्ष्य तालिका में शून्य डेटा मानों का एक बहुत था यहाँ उल्लेख करना चाहता था, लेकिन मैं देख सकता है कितनी अच्छी तरह COALESCE अगर मैं के सभी में डेटा था काम करेगा मेरी कॉलम, इसलिए बोल्टबेट के समाधान पर उपरोक्त निश्चित रूप से योग्यता की गारंटी देता है। –

+1

हारून बर्ट्रैंड ने इसे "रसोई सिंक प्रक्रिया" कहा है और इस प्रकार की समस्या से निपटने के कुछ अच्छे विचार हैं जिन्हें http://sqlsentry.tv/the-kitchen-sink-procedure/ और http: // ब्लॉग पर देखा जा सकता है .sqlsentry.com/aaronbertrand/backtobasics अद्यतन-रसोई-सिंक-उदाहरण /। – JamieSee

उत्तर

16

लिखने के लिए एक ओर जहां 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 + '%') 

इस प्रकार के एसपी आसानी से कोड उत्पन्न हो सकते हैं (और तालिका-परिवर्तनों के लिए पुनः उत्पन्न)।

आपके पास संख्याओं को संभालने के लिए कुछ विकल्प हैं - यदि आप सटीक अर्थशास्त्र चाहते हैं या खोज अर्थशास्त्र चाहते हैं।

+0

यह मेरे विभाग आईडी फ़ील्ड के लिए कैसे काम करेगा? क्या मैं 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 खंड में एक केस स्टेटमेंट से दूर हो सकता हूं।

जैसा कि आप देख सकते हैं कि यह विशेष कोड टी-एसक्यूएल में है, लेकिन मैं खुशी से कुछ पीएल-एसक्यूएल/माईएसक्यूएल कोड भी देखूंगा और तदनुसार अनुकूलित करूँगा।

+0

मैं बस सोच रहा हूं कि इस प्रश्न के साथ क्या गलत है जो नकारात्मक वोट प्राप्त करता है? –

+0

@Teomanshipahi मेरी क्वेरी के साथ समस्या यह है कि इसमें दो चर की आवश्यकता होती है, फ़ील्ड को खोजने के लिए थोड़ा और फिर पैरामीटर स्वयं, जो एक बहुत बड़ी संग्रहित प्रक्रिया परिवर्तनीय बांध के लिए बनाता है। कोलेसेस का उपयोग करके, आप प्रत्येक फ़ील्ड के लिए एक वैरिएबल का उपयोग कर सकते हैं जिसे आप क्वेरी करना चाहते हैं। मुझे लगता है कि मुझे अपना जवाब हटा देना चाहिए कि यह धागा कितना पुराना है 8^डी –

9

इस प्रकार की खोज को लागू करने का सबसे प्रभावी तरीका संग्रहीत प्रक्रिया के साथ है। यहां दिखाया गया बयान एक ऐसी प्रक्रिया बनाता है जो आवश्यक पैरामीटर स्वीकार करता है। जब पैरामीटर मान की आपूर्ति नहीं की जाती है तो यह पूर्ण पर सेट होती है।

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 की खोज है या इसे अनदेखा कर दिया जाता है। इसके साथ एकमात्र चिंता यह है कि अगर मैं श्मो के अंतिम नाम के साथ लोगों की तलाश कर रहा हूं, तो "जो" का पहला नाम शामिल नहीं किया जा रहा है क्योंकि मान शून्य नहीं है। –

+0

डिली-ओ, यह देखने के लिए COALESCE कमांड देखें कि यह क्यों काम करता है (या मेरे पोस्ट में दिए गए लिंक का पालन करें)।इस प्रकार की चीज़ के प्रदर्शन के लिए ... जिस प्रणाली को मैंने कार्यान्वित किया था, उसके बीच 1 और 2 मिलियन पंक्तियों के बीच था और यह ठीक काम करता था। यह बिल्कुल धीमा नहीं लग रहा था। YMMV। – BoltBait

2

यह किया जा सकता है, लेकिन आमतौर पर इन रसोई-सिंक प्रक्रियाओं के परिणामस्वरूप कुछ खराब क्वेरी योजनाएं होती हैं।

यह सब कहकर, यहां "वैकल्पिक" पैरामीटर के लिए सबसे अधिक उपयोग की जाने वाली रणनीति है। सामान्य दृष्टिकोण न्यूल को "ओमटेड" के रूप में पेश करना है।

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 प्रो प्रसिद्धि Frans बाउमा है:

Stored Procedures vs. Dynamic Queries

+0

पिछले जवाब में, आपने कहा था कि ये अच्छी तरह से काम नहीं करते हैं, क्या आपको लगता है कि मैं सिर्फ बुलेट काटता हूं, बहुत से इनपुट को संवेदीकरण करता हूं और एक एडहोक क्वेरी बनाता हूं, या सभी अलग-अलग विकल्पों के लिए और अधिक विशिष्ट प्रक्रियाएं बनाता हूं? –

+0

ठीक है, यह एक कारण है कि ओआरएम (ऑब्जेक्ट रिलेशनल मॉडल) सिस्टम वास्तव में दृढ़ता से प्रचलित रूप से आ रहे हैं। उनमें से अधिकांश गतिशील क्वेरी पीढ़ी का उपयोग करते हैं, लेकिन वे पैरामीटरकरण का उपयोग करते हैं ताकि आपको इंजेक्शन के मुद्दे न मिले। पैरामीटरयुक्त प्रश्नों को देखें। इससे आपको इस मामले में बेहतर सेवा मिल सकती है। –

5

Erland Sommarskog के लेख Dynamic Search Conditions in T-SQL ऐसा करने के तरीके पर एक अच्छा संदर्भ है। एरलैंड गतिशील एसक्यूएल (केवल सादा आईएफ ब्लॉक, या, कोलेसे, इत्यादि) का उपयोग किये बिना इसे कैसे करें और यहां तक ​​कि प्रत्येक तकनीक की प्रदर्शन विशेषताओं को सूचीबद्ध करने के बारे में कई रणनीतियों को प्रस्तुत करता है।

मामले में आप गोली काटने और गतिशील एसक्यूएल पथ के माध्यम से जाना है, तो आप भी पढ़ना चाहिए Erland के Curse and Blessings of Dynamic SQL जहां वह कैसे ठीक गतिशील SQLs

+0

महान संदर्भ! मैं हमेशा एरलैंड सोमरस्क के काम का आनंद लेता हूं। –

-1

मैं एडहोक क्वेरीज़ पर न्यूल/कोलेसेस विधि के साथ रहूंगा, और तब यह सुनिश्चित करने के लिए परीक्षण करूँगा कि आपके पास प्रदर्शन समस्याएं नहीं हैं।

यदि यह पता चला है कि आपके पास धीमी गति से चलने वाले प्रश्न हैं क्योंकि जब आप अनुक्रमित कॉलम पर खोज रहे हैं तो यह तालिका स्कैन कर रहा है, तो आप हमेशा सामान्य विशिष्ट संग्रहित प्रक्रिया के साथ जेनेरिक खोज संग्रहीत प्रक्रिया को पूरक कर सकते हैं जो इन अनुक्रमित खोजों को खोजने की अनुमति देते हैं खेत। उदाहरण के लिए, आपके पास एक विशेष एसपी हो सकती है जो ग्राहक आईडी, या अंतिम/प्रथम नाम द्वारा खोज करता है।

+0

के लिए देख रहा था मैंने सीआरएम अनुप्रयोगों के साथ काम किया है जहां खोज स्क्रीन में 30 फ़ील्ड हैं। परमिट आपके खिलाफ काम करते हैं। ओआरएम इस क्षेत्र में चमकते हैं। –

+0

मैं यह सुझाव नहीं दे रहा हूं कि आप प्रत्येक क्रमपरिवर्तन के लिए एक अलग एसपी बनाएं। (वह 2^30 संग्रहीत प्रक्रिया होगी)। क्या आप इस बात से सहमत नहीं होंगे कि किसी उपयोगकर्ता द्वारा ग्राहक आईडी (जो मुझे लगता है अद्वितीय है) की खोज में एक विशेष मामला एसपी होना समझ में आता है? – Aheho

+0

दोबारा, मैं केवल यह सुझाव दे रहा हूं कि अगर उसे पता चलता है कि ग्राहक आईडी – Aheho

3

COALESCE विधि का उपयोग करने में एक समस्या है यदि आपके कॉलम में एक पूर्ण मूल्य है, जो एक पूर्ण खोज स्थिति (अर्थात् खोज स्थिति को अनदेखा करता है) में कई डेटाबेस में पंक्ति वापस नहीं करेगा।

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 शून्य है आप प्रभावी हो रही हैं में दो पंक्तियों मिल जाएगा:

उदाहरण के लिए, SQL सर्वर पर निम्नलिखित कोड 2000 कोशिश

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

लेकिन बेशक, न्यूल शून्य के बराबर नहीं है।

मैं के साथ छड़ी करने की कोशिश:

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

बेशक, आपको लगता है कि वाइल्ड कार्ड या जो कुछ भी आप करना चाहते हैं उपयोग करने के लिए समायोजित कर सकते हैं।

+0

अच्छा स्पष्टीकरण मौजूद है तो COALESCE विधि उप-इष्टतम क्वेरीप्लान का उत्पादन करती है। –

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

हम जेनेरिक @ खोज पैरामीटर का उपयोग कर सकते हैं और खोज के लिए इसके लिए कोई मूल्य पास कर सकते हैं।

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 
संबंधित मुद्दे

 संबंधित मुद्दे