【问题标题】:T-SQL Global / Shared DataT-SQL 全局/共享数据
【发布时间】:2009-03-04 21:34:39
【问题描述】:

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

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

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

谢谢。

【问题讨论】:

    标签: sql-server tsql


    【解决方案1】:

    我经常想要类似的东西,但具体不存在。以下是您可以做的几件事。

    选项 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
    

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

    希望对您有所帮助! 伊恩

    【讨论】:

      【解决方案2】:

      对于 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, @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
      

      【讨论】:

        【解决方案3】:

        你通常会为你想要完成的事情创建一个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

        【讨论】:

          【解决方案4】:

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

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

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

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

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-09-29
            • 1970-01-01
            • 2019-01-15
            • 2019-12-27
            • 1970-01-01
            • 2012-08-10
            相关资源
            最近更新 更多