เหตุใดคอลัมน์ที่คำนวณเป็นค่า NULL จึงไม่สามารถเรียกดูได้ในมุมมอง


15

ฉันมีโต๊ะ:

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

และมุมมอง:

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

ฉันมีรูปแบบ dbml ใน C # (LinqToSQL) ด้วยมุมมองFilteredRealty [Ranking]ฟิลด์รับการยอมรับเป็น int nullable และดังนั้นผมจึงมีการแก้ไขประเภทในรหัสที่สร้างขึ้นทุกครั้งเมื่อฉันเปลี่ยนอะไรในฐานข้อมูล มันน่าผิดหวังมากสำหรับฉันและการทำงานด้วยตนเองมากมาย

ไม่มีการรวมที่ใช้ในFilteredRealty (เกี่ยวกับคำถามที่เกี่ยวข้องนี้ )

ทำไมคอลัมน์อันดับของมุมมองถูกพิจารณาว่าเป็นโมฆะถ้าหลักทรัพย์การจัดอันดับไม่เป็นโมฆะ ?

คำตอบ:


19

[Ranking]ฟิลด์จะแสดงเป็น "Nullable" เนื่องจากเป็นคอลัมน์คำนวณ ใช่มันถูกประกาศเป็นNOT NULLแต่เมื่อเพจ MSDN สำหรับคอลัมน์ที่คำนวณแล้วเอ็นจิ้นฐานข้อมูลสามารถเปลี่ยนการกำหนดนั้นในเวลาสืบค้นได้:

โปรแกรมฐานข้อมูลกำหนดความสามารถของคอลัมน์ที่คำนวณได้โดยอัตโนมัติตามนิพจน์ที่ใช้ ผลลัพธ์ของนิพจน์ส่วนใหญ่ถือว่าเป็นโมฆะแม้ว่าจะมีคอลัมน์ที่ไม่สามารถลบได้เท่านั้นเนื่องจากอันเดอร์โฟลว์หรือโอเวอร์โฟลว์ที่เป็นไปได้จะทำให้เกิดผลลัพธ์ที่เป็นโมฆะเช่นกัน ใช้ฟังก์ชัน COLUMNPROPERTY กับคุณสมบัติAllowNullเพื่อตรวจสอบความสามารถในการคำนวณคอลัมน์ใด ๆ ในตาราง การแสดงออกที่เป็นโมฆะสามารถกลายเป็นหนึ่งที่ไม่เป็นโมฆะโดยการระบุ ISNULL ( check_expression , ค่าคงที่ ) โดยที่ค่าคงที่เป็นค่าที่ไม่เป็นโมฆะแทนผลโมฆะใด ๆ

ดังนั้นเรามาดูกันว่านี่เป็นเรื่องจริงหรือไม่:

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

ตอนนี้เรามาดูกันว่าคำแนะนำของพวกเขาเกี่ยวกับISNULLงาน:

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

คำแนะนำของพวกเขาดูเหมือนถูกต้องดังนั้นให้ลองใช้สิ่งนั้นกับคำจำกัดความของคอลัมน์ที่คำนวณ:

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

และตอนนี้เราตรวจสอบคุณสมบัติอีกครั้ง แต่สำหรับฟิลด์ใหม่:

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

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

สิ่งนี้ดูเป็นแง่บวก แต่แม้นิยามดั้งเดิมจะรายงานว่า "ไม่เป็นโมฆะ" จากการตรวจสอบทั้งสองนี้ ดังนั้นลองทดสอบจริง - วิธีที่เอ็นจิ้นฐานข้อมูลกำหนดความสามารถในการรันไทม์:

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

13

ในการรับประกันว่านิพจน์คอลัมน์ที่คำนวณอันดับจะไม่ส่งคืนค่า NULL ไม่ว่าในกรณีใด ๆ คุณต้องล้อมISNULLด้วยค่าเริ่มต้นที่เหมาะสม ตัวอย่างเช่น:

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

NOT NULLจำกัด เพื่อให้แน่ใจมูลค่างานอยู่ไม่ได้เป็นโมฆะในบริบทของการตั้งค่า table- และเซสชั่นในระดับผลกระทบเมื่อตารางมีการแก้ไข

อย่างไรก็ตามเมื่อเคียวรีอ้างถึงนิพจน์นั้น SQL Server มีตัวเลือกระหว่างการใช้ค่าคงที่ (หากการตั้งค่าตรงกัน) หรือคำนวณนิพจน์อีกครั้ง

การตั้งค่าบางอย่างในเซสชันอาจทำให้เกิดโอเวอร์โฟลว์เพื่อส่งคืนค่า NULL ตัวอย่างเช่นดังนั้น SQL Server ต้องคำนึงถึงความเป็นไปได้นี้ เมื่อเข้าถึงผ่านมุมมอง SQL Server จะทำเครื่องหมายคอลัมน์อย่างถูกต้องว่าอาจส่งคืน NULL

การใช้นอกสุดISNULLในการแสดงออกเป็นวิธีเดียวที่ได้รับการสนับสนุนเพื่อให้บรรลุสิ่งที่คุณต้องการ COALESCEตัวอย่างเช่นการใช้จะไม่ทำงาน

การสาธิต:

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

สังเกตการใช้งานsys.sp_refreshsqlmoduleเนื่องจากมุมมองของคุณไม่ได้เป็นแบบแผน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.