Frage

Ich arbeite an einer Anwendung für die Arbeit, die unsere Mitarbeiter Datenbank abzufragen wird. Die Endbenutzer wollen, dass die Fähigkeit, auf der Basis des Standardnamen / Abteilung Kriterien suchen, aber sie wollen auch die Flexibilität für alle Menschen mit dem Vornamen „James“ abzufragen, die in der Abteilung Gesundheit arbeitet. Das einzige, was ich vermeiden wollen, ist einfach die gespeicherte Prozedur eine Liste von Parametern treffen und eine SQL-Anweisung zu generieren, auszuführen, da die Türen zu SQL-Injection auf interner Ebene öffnen würde.

Kann dies geschehen?

War es hilfreich?

Lösung

Während der COALESCE Trick ordentlich ist, meine bevorzugte Methode ist:

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

Diese Art von SPs leicht Code erzeugt werden kann (und erneut generiert für Tabellenänderungen).

Sie haben ein paar Optionen für den Umgang mit Zahlen - je nachdem, ob Sie genaue Semantik oder Such Semantik wollen

.

Andere Tipps

Der effizienteste Weg, um diese Art der Suche zu implementieren, ist mit einer gespeicherten Prozedur. Die folgende Anweisung erstellt eine Prozedur, die die erforderlichen Parameter akzeptiert. Wenn ein Parameterwert nicht angegeben wird es auf NULL gesetzt wird.

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)

auf dieser Seite genommen: http://www.sqlteam.com / article / Implementierung-a-dynamic-where-Klausel

Ich habe es vorher getan. Es funktioniert gut.

Erland Sommarskog des Artikel dynamische Suchbedingungen in T-SQL ist eine gute Referenz auf, wie dies zu tun. Erland präsentiert eine Reihe von Strategien, wie dies zu tun, ohne Verwendung von dynamischem SQL (einfach nur IF-Blöcke, OR, COALESCE, usw.) und sogar listet die Leistungsmerkmale jeder Technik aus.

Falls Sie haben den sauren Apfel beißen und die dynamische SQL-Weg zu gehen, sollten Sie auch Erland Fluch lesen und Segen von dynamischen SQL wo er einige Tipps, wie Sie gibt, um richtig dynamische SQLs schreiben

Es kann getan werden, aber in der Regel diese Küchenspüle Verfahren führen in einigen armen Abfragepläne.

Nachdem alles gesagt, dass, hier ist die Taktik am häufigsten für „optional“ Parameter verwendet. Der normale Ansatz ist NULL zu behandeln, als „weggelassen“.

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: Ein weitaus besserer Ansatz wäre parametrisierte Abfragen sein. Hier ist eine Blog-Post von einem der weltweit führenden Autoritäten auf diesem Gebiet, Frans Bouma von LLBLGen Pro Ruhm:

Stored Procedures vs. dynamische Abfragen

die COALESCE-Methode verwendet, hat ein Problem, dass, wenn Ihre Spalte einen NULL-Wert hat, in einer NULL-Suchbedingung vorbei (dh die Suchbedingung ignoriert) wird die Zeile nicht in vielen Datenbanken zurück.

Zum Beispiel, versuchen Sie den folgenden Code auf 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

Sie werden erst wieder zwei Reihen erhalten, weil in den Zeilen, in denen die Spalte my_string NULL Sie sind wirksam bekommen:

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

Aber natürlich NULL ist nicht gleich NULL.

Ich versuche, mit zu halten:

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

Natürlich können Sie einstellen, dass Wildcards zu verwenden, oder was auch immer Sie tun mögen.

Das Kopieren dieses von meiner 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

Wir Generisches @Search Parameter verwenden und jeden Wert, um es passieren für die Suche.

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

Mein erster Gedanke war, eine Abfrage, so etwas zu schreiben ...

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
       )

... die dann müsste der Anrufer eine Bit-Flag bereitstellen, wenn sie ein bestimmtes Feld gesucht werden soll und dann den Wert liefern, wenn sie danach suchen, aber ich weiß nicht, ob dies eine schlampige WHERE zu schaffen Klausel oder wenn ich mit einer CASE-Anweisung in der WHERE-Klausel weg erhalten kann.

Wie Sie dieser bestimmte Code in T-SQL sehen ist, aber ich werde schauen gerne irgend PL-SQL / MySQL-Code als auch und entsprechend anpassen.

würde ich mit der NULL / COALESCE Methode über AdHoc Abfragen bleiben, und dann sicher, dass Sie keine Probleme haben, die Leistung zu machen testen.

Wenn es sich herausstellt, dass Sie langsam laufende Abfragen haben, weil es einen Table-Scan tut, wenn man auf Spalt ist, die indiziert sind, können Sie immer ergänzen die generische Suche gespeicherte Prozedur mit zusätzlich spezifisch denjenigen, die auf diesen indizierten Feldern ermöglichen die Suche . Zum Beispiel könnten Sie eine spezielle SP haben die Suche nach CustomerID der Fall ist, oder Last / Vorname.

eine Prozedur schreibt alle Mitarbeiterdaten, dessen Anfang mit A in Tabelle einfügen ??

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top