有没有办法让SQL变量保持不变?
答案 0 :(得分:50)
不,但你可以在那里创建一个函数并对其进行硬编码并使用它。
以下是一个例子:
CREATE FUNCTION fnConstant()
RETURNS INT
AS
BEGIN
RETURN 2
END
GO
SELECT dbo.fnConstant()
答案 1 :(得分:17)
我对缺少常量的解决方法是给优化器提供有关值的提示。
DECLARE @Constant INT = 123;
SELECT *
FROM [some_relation]
WHERE [some_attribute] = @Constant
OPTION( OPTIMIZE FOR (@Constant = 123))
这告诉查询编译器在创建执行计划时将变量视为常量。缺点是你必须定义两次值。
答案 2 :(得分:15)
伪常数不是变量或参数。相反,他们是 只需查看一行,并有足够的列来支持您的 常量。使用这些简单的规则,SQL引擎完全忽略 视图的值,但仍然基于其构建执行计划 值。执行计划甚至不显示视图的连接!
答案 3 :(得分:9)
不,但应使用良好的旧命名约定。
declare @MY_VALUE as int
答案 4 :(得分:7)
T-SQL中没有对常量的内置支持。您可以使用SQLMenace的方法来模拟它(尽管您永远无法确定其他人是否已覆盖该函数以返回其他内容...),或者可能编写包含常量的表as suggested over here。也许编写一个触发器来回滚对ConstantValue
列的任何更改?
答案 5 :(得分:6)
在使用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
答案 6 :(得分:5)
如果您对获取变量值的最佳执行计划感兴趣,可以使用动态sql代码。它使变量保持不变。
DECLARE @var varchar(100) = 'some text'
DECLARE @sql varchar(MAX)
SET @sql = 'SELECT * FROM table WHERE col = '''+@var+''''
EXEC (@sql)
答案 7 :(得分:5)
对于枚举或简单常量,具有单行的视图具有出色的性能和编译时检查/依赖性跟踪(导致其列名称)
请参阅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 )
答案 8 :(得分:2)
好的,让我们看看
常量是不可变的值,它们在编译时是已知的,并且在程序的生命周期内不会改变
这意味着您在SQL Server中永远不会有常量
declare @myvalue as int
set @myvalue = 5
set @myvalue = 10--oops we just changed it
刚改变的值
答案 9 :(得分:1)
由于没有构建支持常量,我的解决方案非常简单。
由于不支持:
Declare Constant @supplement int = 240
SELECT price + @supplement
FROM what_does_it_cost
我只想将其转换为
SELECT price + 240/*CONSTANT:supplement*/
FROM what_does_it_cost
显然,这依赖于整个事物(没有尾随空格和注释的值)是唯一的。通过全局搜索和替换可以更改它。
答案 10 :(得分:0)
在数据库文献中没有“创建常量”这样的东西。常量按原样存在,通常称为值。可以声明一个变量并为其赋值(常量)。从学术观点来看:
DECLARE @two INT
SET @two = 2
这里@two是变量,2是值/常数。
答案 11 :(得分:-1)
最佳答案来自SQLMenace根据要求,如果要创建临时常量以在脚本中使用,即跨多个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