Postgresql

為公司和股東設計數據庫結構

  • November 22, 2021

我正在做一個個人項目,我想創建一個數據庫來保存每個上市公司的每個所有者的資訊。比如說“Sears INC”,程序將獲取“Sears INC”中每個所有者的資訊。這就是想法。但是我很難嘗試建構這個數據庫。我對此主題的經驗和知識有限,因此將不勝感激任何指導。

現在我首先考慮製作一張名為公司的表格,並為他們提供所有唯一的 ID,並為每個公司製作一張表格。然後在這些表中將是所有具有其唯一 ID 的所有者。這將連結到他們的資訊。我試圖在這裡形象化:

這裡

現在我知道為每家公司創建一張表會很乏味,但我想不出任何其他方式來做到這一點。眾所周知,每家公司可能有相同的所有者,因此使用 Owner_ID 來辨識每個所有者是有意義的。

我在 CVS 文件中擁有所有其他數據,在建構數據庫後,我可以輕鬆地將其導入 PostgreSQL。

任何幫助將不勝感激。

TL:博士;創建一個可以按公司名稱搜尋的股票所有者數據庫,並且需要幫助來建構數據庫以獲得最大效力。

一個人只能有一部電話和一個地址。公司也是如此,因為我製作了一個腳本,可以根據這些資訊找到手機。我區分實體是公司還是個人的方法是使用名為 F_Org 的列,對於公司而言,該列將大於 4 位數字。這一切都由腳本處理。

我在數據庫設計答案中經常涉及的一個主題是,在 (a) 考慮關係數據庫的技術方面——例如,表、列等的聲明——之前,強烈建議首先 (b)精確定義感興趣的業務環境的所有特徵。這意味著辨識實體類型、它們的屬性以及它們之間存在的每個重要關聯。

關於所述元素的一組定義通常稱為業務規則,它們構成了適用的概念模型。

此外,我認為關於 (1) 數據管理和 (2) 關係設計和操作 (3) 可能有助於澄清您在問題中提出的某些方面以及通過評論提出的其他重要主題。隨著答案的進行,我將整合所有這些要點。

概念層面

讓我們開始重新評估相關的抽象概念級別。在這方面,重要的是製定一系列描述業務環境的陳述。因此,在您的具體情況下,盡量保持業務規則盡可能簡單:

  • 公司主要由其ID標識
  • 公司由其名稱交替辨識
  • 公司成立於其成立日期
  • 一個主要由他或她的ID來辨識
  • 一個由他或她的FirstNameLastNameGenderCodeBirthDateBirthPlace的組合交替辨識
  • 一個只保留一個地址
  • 一個只使用一個電話號碼
  • 公司由一對多的人擁有
  • 一個擁有零個或多個公司

說明性 IDEF1X 模型

然後根據上面製定的業務規則,可以故意創建一個相對簡單的 IDEF1X模型,如圖 1所示,以便擁有一個圖形設備,將大部分重要功能整合到單個資源中:

圖 1 - 公司和股東簡化的 IDEF1X 模型

資訊建模集成定義( IDEF1X ) 是一種高度推薦的數據建模技術,於1993 年 12 月由美國國家標準與技術研究院(NIST)確立為*標準。*它牢固地基於 (a) 關係模型的創始人,即EF Codd 博士所撰寫的一些早期理論著作;(b)由PP Chen 博士開發的實體關係視圖;以及 (c) Robert G. Brown 創建的邏輯數據庫設計技術。

正如所展示的,在 IDEF1X 模型中,我們可以開始包括技術考慮,例如必須在邏輯級別通過主鍵、備用鍵和外鍵定義(為簡潔起見:分別為 PK、AK 和 FK)約束的屬性或屬性的指示。

Company前面討論的最後兩個業務規則表明實體類型和之間存在多對多 (M:N) 關聯或關係Person,這揭示了我稱之為關聯實體類型的存在CompanyOwner(這可能很好被命名CompanyShareHolder或更適合業務領域中使用的術語的東西)。

在目前的建模練習中,一個特別重要的屬性是我命名的屬性StockShareQuantity(描繪了Shares的總和),因為它完全出現在CompanyOwner關聯的上下文中;這樣,它既不屬於 aPerson也不屬於 a Company,而是屬於這兩種獨立實體類型之間可能出現的聯繫。

