T-SQL全局/共享数据

时间:2009-03-04 21:34:39

标签: sql-server tsql

在编写TSQL存储过程时,我发现自己想要集中/规范化代码的某些部分。例如,如果我有这样的查询:

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

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

感谢。

4 个答案:

答案 0 :(得分: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

这是数据库规范化的典型方法,但人们不一定会考虑这一点,以保持数据库逻辑数据的集中化。

我希望有所帮助! 伊恩

答案 1 :(得分:0)

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

E.g:

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, @CommaIndex-@StartIndex)
            SET @StartIndex = @CommaIndex + 1
        END
        ELSE
        BEGIN
            Set @Id = SUBSTRING(@IdString, @StartIndex, @TotalLength-@StartIndex+1)
            SET @StartIndex = @TotalLength+1
        END
        INSERT INTO @IdTable
        (Id)
        VALUES
        (CAST(@Id AS INT))
    END

    RETURN
END

答案 2 :(得分: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

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

例如)我有一个名为vwActiveSites的视图,用于根据名称建议查询活动网站

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

这里的美妙之处在于,您使用 vwFilteredSomeTable 的所有查询都不需要更改。如果您需要使用不同的值进行过滤,则只需更改 fnSomeTableFilters

答案 3 :(得分:0)

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

例如,如果SomeColumn是State并且值('FL','GA','SC')是您的东南地区,那么而不是传播:

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

到处都是,只需创建一个Territory列并完成它。

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