Tại sao một cột được tính toán KHÔNG NULL được coi là không thể xem được?


15

Tôi có một cái bàn:

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

Và một quan điểm:

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

Tôi có một mô hình dbml trong C # (LinqToQuery) với khung nhìn FilteredRealty trong đó. Trường [Xếp hạng] được công nhận là int nullable và vì vậy tôi phải sửa loại trong mã được tạo mỗi khi tôi thay đổi bất cứ điều gì trong cơ sở dữ liệu. Điều này rất khó chịu đối với tôi và rất nhiều công việc thủ công.

Không có tổng hợp được sử dụng trong FilteredRealty (liên quan đến câu hỏi liên quan này ).

Tại sao cột Xếp hạng của chế độ xem được coi là không thể thực hiện được nếu Realty.Ranking không thể rỗng?

Câu trả lời:


18

Các [Ranking]lĩnh vực được hiển thị là "Nullable" do để trở thành một cột tính. Có, nó được khai báo là NOT NULL, nhưng là trang MSDN cho các trạng thái Cột được tính toán , công cụ cơ sở dữ liệu có thể thay đổi quyết định đó tại thời điểm truy vấn:

Công cụ cơ sở dữ liệu tự động xác định tính vô hiệu của các cột được tính toán dựa trên các biểu thức được sử dụng. Kết quả của hầu hết các biểu thức được coi là nullable ngay cả khi chỉ có các cột không thể hiển thị, bởi vì các dòng có thể tràn hoặc tràn cũng sẽ tạo ra kết quả null. Sử dụng hàm COLUMNPROPERTY với thuộc tính allowNull để điều tra tính vô hiệu của bất kỳ cột được tính toán nào trong một bảng. Một biểu thức là nullable có thể được biến thành một biểu thức không thể hoàn thành bằng cách chỉ định ISNULL ( check_expression , hằng số ), trong đó hằng số là giá trị không thay thế cho bất kỳ kết quả null nào.

Vì vậy, hãy xem điều này có đúng không:

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  ==  :-(

Bây giờ hãy xem lời khuyên của họ về ISNULLcông việc:

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

Lời khuyên của họ có vẻ chính xác, vì vậy hãy thử áp dụng điều đó vào định nghĩa của cột được tính toán:

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

Và bây giờ chúng tôi kiểm tra lại các thuộc tính, nhưng đối với trường mới:

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

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

Điều này có vẻ tích cực cho đến nay, nhưng ngay cả định nghĩa ban đầu đã báo cáo "KHÔNG NULL" từ hai kiểm tra này. Vì vậy, hãy thử kiểm tra thực tế - cách công cụ cơ sở dữ liệu xác định tính vô hiệu trong thời gian chạy:

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

13

Để đảm bảo rằng biểu thức cột được tính toán Xếp hạng không trả về NULL trong mọi trường hợp, bạn phải bọc nó ISNULLvới một giá trị mặc định phù hợp. Ví dụ:

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

Các NOT NULLhạn chế để đảm bảo giá trị tiếp tục tồn tại không phải là null, trong bối cảnh các thiết lập Bảng- và cấp phiên có hiệu lực khi bảng được sửa đổi.

Tuy nhiên, khi truy vấn tham chiếu biểu thức đó, SQL Server có lựa chọn giữa việc sử dụng giá trị bền vững (nếu cài đặt khớp) hoặc tính toán biểu thức một lần nữa.

Ví dụ, một số cài đặt phiên có thể khiến tràn trả về NULL, vì vậy SQL Server phải tính đến khả năng này. Khi được truy cập qua chế độ xem, SQL Server đánh dấu chính xác cột là có khả năng trả về NULL.

Sử dụng ngoài cùng ISNULLtrên biểu thức là cách duy nhất được hỗ trợ để đạt được những gì bạn muốn. Sử dụngCOALESCE sẽ không hoạt động, ví dụ.

Bản giới thiệu:

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

Lưu ý việc sử dụng sys.sp_refreshsqlmodulevì chế độ xem của bạn không phải là sơ đồ.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.