代码之家  ›  专栏  ›  技术社区  ›  TheEmirOfGroofunkistan

有没有办法使tsql变量变为常量?

  •  74
  • TheEmirOfGroofunkistan  · 技术社区  · 18 年前

    有没有办法使tsql变量变为常量?

    12 回复  |  直到 18 年前
        1
  •  46
  •   dakab    11 年前

    不,但您可以创建一个函数并在其中对其进行硬编码并使用它。

    下面是一个例子:

    CREATE FUNCTION fnConstant()
    RETURNS INT
    AS
    BEGIN
        RETURN 2
    END
    GO
    
    SELECT dbo.fnConstant()
    
        2
  •  17
  •   neves    11 年前

    我对缺少常量的解决方法是向优化器提供有关值的提示。

    DECLARE @Constant INT = 123;
    
    SELECT * 
    FROM [some_relation] 
    WHERE [some_attribute] = @Constant
    OPTION( OPTIMIZE FOR (@Constant = 123))
    

    这会告诉查询编译器在创建执行计划时将变量视为常量。缺点是您必须定义值两次。

        3
  •  14
  •   Pixelated    11 年前

    使用伪常量: http://blogs.msdn.com/b/sql_server_appendix_z/archive/2013/09/16/sql-server-variables-parameters-or-literals-or-constants.aspx

    伪常量不是变量或参数。相反,他们是 只需使用一行和足够的列来支持 常量。使用这些简单的规则,SQL引擎将完全忽略 视图的值,但仍基于其 价值。执行计划甚至不显示视图的联接!

        4
  •  9
  •   jason saldo    18 年前

    不,但应该使用好的旧命名约定。

    declare @MY_VALUE as int
    
        5
  •  7
  •   Daniel Cassidy    14 年前

    T-SQL中没有对常量的内置支持。您可以使用sqlmenace的方法来模拟它(尽管您永远无法确定是否有其他人重写了函数以返回其他值),或者可能编写了一个包含常量的表, as suggested over here . 可能编写一个触发器,将对 ConstantValue 专栏?

        6
  •  6
  •   Robert    13 年前

    在使用SQL函数之前,请运行以下脚本以查看性能差异:

    IF OBJECT_ID('fnFalse') IS NOT NULL
    DROP FUNCTION fnFalse
    GO
    
    IF OBJECT_ID('fnTrue') IS NOT NULL
    DROP FUNCTION fnTrue
    GO
    
    CREATE FUNCTION fnTrue() RETURNS INT WITH SCHEMABINDING
    AS
    BEGIN
    RETURN 1
    END
    GO
    
    CREATE FUNCTION fnFalse() RETURNS INT WITH SCHEMABINDING
    AS
    BEGIN
    RETURN ~ dbo.fnTrue()
    END
    GO
    
    DECLARE @TimeStart DATETIME = GETDATE()
    DECLARE @Count INT = 100000
    WHILE @Count > 0 BEGIN
    SET @Count -= 1
    
    DECLARE @Value BIT
    SELECT @Value = dbo.fnTrue()
    IF @Value = 1
        SELECT @Value = dbo.fnFalse()
    END
    DECLARE @TimeEnd DATETIME = GETDATE()
    PRINT CAST(DATEDIFF(ms, @TimeStart, @TimeEnd) AS VARCHAR) + ' elapsed, using function'
    GO
    
    DECLARE @TimeStart DATETIME = GETDATE()
    DECLARE @Count INT = 100000
    DECLARE @FALSE AS BIT = 0
    DECLARE @TRUE AS BIT = ~ @FALSE
    
    WHILE @Count > 0 BEGIN
    SET @Count -= 1
    
    DECLARE @Value BIT
    SELECT @Value = @TRUE
    IF @Value = 1
        SELECT @Value = @FALSE
    END
    DECLARE @TimeEnd DATETIME = GETDATE()
    PRINT CAST(DATEDIFF(ms, @TimeStart, @TimeEnd) AS VARCHAR) + ' elapsed, using local variable'
    GO
    
    DECLARE @TimeStart DATETIME = GETDATE()
    DECLARE @Count INT = 100000
    
    WHILE @Count > 0 BEGIN
    SET @Count -= 1
    
    DECLARE @Value BIT
    SELECT @Value = 1
    IF @Value = 1
        SELECT @Value = 0
    END
    DECLARE @TimeEnd DATETIME = GETDATE()
    PRINT CAST(DATEDIFF(ms, @TimeStart, @TimeEnd) AS VARCHAR) + ' elapsed, using hard coded values'
    GO
    
        7
  •  5
  •   NDB Pickels    9 年前

    如果您对获取变量值的最佳执行计划感兴趣,可以使用动态SQL代码。它使变量变为常量。

    DECLARE @var varchar(100) = 'some text'
    DECLARE @sql varchar(MAX)
    SET @sql = 'SELECT * FROM table WHERE col = '''+@var+''''
    EXEC (@sql)
    
        8
  •  5
  •   monkeyhouse    7 年前

    对于枚举或简单常量,只有一行的视图具有很好的性能和编译时检查/依赖项跟踪(因为它是一个列名)

    查看Jared Ko的博客帖子 https://blogs.msdn.microsoft.com/sql_server_appendix_z/2013/09/16/sql-server-variables-parameters-or-literals-or-constants/

    创建视图

     CREATE VIEW ShipMethods AS
     SELECT CAST(1 AS INT) AS [XRQ - TRUCK GROUND]
       ,CAST(2 AS INT) AS [ZY - EXPRESS]
       ,CAST(3 AS INT) AS [OVERSEAS - DELUXE]
      , CAST(4 AS INT) AS [OVERNIGHT J-FAST]
       ,CAST(5 AS INT) AS [CARGO TRANSPORT 5]
    

    使用视图

    SELECT h.*
    FROM Sales.SalesOrderHeader 
    WHERE ShipMethodID = ( select [OVERNIGHT J-FAST] from ShipMethods  )
    
        9
  •  2
  •   SQLMenace    18 年前

    好吧,让我们看看

    常量是在编译时已知的不可变值,在程序的生命周期内不会改变。

    这意味着在SQL Server中永远不能有常量

    declare @myvalue as int
    set @myvalue = 5
    set @myvalue = 10--oops we just changed it
    

    值刚刚更改

        10
  •  1
  •   Gert-Jan    8 年前

    由于没有对常量的内置支持,所以我的解决方案非常简单。

    因为这是不支持的:

    Declare Constant @supplement int = 240
    SELECT price + @supplement
    FROM   what_does_it_cost
    

    我只要把它转换成

    SELECT price + 240/*CONSTANT:supplement*/
    FROM   what_does_it_cost
    

    显然,这依赖于整体(没有尾随空格和注释的值)是唯一的。可以通过全局搜索和替换进行更改。

        11
  •  0
  •   Greg Hurlman    18 年前

    数据库文献中没有“创建常量”这样的东西。常量按原样存在,通常称为值。可以声明一个变量并为其赋值(常量)。从学术角度来看:

    DECLARE @two INT
    SET @two = 2
    

    这里@two是一个变量,2是一个值/常量。

        12
  •  -1
  •   Tony Wall    13 年前

    最好的答案是根据需求从sqlmesance中得到,如果这是为了创建一个临时常量,以便在脚本中使用,即跨多个go语句/批处理。

    只需在tempdb中创建过程,就不会对目标数据库产生影响。

    其中一个实际的例子是数据库创建脚本,它在包含逻辑模式版本的脚本末尾写入控制值。在文件的顶部有一些带有更改历史等的注释…但实际上,大多数开发人员将忘记向下滚动并更新文件底部的模式版本。

    使用上面的代码,可以在数据库脚本(从SSMS的生成脚本功能复制)创建数据库之前在顶部定义一个可见的模式版本常量,但在末尾使用。这正是开发人员面对变更历史和其他评论时的情况,因此他们很可能会更新它。

    例如:

    use tempdb
    go
    create function dbo.MySchemaVersion()
    returns int
    as
    begin
        return 123
    end
    go
    
    use master
    go
    
    -- Big long database create script with multiple batches...
    print 'Creating database schema version ' + CAST(tempdb.dbo.MySchemaVersion() as NVARCHAR) + '...'
    go
    -- ...
    go
    -- ...
    go
    use MyDatabase
    go
    
    -- Update schema version with constant at end (not normally possible as GO puts
    -- local @variables out of scope)
    insert MyConfigTable values ('SchemaVersion', tempdb.dbo.MySchemaVersion())
    go
    
    -- Clean-up
    use tempdb
    drop function MySchemaVersion
    go