2009-03-04 79 views
0

在编写TSQL存储过程时,我发现自己希望集中/规范化代码的某些部分。举例来说,如果我有这样的查询:T-SQL全局/共享数据

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

对于这样的情况下,我想提出(2,4,8)在一些地方的程序之外,我可以重复使用在其他一些查询后 - 避免重复。有没有内置的方法来做到这一点?真正整洁的是,如果我可以分解整个SQL代码片段(如WHERE子句的一部分),并在其他查询中重用这些代码,但我怀疑这是可能的。

谢谢。

回答

2

我经常想要一个类似的东西,但具体不存在。这里有几件你可以做的。

选项1

我们所做的是使用用户定义函数(UDF)收集可以称之为全局变量。

您可以在查询中内联UDF,这使得它非常有用。

假设您想要指定跨多个存储过程使用的服务器名称。复制该值不会得到最佳维护。相反,你可以这样做:

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

选项2

这一个是比较明显的,但值得指出的。将您的值保存在查找表中并通过ID引用它。 ID不会改变,但它所指的值可能会改变。使用样品例如以上,但此选项:

Table: Servers 
Columns: ServerID, ServerName 

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

这是数据库规范化的典型做法,但人不一定想这对于保持集中DB-逻辑数据的目的。

我希望有帮助! Ian

+0

+1 - 当我遇到这个问题时我会用UDF – annakata 2009-03-04 21:53:15

0

在SQL Server 2005中,您可以考虑使用表值函数。

例如为:

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 
) 

更常见的是,你可能想在值作为参数传递给存储过程。你可以做成逗号分隔的字符串。例如。

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

你通常会为您创建试图完成什么VIEW

首先创建一个返回值SomeColumn功能2,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 

现在创建一个观点,即过滤2,4,8

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

最后,您的查询变得

SELECT * FROM vwFilteredSomeTable 

确保为您的视图提供有意义的名称

e.g)我有一个视图对查询活动网站叫vwActiveSites作为顾名思义

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

的美在这里的是,使用vwFilteredSomeTable您所有的疑问并不需要改变。如果你需要过滤不同的值,只需要fnSomeTableFilters需要更改

0

是的 - 使用表或视图。 SomeColumn是IN(2,4,8)必须以某种方式对您的数据有意义,所以这样建模。给它一个有意义的名字,你可以自己重用它或者加入其他查询。为什么把它埋在UDF或其他类似的东西里?

例如,如果SomeColumn是国家和值( 'FL', 'GA', 'SC')为您的南东部地区,然后,而不是传播:

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

周围的一切,只是创建一个地区专栏,并完成它。

重复使用静态WHERE子句是另一个表或属性(又名概念)只是乞求出来。