Sql-Server

SQL Server 中的抽像類。他們甚至可能嗎?

  • September 9, 2016

我有一個非常具體的問題,我很驚訝還沒有人問過。它涉及一個具體的類模型和 SQL Server 2016 DDL。要點是:在我的模型中,某些類繼承自基類,比如說"BaseInfo".

這個類是抽象的。在 SQL 術語中,這意味著我不(或者我是否?)想要創建一個帶有行的單獨表(例如。。CREATE TABLE "BaseInfo"....但是我確實希望我的一些表(實際上很多)具有相同的列(加上一些他們自己的)。在 OOP 術語中,我希望我的一些類繼承自該表定義。有沒有辦法在 DDL 中定義它,還是我必須手動實現它?

筆記:

  1. 我已經閱讀了關於 TPH、TPT、TPC 的所有文章。它們太簡單了,它們都具有相同的“人-學生-教育者”模型,與我的情況不符。我可能想做的是 TPC,但我希望對BaseInfo錶所做的更改自動應用於所有子類。
  2. 我不會查詢BaseInfo。我寧願做一個涉及一些(或全部)孩子的(罕見的)複雜查詢。
  3. BaseInfoDDL ( ALTER TABLE BaseInfo...) 所做的更改必須反映給孩子(最好是自動)。
  4. PostgreSQL 的 INHERITS 語句在這里大放異彩。SQL Server 中是否有任何等價物(我已經進行了研究,但一無所獲)?
  5. 如果我沒有得到答案或有其他突破,我將採用手動方法。BaseInfo使用DDL保存程式碼片段並將其添加到CREATE TABLE每個子表的語句中。
  6. 答案必須尊重概念模型定義!

雖然 PostgreSQL 確實支持這個請求是正確的,但 SQL Server 沒有類似的能力。這使您可以將所有“公共”列放在每個表中,或者擁有一個“基”表,其中包含將在必要時連接到的公共列(很可能 100% 的時間都不需要) .

我建議不要將這些“常見”列複製到所有(大多數)表中,如下所示:

  1. 如果我沒有得到答案或有其他突破,我將採用手動方法。BaseInfo使用DDL保存程式碼片段並將其添加到CREATE TABLE每個子表的語句中。

因為:

  1. 長期維護更困難/更容易出錯,因為架構失去同步的可能性更大。將語句模板化CREATE TABLE是一回事,但需要協調修改。實際上,這裡的要求之一是:

3. 對BaseInfoDDL ( ALTER TABLE BaseInfo...) 所做的更改必須反映給孩子(最好是自動)。

  1. 分離數據時性能通常會更好。請記住,數據庫與應用程式碼有著根本不同的目標——物理儲存和基於集合的操作。雖然它可能看起來違反直覺和/或“笨拙”和/或反對“架構”最佳實踐,但根據特定 RDBMS 的優勢建構數據模型將產生最佳結果。連接可能看起來是“額外的”工作(有時確實如此),但 RDBMS 專門針對以這種方式工作進行了優化(較小的表通常對於查詢索引維護來說更快——這是不應該被忽視的!)。
  2. 您可以通過將每個 Class + SubClass 關係抽象為 Views 來解決 JOIN 的大部分“混亂”。這些絕對可以在所有SELECT情況下提供幫助,甚至在大多數UPDATE情況下通過可更新視圖(在CREATE VIEW的 MSDN 頁面中詳細描述。INSERTDELETE語句也不能正常工作,但是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 (使用者定義的函式重載?)上提出了請求,並且在使用它後,最終的痛苦多於收穫。

引用自:https://dba.stackexchange.com/questions/149185