NOT NULL hesaplanmış bir sütun neden bir görünümde geçersiz sayılır?


15

Bir masam var:

CREATE TABLE [dbo].[Realty](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [RankingBonus] [int] NOT NULL,
    [Ranking]  AS ([Id]+[RankingBonus]) PERSISTED NOT NULL
    ....
)

Ve bir görüş:

CREATE View  [dbo].[FilteredRealty] AS
 SELECT 
realty.Id as realtyId,
...
COALESCE(realty.Wgs84X, ruian_cobce.Wgs84X, ruian_obec.Wgs84X) as Wgs84X,
COALESCE(realty.Wgs84Y, ruian_cobce.Wgs84Y, ruian_obec.Wgs84Y) as Wgs84Y,
realty.Ranking,
...
FROM realty
JOIN Category ON realty.CategoryId = Category.Id
LEFT JOIN ruian_cobce ON realty.cobceId = ruian_cobce.cobce_kod
LEFT JOIN ruian_obec ON realty.obecId = ruian_obec.obec_kod
LEFT JOIN okres ON realty.okresId = okres.okres_kod
LEFT JOIN ExternFile ON realty.Id = ExternFile.ForeignId AND ExternFile.IsMain = 1
                     AND ExternFile.ForeignTable = 5
INNER JOIN Person ON realty.OwnerId = Person.Id
WHERE Person.ConfirmStatus = 1

C # (LinqToSQL) içinde FilteredRealty görünümü ile bir dbml modeli var. [Sıralaması] alan null bir int olarak ve ben veritabanında herhangi bir değişiklik olduğunda oluşturulan kodun her zaman tipini düzeltmek zorunda tanınır. Bu benim için çok sinir bozucu ve bir sürü el işi.

FilteredRealty'de ( bu ilgili soru ile ilgili ) kullanılan hiçbir agrega yoktur .

Realty.Ranking boş bırakılamazsa görünümün Sıralama sütunu neden boş bırakılır olarak değerlendirilir ?

Yanıtlar:


19

[Ranking]Alan nedeniyle hesaplanmış bir sütun olmak üzere "Nullable" olarak göstermektedir. Evet, olarak bildirilir NOT NULL, ancak Hesaplanan Sütunlar için MSDN sayfası belirtildiği gibi, veritabanı altyapısı bu saptamayı sorgu zamanında değiştirebilir:

Veritabanı Altyapısı, kullanılan ifadelere göre hesaplanan sütunların nullabilitesini otomatik olarak belirler. İfadelerin çoğu, yalnızca boş değerli olmayan sütunlar olsa bile null değeri olarak kabul edilir, çünkü olası alt akışlar veya taşmalar da boş sonuçlar üretecektir. Tablodaki herhangi bir hesaplanmış sütunun nullabilitesini araştırmak için AllowsNull özelliğiyle COLUMNPROPERTY işlevini kullanın . Null olabilecek bir ifade ISNULL ( check_expression , constant ) belirtilerek null edilemeyen bir ifadeye dönüştürülebilir ; burada sabit , herhangi bir null sonuç için ikame edilmiş null olmayan bir değerdir.

Öyleyse, bunun doğru olup olmadığını görelim:

CREATE TABLE [dbo].[Realty](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [RankingBonus] [int] NOT NULL,
    [Ranking]  AS ([Id]+[RankingBonus]) PERSISTED NOT NULL
);
GO

EXEC sp_help 'dbo.Realty';
-- Ranking: Nullable = "no"

SELECT COLUMNPROPERTY(OBJECT_ID(N'dbo.Realty'), N'Ranking', 'AllowsNull') AS [AllowsNull?];
-- 0

