Sql-Server
SQL Server 中的抽像類。他們甚至可能嗎?
我有一個非常具體的問題,我很驚訝還沒有人問過。它涉及一個具體的類模型和 SQL Server 2016 DDL。要點是:在我的模型中,某些類繼承自基類,比如說
"BaseInfo"
.這個類是抽象的。在 SQL 術語中,這意味著我不(或者我是否?)想要創建一個帶有行的單獨表(例如。。
CREATE TABLE "BaseInfo"....
但是我確實希望我的一些表(實際上很多)具有相同的列(加上一些他們自己的)。在 OOP 術語中,我希望我的一些類繼承自該表定義。有沒有辦法在 DDL 中定義它,還是我必須手動實現它?筆記:
- 我已經閱讀了關於 TPH、TPT、TPC 的所有文章。它們太簡單了,它們都具有相同的“人-學生-教育者”模型,與我的情況不符。我可能想做的是 TPC,但我希望對
BaseInfo
錶所做的更改自動應用於所有子類。- 我不會查詢
BaseInfo
。我寧願做一個涉及一些(或全部)孩子的(罕見的)複雜查詢。- 對
BaseInfo
DDL (ALTER TABLE BaseInfo...
) 所做的更改必須反映給孩子(最好是自動)。- PostgreSQL 的 INHERITS 語句在這里大放異彩。SQL Server 中是否有任何等價物(我已經進行了研究,但一無所獲)?
- 如果我沒有得到答案或有其他突破,我將採用手動方法。
BaseInfo
使用DDL保存程式碼片段並將其添加到CREATE TABLE
每個子表的語句中。- 答案必須尊重概念模型定義!
雖然 PostgreSQL 確實支持這個請求是正確的,但 SQL Server 沒有類似的能力。這使您可以將所有“公共”列放在每個表中,或者擁有一個“基”表,其中包含將在必要時連接到的公共列(很可能 100% 的時間都不需要) .
我建議不要將這些“常見”列複製到所有(大多數)表中,如下所示:
- 如果我沒有得到答案或有其他突破,我將採用手動方法。
BaseInfo
使用DDL保存程式碼片段並將其添加到CREATE TABLE
每個子表的語句中。因為:
- 長期維護更困難/更容易出錯,因為架構失去同步的可能性更大。將語句模板化
CREATE TABLE
是一回事,但需要協調修改。實際上,這裡的要求之一是:3. 對
BaseInfo
DDL (ALTER TABLE BaseInfo...
) 所做的更改必須反映給孩子(最好是自動)。
- 分離數據時性能通常會更好。請記住,數據庫與應用程式碼有著根本不同的目標——物理儲存和基於集合的操作。雖然它可能看起來違反直覺和/或“笨拙”和/或反對“架構”最佳實踐,但根據特定 RDBMS 的優勢建構數據模型將產生最佳結果。連接可能看起來是“額外的”工作(有時確實如此),但 RDBMS 專門針對以這種方式工作進行了優化(較小的表通常對於查詢和索引維護來說更快——這是不應該被忽視的!)。
- 您可以通過將每個 Class + SubClass 關係抽象為 Views 來解決 JOIN 的大部分“混亂”。這些絕對可以在所有
SELECT
情況下提供幫助,甚至在大多數UPDATE
情況下通過可更新視圖(在CREATE VIEW的 MSDN 頁面中詳細描述。INSERT
和DELETE
語句也不能正常工作,但是INSERT
通過OUTPUT
子句組合兩個表仍然可以更容易到表中,當在外鍵上指定屬性時,INSERT
語句可以處理這兩個表。下面是一個例子來展示大部分內容:BaseInfo``DELETE``ON DELETE CASCADE
/* DROP VIEW dbo.UpdatableView; DROP TABLE dbo.UpdatableViewTableB; DROP TABLE dbo.UpdatableViewTableA; */ CREATE TABLE dbo.UpdatableViewTableA ( ID INT NOT NULL IDENTITY(1, 1) CONSTRAINT [PK_UpdatableViewTableA] PRIMARY KEY, IsActive BIT NOT NULL, InsertTime DATETIME2 NOT NULL CONSTRAINT [DF_UpdatableViewTableA_InsertTime] DEFAULT (SYSDATETIME()) ); CREATE TABLE dbo.UpdatableViewTableB ( ID INT NOT NULL CONSTRAINT [PK_UpdatableViewTableB] PRIMARY KEY, Whateva NVARCHAR(4000) NULL, CONSTRAINT [FK_UpdatableViewTableB_UpdatableViewTableA_ID] FOREIGN KEY ([ID]) REFERENCES dbo.UpdatableViewTableA ([ID]) ON DELETE CASCADE ); GO CREATE VIEW dbo.UpdatableView AS SELECT a.[ID], a.[IsActive], a.[InsertTime], b.[Whateva] FROM dbo.UpdatableViewTableA a INNER JOIN dbo.UpdatableViewTableB b ON b.[ID] = a.[ID]; GO INSERT INTO dbo.UpdatableViewTableA ([IsActive]) VALUES (1); INSERT INTO dbo.UpdatableViewTableB ([ID], [Whateva]) VALUES (1, N'test row'); INSERT INTO dbo.UpdatableViewTableA ([IsActive]) VALUES (1); INSERT INTO dbo.UpdatableViewTableB ([ID], [Whateva]) VALUES (2, N'another row'); SELECT * FROM dbo.UpdatableView; UPDATE uv SET uv.IsActive = 0 FROM dbo.UpdatableView uv WHERE uv.[ID] = 2; SELECT * FROM dbo.UpdatableView; UPDATE uv SET uv.[Whateva] = N'what?' FROM dbo.UpdatableView uv WHERE uv.[ID] = 1; SELECT * FROM dbo.UpdatableView; DELETE uv FROM dbo.UpdatableView uv WHERE uv.[ID] = 1; -- Msg 4405, Level 16, State 1, Line 59 -- View or function 'uv' is not updatable because the modification -- affects multiple base tables.
我在以下 DBA.SE 答案中更詳細地描述了實現此類數據模型的變體:
PS 對於它的價值(這可能並不多;-),我不確定此功能有多少實際好處,因為大多數時候,“基”類中的屬性確實具有單獨查詢的價值,即使僅在報告中。這類似於 PostgreSQL 重載函式的能力,最近在 Microsoft Connect (使用者定義的函式重載?)上提出了請求,並且在使用它後,最終的痛苦多於收穫。