如指定的那樣,每個CompanyOwner事件或實例由其CompanyIdOwnerId值的組合標識,因此這些屬性在實體類型描述中突出顯示為複合 PK。該CompanyOwner.CompanyId屬性用指向 的 FK 來區分Company.CompanyId,而CompanyOwner.OwnerId用引用 的 FK 來註明Person.PersonId

為了描繪一個更精細的Person實體類型,我分解Person.NameFirstName和,LastName並包括了 和列。所有這些屬性的組合值通常用於在某些業務場景中辨識 a,但您可能只是對跟踪 感興趣,如果這符合您的數據使用要求,因此您不必遵循關於正在討論的特定數據庫的相同方法。GenderCode``BirthDate``BirthPlace``Person``Person.FullName

說明性邏輯 SQL-DDL 結構

隨後,通過數據庫管理系統提供的數據定義語言(在本例中為 PostgreSQL)來聲明邏輯結構相對更容易,如下例所示:

-- You have to determine which are the most fitting 
-- data types and sizes for all the table columns 
-- depending on the business context characteristics.

-- Also, you should make accurate tests to define the
-- most convenient physical implementation settings; e.g.,
-- a good INDEXing strategy based on query tendencies.

-- As one would expect, you are free to make use of 
-- your preferred (or required) naming conventions.

CREATE TABLE Company ( -- Stands for an independent entity type
   CompanyId       INT       NOT NULL, -- You may like to set it with the SERIAL type to retain system-assigned and system-generated surrogate values.
   Name            TEXT      NOT NULL,
   FoundingDate    DATE      NOT NULL,
   Etcetera        TEXT      NOT NULL,
   CreatedDateTime TIMESTAMP NOT NULL DEFAULT NOW(), -- You may also configure it so that the DEFAULT value is set by the CURRENT_TIMESTAMP function, if appropriate. 
   --
   CONSTRAINT Company_PK PRIMARY KEY (CompanyId),
   CONSTRAINT Company_AK UNIQUE      (Name) -- Single-colum ALTERNATE KEY.
);

CREATE TABLE Person ( -- Denotes an independent entity type.
   PersonId        INT       NOT NULL, -- You may like to set it with the SERIAL type to retain system-assigned and system-generated surrogate values.
   FirstName       TEXT      NOT NULL,
   LastName        TEXT      NOT NULL,
   GenderCode      TEXT      NOT NULL,
   BirthDate       DATE      NOT NULL,
   BirthPlace      TEXT      NOT NULL,  
   Address         TEXT      NOT NULL,   
   PhoneNumber     TEXT      NOT NULL,     
   CreatedDateTime TIMESTAMP NOT NULL DEFAULT NOW(), -- You may also configure it so that the DEFAULT value is set by the CURRENT_TIMESTAMP function, if appropriate.
   --
   CONSTRAINT Person_PK PRIMARY KEY (PersonId),
   CONSTRAINT Person_AK UNIQUE      ( -- Composite ALTERNATE KEY.
       FirstName,
       LastName,
       GenderCode,
       BirthDate,
       BirthPlace
   )
);

CREATE TABLE CompanyOwner ( -- Represents an associative entity type or M:N association. Attaching an extra column to hold system-generated and system-assigned surrogate values to this table is superfluous.
   CompanyId          INT       NOT NULL,
   OwnerId            INT       NOT NULL,
   StockShareQuantity INT       NOT NULL,
   Etcetera           TEXT      NOT NULL,  
   CreatedDateTime    TIMESTAMP NOT NULL DEFAULT NOW(), -- You may also configure it so that the DEFAULT value is set by the CURRENT_TIMESTAMP function, if appropriate. 
   --
   CONSTRAINT CompanyOwner_PK          PRIMARY KEY (CompanyId, OwnerId), -- Composite PRIMARY KEY.
   CONSTRAINT CompanyOwnerToCompany_FK FOREIGN KEY (CompanyId)
       REFERENCES Company (CompanyId),
   CONSTRAINT CompanyOwnerToPerson_FK  FOREIGN KEY (OwnerId)
       REFERENCES Person (PersonId),
   CONSTRAINT StockShareQtyIsValid_CK  CHECK       (StockShareQuantity >= 0) -- Appears to be required.
);

如前所述,在這個故意且相對簡單的邏輯結構b中(與您的圖表中描繪的非常相似,儘管有一些重要的區別):

  • 每個基表表示一個單獨的實體類型,從而防止歧義;
  • 代表相應實體類型的單個屬性;
  • 為每一固定了一個特定的數據類型,以確保它保留的所有都屬於一個特定的集合(您必須適應以適應您的確切需求,從PostgreSQL提供的選項中選擇最合適的類型) ,無論是 INT、TIMESTAMP、TEXT 等;和
  • (以聲明方式)設置多個約束c、d ,以保證所有表中保留的符合概念模型中確定的規則。