SELECT * FROM sys.dm_exec_describe_first_result_set(N'SELECT * FROM dbo.Realty', '', NULL);
-- Ranking: is_nullable = 1  ==  :-(

Şimdi ISNULLeserlerle ilgili tavsiyelerinin olup olmadığını görelim :

SELECT * FROM sys.dm_exec_describe_first_result_set(
   N'SELECT Id, RankingBonus, ISNULL(Ranking, -99) AS [RealRanking] FROM dbo.Realty;',
   '',
   NULL);
-- RealRanking: is_nullable = 0

Tavsiyeleri doğru görünüyor, bu yüzden bunu hesaplanan sütunun tanımına uygulamayı deneyelim:

ALTER TABLE dbo.Realty
  ADD [RankingFixed] AS (ISNULL(([Id]+[RankingBonus]), -99))
  PERSISTED NOT NULL;
GO

Ve şimdi özellikleri tekrar kontrol ediyoruz, ancak yeni alan için:

EXEC sp_help 'dbo.Realty';
-- RankingFixed: Nullable = "no"

SELECT COLUMNPROPERTY(OBJECT_ID(N'dbo.Realty'),
                      N'RankingFixed',
                      'AllowsNull') AS [AllowsNullsNow?];
-- 0

Bu şimdiye kadar olumlu görünüyor, ancak orijinal tanım bile bu iki kontrolden "NULL DEĞİL" bildirdi. Öyleyse gerçek testi deneyelim - veritabanı motoru çalışma zamanında nulllanmayı nasıl belirler:

SELECT * FROM sys.dm_exec_describe_first_result_set(N'SELECT * FROM dbo.Realty', '', NULL);
-- RankingFixed: is_nullable = 0  ==  :-) WOO HOO!

13

Bu teminat için Sıralaması hesaplanan sütun ifadesi hiçbir koşulda NULL dönmez, sen sarın gerekir ISNULLuygun varsayılan değerle. Örneğin:

Ranking AS ISNULL(Id + RankingBonus, 0) PERSISTED NOT NULL

NOT NULLKısıt tablo modifiye edildiğinde kalıcı değerinin geçerli fiili ve oturum düzeyi ayarlarına bağlamında, boş değil garanti eder.

Ancak, bir sorgu bu ifadeye başvurduğunda, SQL Server kalıcı değeri kullanma (ayarlar eşleşiyorsa) veya ifadeyi yeniden hesaplama arasında seçim yapabilir.

Bazı oturum ayarları, bir taşma işleminin NULL döndürmesine neden olabilir, bu nedenle SQL Server'ın bu olasılığı hesaba katması gerekir. Görünüm üzerinden erişildiğinde, SQL Server sütunu doğru bir NULL döndürme olarak doğru işaretler.

ISNULLİfadenin en dışını kullanmak, istediğiniz şeyi elde etmenin tek desteklenen yoludur. COALESCEÖrneğin kullanmak işe yaramaz.

Demo:

CREATE TABLE dbo.T1
(
    c1 integer NOT NULL,
    c2 integer NOT NULL,
    c3 AS c1 + c2 PERSISTED NOT NULL
);
GO
CREATE VIEW dbo.V1
AS
SELECT T.c1,
       T.c2,
       T.c3
FROM dbo.T1 AS T;
GO
SELECT AllowsNull = COLUMNPROPERTY(OBJECT_ID(N'dbo.V1', N'V'), N'c3', 'AllowsNull');
GO
ALTER TABLE dbo.T1
DROP COLUMN c3;
GO
ALTER TABLE dbo.T1
ADD c3 AS ISNULL(c1 + c2, 0) PERSISTED NOT NULL;
GO
EXECUTE sys.sp_refreshsqlmodule
    @name = N'dbo.V1';
GO
SELECT AllowsNull = COLUMNPROPERTY(OBJECT_ID(N'dbo.V1', N'V'), N'c3', 'AllowsNull');
GO
DROP VIEW dbo.V1;
DROP TABLE dbo.T1;
GO

Kullanımınıza dikkat edin, sys.sp_refreshsqlmoduleçünkü görüşünüz şematik değildir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.