TSQL değişkenini sabit yapmanın bir yolu var mı?
TSQL değişkenini sabit yapmanın bir yolu var mı?
Yanıtlar:
Hayır, ancak bir işlev oluşturabilir ve onu orada kodlayabilir ve onu kullanabilirsiniz.
İşte bir örnek:
CREATE FUNCTION fnConstant()
RETURNS INT
AS
BEGIN
RETURN 2
END
GO
SELECT dbo.fnConstant()
WITH SCHEMABINDING
içinde CREATE FUNCTION
(function arayabilecek olan bir saklı yordam içinde aksine) deyimi - Bu doğru mu?
Jared Ko tarafından sunulan bir çözüm, sözde sabitleri kullanmaktır .
SQL Server'da açıklandığı gibi : Değişkenler, Parametreler veya Değişkenler? Veya… Sabitler? :
Sözde Sabitler, değişkenler veya parametreler değildir. Bunun yerine, tek satırlı görünümler ve sabitlerinizi desteklemek için yeterli sütunlardır. Bu basit kurallarla SQL Engine, görünümün değerini tamamen yok sayar, ancak yine de değerine dayalı olarak bir yürütme planı oluşturur. Uygulama planı, görünüme bir katılım bile göstermiyor!
Bunun gibi oluşturun:
CREATE SCHEMA ShipMethod GO -- Each view can only have one row. -- Create one column for each desired constant. -- Each column is restricted to a single value. CREATE VIEW ShipMethod.ShipMethodID 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]
O zaman şu şekilde kullanın:
SELECT h.* FROM Sales.SalesOrderHeader h JOIN ShipMethod.ShipMethodID const ON h.ShipMethodID = const.[OVERNIGHT J-FAST]
Veya bunun gibi:
SELECT h.* FROM Sales.SalesOrderHeader h WHERE h.ShipMethodID = (SELECT TOP 1 [OVERNIGHT J-FAST] FROM ShipMethod.ShipMethodID)
Eksik sabitler için çözümüm, optimize ediciye değer hakkında ipuçları vermektir.
DECLARE @Constant INT = 123;
SELECT *
FROM [some_relation]
WHERE [some_attribute] = @Constant
OPTION( OPTIMIZE FOR (@Constant = 123))
Bu, sorgu derleyicisine, değişkene yürütme planını oluştururken sabitmiş gibi davranmasını söyler. Olumsuz tarafı, değeri iki kez tanımlamanız gerektiğidir.
Hayır, ancak eski güzel adlandırma kuralları kullanılmalıdır.
declare @MY_VALUE as int
FN_CONSTANT()
. Bu şekilde ne yaptığı açıktır.
T-SQL'de sabitler için yerleşik destek yoktur. Simüle etmek için SQLMenace'in yaklaşımını kullanabilirsiniz (yine de başka birinin başka bir şey döndürmek için işlevin üzerine yazıp yazmadığından emin olamazsınız…) veya burada önerildiği gibi sabitler içeren bir tablo yazabilirsiniz . ConstantValue
Sütunda herhangi bir değişikliği geri alan bir tetikleyici yazabilir misiniz?
Bir SQL işlevini kullanmadan önce, performanstaki farklılıkları görmek için aşağıdaki komut dosyasını çalıştırın:
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
2760ms elapsed, using function
| 2300ms elapsed, using local variable
| 2286ms elapsed, using hard coded values
|
5570 elapsed, using function
| 406 elapsed, using local variable
| 383 elapsed, using hard coded values
| 3893 elapsed, using function without schemabinding
select top 1 @m = cv_val from code_values where cv_id = 'C101'
ve ... 'C201'
hepsi SQL-Server 2016'da vardı
Değişkendeki bir değer için en uygun yürütme planını almakla ilgileniyorsanız, dinamik bir sql kodu kullanabilirsiniz. Değişkeni sabit yapar.
DECLARE @var varchar(100) = 'some text'
DECLARE @sql varchar(MAX)
SET @sql = 'SELECT * FROM table WHERE col = '''+@var+''''
EXEC (@sql)
Numaralandırmalar veya basit sabitler için, tek satırlı bir görünüm müthiş bir performansa sahiptir ve derleme zamanı denetimi / bağımlılık takibi sağlar (çünkü bir sütun adıdır)
Jared Ko'nun blog gönderisine bakın https://blogs.msdn.microsoft.com/sql_server_appendix_z/2013/09/16/sql-server-variables-parameters-or-literals-or-constants/
görünümü yarat
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]
görünümü kullan
SELECT h.*
FROM Sales.SalesOrderHeader
WHERE ShipMethodID = ( select [OVERNIGHT J-FAST] from ShipMethods )
Tamam, görelim
Sabitler, derleme sırasında bilinen ve programın ömrü boyunca değişmeyen değişmez değerlerdir.
bu, SQL Server'da asla bir sabite sahip olamayacağınız anlamına gelir
declare @myvalue as int
set @myvalue = 5
set @myvalue = 10--oops we just changed it
değer az önce değişti
Sabitler için hiçbir yapı desteği olmadığından, çözümüm çok basit.
Bu desteklenmediğinden:
Declare Constant @supplement int = 240
SELECT price + @supplement
FROM what_does_it_cost
Ben onu basitçe
SELECT price + 240/*CONSTANT:supplement*/
FROM what_does_it_cost
Açıkçası, bu her şeyin (boşluk ve yorumun arkasına gitmeyen değer) benzersiz olmasına dayanır. Küresel arama ve değiştirme ile değiştirmek mümkündür.
Veritabanı literatüründe "sabit oluşturmak" diye bir şey yoktur. Sabitler oldukları gibi var olurlar ve genellikle değerler olarak adlandırılırlar. Bir değişken tanımlayabilir ve ona bir değer (sabit) atayabilir. Eğitimsel bir bakış açısıyla:
DECLARE @two INT
SET @two = 2
Burada @ iki bir değişkendir ve 2 bir değer / sabittir.
2
, "derleme zamanında" atandığında ikili bir değere çevrilir. Kodlanan gerçek değer, atandığı veri türüne bağlıdır (int, char, ...).
En iyi yanıt, komut dosyalarında, yani birden çok GO deyimi / toplu işinde kullanılmak üzere geçici bir sabit oluşturmaksa gereksinime göre SQLMenace'den alınır.
Sadece tempdb'de yordamı oluşturun, ardından hedef veritabanı üzerinde hiçbir etkiniz olmaz.
Bunun pratik bir örneği, mantıksal şema sürümünü içeren komut dosyasının sonuna bir kontrol değeri yazan bir veritabanı oluşturma betiğidir. Dosyanın en üstünde, değişiklik geçmişi vb. İçeren bazı yorumlar var ... Ancak pratikte çoğu geliştirici, aşağı kaydırmayı ve dosyanın altındaki şema sürümünü güncellemeyi unutacaktır.
Yukarıdaki kodun kullanılması, görünür bir şema sürüm sabitinin, veritabanı komut dosyası (SSMS'nin komut dosyası oluşturma özelliğinden kopyalanan) veritabanını oluşturmadan önce en üstte tanımlanmasına izin verir, ancak sonunda kullanılır. Bu, değişiklik geçmişinin ve diğer yorumların hemen yanında geliştiricinin karşısındadır, bu nedenle güncelleme olasılıkları çok yüksektir.
Örneğin:
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
WITH SCHEMABINDING
bunu 'gerçek' bir sabite dönüştürmelidir (bir UDF'nin SQL'de deterministik olarak görülmesi için bir gereklilik). Yani önbelleğe alınmalı. Yine de +1.