b我上傳了一個db<>fiddle和一個SQL Fiddle,在 PostgreSQL 9.6 上執行,其中包含我定義的 DDL 結構和約束以及範例數據,以便您可以“實際”測試它。

c由於 (i) 數據的結構(即表、列和類型)和 (ii) 施加在此類結構上以確保其僅接受有效數據的約束(例如,PK、FK 和 CHECK)是 (iii ) 關係數據庫配置的兩個不同但相關的因素,我建議 (iv) 將結構聲明與約束聲明分開——儘管 PostgreSQL 提供的 SQL 語言和方言允許聲明“內聯”列約束,如果您希望選擇該選項—。實際上,將約束定義移到 CREATE TABLE … (…) 之外會更好。陳述,因此這一點值得徹底評估。

d關於結構與約束分離的一個例外是,我實際上在“內聯”列聲明中修復了 NOT NULL,因為它是一種特殊類型的約束。為了使事情盡可能簡短,允許 NULL 標記是一種方法——在理論上存在爭議——由 SQL 語言設計者引入,以嘗試管理缺少資訊的問題,這是一個相當廣泛的主題。反過來,NULL 標記意味著處理另一個稱為三值邏輯的問題。根據關係理論,包含一個或多個包含 NULL 標記 (1) 的列的表不會表示一種數學關係——所述標記是關於缺少值的指示符,因此它們不是域值——因此(2)這樣的表在操作時不會“表現”為關係。因此,雖然有可能讓列保持 NULL 標記,但我建議您研究有關這些主題的可靠材料,以便您可以在了解有關缺失數據管理的所有含義和方法時做出明智的決定。

Person.Address 列

如果您對操作Address列的某些編碼部分感興趣,讓我們說PostCode,您可能希望評估將其分解為幾列並將相關資訊移動到單獨的表中,該Person表可能會通過具有 FK 約束的列。

為每個公司聲明一個表?

您在評論中提出了以下想法:

正如我所說,設計將會改變,因為

$$ … $$會有多家公司,人們可以擁有多家公司,因此會出現兩次。我最初的問題是如何設計這個。我想過為每家公司製作一張桌子,我認為這將是我最後的手段,但我仍然沒有其他關於如何做到這一點的指導或提示。

,您不應該每個Company都創建一個表,因為那樣會非常不理想。

在這方面,可以說保留在每個先前呈現的基表中的每一行都是關於屬於某個類型的某個概念級別實體的斷言,即,**公司人員CompanyOwner

因此,關於給定公司的一行在表中只保存一次Company,而關於給定人員的一行在表中只保存一次Person。然後,由於Person可以擁有零個、一個或多個Companies ,因此有關**Person與單個Company的確切聯繫的每一行在表中僅包含一次。CompanyOwner

表中的一行CompanyOwner不包含有關Person的全部資訊,它僅包含 (1)OwnerId列中的一個值 — 約束為 FK — 引用 (2)Person.PersonId列中保留的一個值 — 約束為PK——。某個CompanyOwner.OwnerId值可能會重複多次,因此也可能與某個CompanyOwner.CompanyId值一起發生,但這沒有問題。如範例所示,通過複合 PK 定義(CompanyId, OwnerId)防止重複相同的值組合的可能性。CompanyOwner

派生資訊

當涉及到關係數據庫時,一組基表絕對不是一個固定的結構,因為除了易於擴展和調整之外,基表還有助於派生在設計時未配置的新表。

讓我們假設您已通過以下 INSERT 操作使用範例數據填充數據庫表:

INSERT INTO Company 
   (CompanyId, Name, FoundingDate, Etcetera)
VALUES
   (1748, 'Database Modeling Inc.', '1985-06-30', 'Foo'),
   (1750, 'Application Programming Co.', '1987-10-14', 'Bar');

INSERT INTO Person 
   (PersonId, FirstName, LastName, BirthDate, BirthPlace, GenderCode, Address, PhoneNumber)
