2009-03-04 4 views
0

Wenn ich gespeicherte TSQL-Prozeduren schreibe, möchte ich einige Teile des Codes zentralisieren/normalisieren. wenn ich eine Abfrage wie folgt Zum Beispiel haben:T-SQL Global/Gemeinsame Daten

SELECT * FROM SomeTable WHERE SomeColumn IN (2, 4, 8) 

für Fälle wie diesen würde ich setzen möchte (2,4,8) in einem Ort außerhalb des Verfahrens, dass ich später in einer anderen Abfrage wiederverwenden könnte - um Wiederholungen zu vermeiden. Gibt es eine eingebaute Möglichkeit, dies zu tun? Was wäre wirklich toll, wenn ich ganze Teile von SQL-Code, wie Teile der WHERE-Klausel, auseinander brechen und diese in anderen Abfragen wiederverwenden könnte, aber ich bezweifle, dass dies möglich ist.

Danke.

Antwort

2

Ich wollte oft eine ähnliche Sache, aber das existiert nicht spezifisch. Hier sind ein paar Dinge, die Sie können tun können.

Option 1

Was wir haben, ist User Defined Functions (UDF) zu sammeln, was man nennen könnte globale Variablen gemacht verwendet.

Sie sind in der Lage eine UDF inline innerhalb Ihrer Anfrage zu nennen, die es wirklich nützlich macht.

Angenommen, Sie einen Servernamen angeben wollte, die Sie über mehrere gespeicherte Prozeduren verwenden würde. Die Duplizierung dieses Werts wäre nicht optimal wartbar. Stattdessen könnte tun Sie so etwas wie:

select * from clientNodes where serverName = dbo.SOME_SERVER_NAME() 

Option 2

Dieser ist mehr offensichtlich, aber erwähnenswert,. Bewahren Sie Ihre Werte in einer Nachschlagetabelle auf und referenzieren Sie sie anhand einer ID. Die ID würde sich nicht ändern, aber der Wert, auf den sie verweist, könnte. Unter Verwendung der Probe Beispiel wie oben, aber für diese Option:

Table: Servers 
Columns: ServerID, ServerName 

declare @serverName varchar(50) 
select @serverName = ServerName from Servers where ServerID = 1 

Dies ist ein typischer Ansatz zur Datenbank Normalisierung aber die Menschen über diese für Zwecke des Haltens DB-Logik Daten zentralisiert nicht unbedingt denken.

Ich hoffe, dass hilft! Ian

+0

+1 - Ich gehe mit UDFs, wenn ich dieses Problem habe – annakata

0

Mit SQL Server 2005 können Sie mit einer Tabellenwertfunktion in Betracht ziehen.

Z. B .:

SELECT ... FROM SomeTable INNER JOIN SomeFunction() F ON SomeTable.SomeColumn = F.Id 

... 

CREATE FUNCTION SomeFunction() 
RETURNS @IdTable TABLE (Id INT) 
AS 
RETURN 
(
    SELECT 2 Id 
    UNION ALL 
    SELECT 4 
    UNION ALL 
    SELECT 8 
) 

Häufiger, könnten Sie in den Werten als Argument an eine gespeicherte Prozedur übergeben werden soll. Sie können dies als eine durch Kommas getrennte Zeichenfolge tun. Z.B.

EXEC MyProcedure('2,4,8') 

... 

CREATE PROCEDURE MyProcedure 
(
    @IdString AS VARCHAR(MAX) 
) 
AS 
BEGIN 
    SELECT ... FROM SomeTable INNER JOIN SomeFunction(@IdString) F ON SomeTable.SomeColumn = F.Id 
END 

... 

CREATE FUNCTION dbo.SomeFunction 
(
    @IdString VARCHAR(MAX) 
) 
RETURNS @IdTable TABLE (Id INT) 
AS 
BEGIN 
    DECLARE @CommaIndex INT, @TotalLength INT, @StartIndex INT, @Id VARCHAR(10) 
    SET @TotalLength=LEN(@IdString) 
    SET @StartIndex = 1 

    WHILE @StartIndex <= @TotalLength 
    BEGIN 
     SET @CommaIndex = CHARINDEX(',', @IdString, @StartIndex) 
     IF @CommaIndex > 0 
     BEGIN 
      SET @Id = SUBSTRING(@IdString, @StartIndex, @[email protected]) 
      SET @StartIndex = @CommaIndex + 1 
     END 
     ELSE 
     BEGIN 
      Set @Id = SUBSTRING(@IdString, @StartIndex, @[email protected]+1) 
      SET @StartIndex = @TotalLength+1 
     END 
     INSERT INTO @IdTable 
     (Id) 
     VALUES 
     (CAST(@Id AS INT)) 
    END 

    RETURN 
END 
0

würden Sie in der Regel eine VIEW für schaffen, was Sie versuchen zu erreichen.

zuerst eine Funktion erstellen, die zurückgibt SomeColumn 2 Werte, 4, 8

create function fnSomeTableFilters() 
returns @Result table (ID int not null) 
as 

begin 
    insert @Result(ID) 
    select 2 
    union select 4 
    union select 8 

    return 
end 
GO 

Jetzt eine Ansicht erstellen, 2,4,8-Filter

create view vwFilteredSomeTable 
as 
select * from SomeTable where SomeColumn in (select ID from dbo.fnSomeTableFilters()) 

Last, Ihre Anfrage wird

SELECT * FROM vwFilteredSomeTable 

Achten Sie darauf, Ihrer Ansicht einen aussagekräftigen Namen zu geben

z) Ich habe eine Ansicht namens vwActiveSites für Active Sites abfragen gegen als Name hier

create view vwActiveSites 
as 
    select ... 
    from Sites S 
    where S.Active = 1 

Die Schönheit legt nahe, dass, alle Ihre Anfragen, die vwFilteredSomeTable nicht ändern müssen, verwendet. Wenn Sie mit einem anderen Wert filtern müssen, müssen Sie nur fnSomeTableFilters müssen geändert werden

0

Ja - verwenden Sie eine Tabelle oder eine Ansicht. SomeColumn, das IN (2, 4, 8) ist, muss irgendwie zu Ihren Daten sinnvoll sein, also modellieren Sie es auf diese Weise. Geben Sie ihm einen aussagekräftigen Namen und Sie können ihn entweder selbst wiederverwenden oder mit anderen Abfragen verbinden. Warum vergräbt man es in einer UDF oder so?

ZB wenn SomeColumn Staat war und die Werte ('FL', 'GA', 'SC') waren Ihre Süd Ostgebieten, dann statt Verbreitung.

SELECT * FROM SomeTable WHERE State IN ('FL', 'GA', 'SC') 

ringsum, nur erstellen eine Gebietsspalte und damit fertig sein.

Wiederholte Verwendung eines statischen WHERE-Klausel ist eine andere Tabelle oder Attribut (aka ein Konzept) nur betteln, um herauskommen.