TSQL 変数を定数にする方法はありますか?
12 に答える
No, but you can create a function and hardcode it in there and use that.
Here is an example:
CREATE FUNCTION fnConstant()
RETURNS INT
AS
BEGIN
RETURN 2
END
GO
SELECT dbo.fnConstant()
不足している定数に対する私の回避策は、値に関するヒントをオプティマイザーに与えることです。
DECLARE @Constant INT = 123;
SELECT *
FROM [some_relation]
WHERE [some_attribute] = @Constant
OPTION( OPTIMIZE FOR (@Constant = 123))
これにより、クエリ コンパイラは、実行プランの作成時に変数を定数であるかのように処理するように指示されます。欠点は、値を 2 回定義する必要があることです。
No, but good old naming conventions should be used.
declare @MY_VALUE as int
T-SQL には、定数の組み込みサポートはありません。SQLMenace のアプローチを使用してそれをシミュレートすることもできます (ただし、他の誰かが関数を上書きして別の何かを返すかどうかはわかりませんが…)、ここで提案されているように、定数を含むテーブルを作成することもできます。ConstantValue
おそらく、列への変更をロールバックするトリガーを作成しますか?
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
わかりました、見てみましょう
定数は、コンパイル時に認識され、プログラムの存続期間中変更されない不変の値です。
つまり、SQL Server で定数を使用することはできません。
declare @myvalue as int
set @myvalue = 5
set @myvalue = 10--oops we just changed it
値が変更されただけ
定数のサポートは組み込まれていないため、私の解決策は非常に単純です。
これはサポートされていないため:
Declare Constant @supplement int = 240
SELECT price + @supplement
FROM what_does_it_cost
私は単にそれをに変換します
SELECT price + 240/*CONSTANT:supplement*/
FROM what_does_it_cost
明らかに、これは全体 (末尾のスペースとコメントを除いた値) が一意であることに依存しています。グローバル検索と置換で変更できます。
データベースの文献には「定数を作成する」というようなものはありません。定数はそのまま存在し、しばしば値と呼ばれます。変数を宣言して、それに値 (定数) を割り当てることができます。学問的な観点から:
DECLARE @two INT
SET @two = 2
ここで @two は変数で、2 は値/定数です。
最良の答えは、スクリプト内で、つまり複数の GO ステートメント/バッチで使用する一時定数を作成する場合の要件に従って、SQLMenace からのものです。
tempdb でプロシージャを作成するだけで、ターゲット データベースに影響はありません。
この実用的な例の 1 つは、論理スキーマ バージョンを含むスクリプトの最後に制御値を書き込むデータベース作成スクリプトです。ファイルの上部には、変更履歴などのコメントがあります。しかし、実際には、ほとんどの開発者は、下にスクロールしてファイルの下部にあるスキーマ バージョンを更新することを忘れます。
上記のコードを使用すると、データベース スクリプト (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