VALUES
   (1, 'Edgar', 'Codd', '1923-08-19', 'Fortuneswell, UK', 'M', 'IBM Research Laboratory K01/282, 5600 Cottle Road, San Jose, CA, USA', '01-800-17-50-17-50'),
   (2, 'Alan', 'Turing', '1912-06-23', 'Maida Vale, UK','M', 'National Physical Laboratory, Hampton Road, Teddington, TW11 0LW, England', '01-800-17-48-17-48'),
   (3, 'Grace', 'Hopper', '1906-12-09', 'New York City, USA', 'F', 'Navy’s Office of Information Systems Planning, USA.', '01-800-17-50-17-50'),   
   (4, 'Diego', 'Velázquez', '1599-06-06', 'Seville, Spain', 'M', 'Palacio Real, Madrid, Spain', '01-800-17-50-17-50'),
   (5, 'Michelangelo', 'Buonarroti', '1475-03-06', 'Caprese, Italy', 'M', 'Sistine Chapel, Vatican City State', '01-800-17-50-17-50'); 

INSERT INTO CompanyOwner 
   (CompanyId, OwnerId, StockShareQuantity, Etcetera)
VALUES
   (1748, 1, 2500, 'U'),
   (1750, 1, 2500, 'V'),
   (1750, 2, 8000, 'W'),
   (1750, 3, 3580, 'X'),
   (1748, 4, 12899, 'Y'),
   (1750, 5, 12899, 'Z'); 

之後,如果您想生成一個包含所有公司**Owners數據的表,您可以聲明如下所示的 VIEW:

CREATE VIEW CompanyAndOwner AS
   SELECT C.CompanyId,
          C.Name AS CompanyName,
          P.PersonId,
          P.FirstName,
          P.LastName,
          P.BirthDate,
          P.BirthPlace,
          P.GenderCode,
          P.Address,
          P.PhoneNumber,
         CO.StockShareQuantity,
          P.CreatedDateTime
       FROM Person P
       JOIN CompanyOwner CO
         ON CO.OwnerId = P.PersonId
       JOIN Company C
         ON C.CompanyId = CO.CompanyId;

然後你可以表達連續的操作c直接從那個 VIEW 中選擇;例如:

SELECT *            
 FROM CompanyAndOwner 
WHERE CompanyId = 1750;

SELECT CompanyName,
      FirstName AS OwnerFirstName,
      LastName  AS OwnerLastName,
      StockShareQuantity
 FROM CompanyAndOwner 
WHERE CompanyId = 1750; 

SELECT * 
 FROM CompanyAndOwner 
WHERE CompanyId = 1748;

SELECT CompanyName,
      FirstName AS OwnerFirstName,
      LastName  AS OwnerLastName,
      StockShareQuantity
 FROM CompanyAndOwner 
WHERE CompanyId = 1748;

或者您也可以直接從基表中選擇:

SELECT COUNT(OwnerId) AS OwnedCompaniesQuantity
  FROM CompanyOwner
 WHERE OwnerId = 1;

等等。

e這裡包含的所有數據操作操作都包含在之前連結到的db<>fiddleSQL Fiddle中,因此您可以分析它們產生的結果集。

公司地址和電話號碼

在我們通過評論進行的一系列審議中,我問您是否有興趣保留屬於Companies的**地址電話號碼,您的回答如下:

一個人只能有一部電話和一個地址。公司也是如此,因為我製作了一個腳本,可以根據這些資訊找到手機。我區分實體是公司還是個人的方法是使用名為 F_Org 的列,對於公司而言,該列將大於 4 位數字。這一切都由腳本處理。

我不確定這是否意味著公司地址電話號碼儲存在應用程序組件中(可能是帶有記錄和欄位的文件,或類似的東西)但是,如果您實際上正在處理這些資訊,您應該使用正確的工具來完成這項工作,即將這些方麵包括在數據庫結構中,並利用數據庫管理系統(即 PostgreSQL)提供的工具,以便您可以管理相關數據一種最佳方式(例如,憑藉基於關係代數和聲明性約束的邏輯級操作,在物理級由強大的集合處理引擎支持)。

表示超類型-子類型關係的可行 DDL 結構擴展

因此,如果您確定,在您的業務領域

  • 同一地址出現可以由多個個人和/或公司實例保存,

  • 多個Person和/或Company實例可以使用相同的PhoneNumber ,

您可能想分析我在此答案中包含的圖表,以解決與所考慮的場景非常相似的問題(除其他特徵外,Party超類型代表組織人員子類型,扮演角色組織的所有者,以及通過超類型與組織人員連結的**地址和電話號碼),因為它們可以用作暫定擴展的參考。

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