PostgreSQL
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> PostgreSQL

Chữ "O" trong ORDBMS:Kế thừa PostgreSQL

Trong mục blog này, chúng ta sẽ đi qua kế thừa PostgreSQL, theo truyền thống là một trong những tính năng hàng đầu của PostgreSQL kể từ những bản phát hành đầu tiên. Một số cách sử dụng kế thừa điển hình trong PostgreSQL là:

  • phân vùng bảng
  • nhiều hợp đồng thuê nhà

PostgreSQL cho đến khi phiên bản 10 triển khai phân vùng bảng bằng cách sử dụng kế thừa. PostgreSQL 10 cung cấp một cách phân vùng khai báo mới. Phân vùng PostgreSQL bằng cách sử dụng kế thừa là một công nghệ khá hoàn thiện, được ghi chép và kiểm tra kỹ lưỡng, tuy nhiên tính kế thừa trong PostgreSQL từ góc độ mô hình dữ liệu (theo quan điểm của tôi) không phổ biến lắm, do đó chúng tôi sẽ tập trung vào các trường hợp sử dụng cổ điển hơn trong blog này. Chúng tôi đã thấy từ blog trước (các tùy chọn đa thuê cho PostgreSQL) rằng một trong những phương pháp để đạt được nhiều thuê là sử dụng các bảng riêng biệt và sau đó hợp nhất chúng qua một khung nhìn. Chúng tôi cũng đã thấy những mặt hạn chế của thiết kế này. Trong blog này, chúng tôi sẽ nâng cao thiết kế này bằng cách sử dụng tính năng kế thừa.

Giới thiệu về Thừa kế

Nhìn lại phương pháp đa thuê nhà được thực hiện với các bảng và khung nhìn phân tách, chúng tôi nhớ rằng nhược điểm chính của nó là không có khả năng thực hiện chèn / cập nhật / xóa. Thời điểm chúng tôi thử cập nhật về cho thuê xem chúng tôi sẽ nhận được LỖI này:

ERROR:  cannot insert into view "rental"
DETAIL:  Views containing UNION, INTERSECT, or EXCEPT are not automatically updatable.
HINT:  To enable inserting into the view, provide an INSTEAD OF INSERT trigger or an unconditional ON INSERT DO INSTEAD rule.

Vì vậy, chúng tôi sẽ cần tạo trình kích hoạt hoặc quy tắc về cho thuê xem chỉ định một chức năng để xử lý việc chèn / cập nhật / xóa. Giải pháp thay thế là sử dụng kế thừa. Hãy để chúng tôi thay đổi giản đồ của blog trước:

template1=# create database rentaldb_hier;
template1=# \c rentaldb_hier
rentaldb_hier=# create schema boats;
rentaldb_hier=# create schema cars;

Bây giờ chúng ta hãy tạo bảng mẹ chính:

rentaldb_hier=# CREATE TABLE rental (
    id integer NOT NULL,
    customerid integer NOT NULL,
    vehicleno text,
    datestart date NOT NULL,
    dateend date
); 

Theo thuật ngữ OO, bảng này tương ứng với lớp cha (theo thuật ngữ java). Bây giờ, hãy xác định các bảng con bằng cách kế thừa từ public.rental và cũng thêm một cột cho mỗi bảng cụ thể cho miền:ví dụ:số giấy phép bắt buộc của người lái xe (khách hàng) đối với ô tô và chứng chỉ lái thuyền tùy chọn.

rentaldb_hier=# create table cars.rental(driv_lic_no text NOT NULL) INHERITS (public.rental);
rentaldb_hier=# create table boats.rental(sail_cert_no text) INHERITS (public.rental);

Hai bảng ô tô.rental Thuyền.rental kế thừa tất cả các cột từ public.rental cha của chúng :

rentaldb_hier=# \d cars.rental
                           Table "cars.rental"
     Column     |         Type          | Collation | Nullable | Default
----------------+-----------------------+-----------+----------+---------
 id             | integer               |           | not null |
 customerid     | integer               |           | not null |
 vehicleno      | text                  |           |          |
 datestart      | date                  |           | not null |
 dateend        | date                  |           |          |
 driv_lic_no | text                  |           | not null |
Inherits: rental
rentaldb_hier=# \d boats.rental
                         Table "boats.rental"
    Column    |         Type          | Collation | Nullable | Default
--------------+-----------------------+-----------+----------+---------
 id           | integer               |           | not null |
 customerid   | integer               |           | not null |
 vehicleno    | text                  |           |          |
 datestart    | date                  |           | not null |
 dateend      | date                  |           |          |
 sail_cert_no | text                  |           |          |
Inherits: rental

Chúng tôi nhận thấy rằng chúng tôi đã bỏ qua công ty cột trong định nghĩa của bảng cha (và kết quả là cả trong bảng con). Điều này không còn cần thiết vì nhận dạng người thuê có trong tên đầy đủ của bảng! Chúng ta sẽ thấy sau một cách dễ dàng để tìm ra điều này trong các truy vấn. Bây giờ, hãy chèn một số hàng trong ba bảng (chúng tôi mượn khách hàng lược đồ và dữ liệu từ blog trước):

rentaldb_hier=# insert into rental (id, customerid, vehicleno, datestart) VALUES(1,1,'SOME ABSTRACT PLATE NO',current_date);
rentaldb_hier=# insert into cars.rental (id, customerid, vehicleno, datestart,driv_lic_no) VALUES(2,1,'INI 8888',current_date,'gr690131');
rentaldb_hier=# insert into boats.rental (id, customerid, vehicleno, datestart) VALUES(3,2,'INI 9999',current_date);

Bây giờ chúng ta hãy xem những gì có trong bảng:

rentaldb_hier=# select * from rental ;
 id | customerid |       vehicleno        | datestart  | dateend
----+------------+------------------------+------------+---------
  1 |          1 | SOME ABSTRACT PLATE NO | 2018-08-31 |
  2 |          1 | INI 8888               | 2018-08-31 |
  3 |          2 | INI 9999               | 2018-08-31 |
(3 rows)
rentaldb_hier=# select * from boats.rental ;
 id | customerid | vehicleno | datestart  | dateend | sail_cert_no
----+------------+-----------+------------+---------+--------------
  3 |          2 | INI 9999  | 2018-08-31 |         |
(1 row)
rentaldb_hier=# select * from cars.rental ;
 id | customerid | vehicleno | datestart  | dateend | driv_lic_no
----+------------+-----------+------------+---------+-------------
  2 |          1 | INI 8888  | 2018-08-31 |         | gr690131
(1 row)

Vì vậy, các khái niệm kế thừa tương tự tồn tại trong các ngôn ngữ Hướng đối tượng (như Java) cũng tồn tại trong PostgreSQL! Chúng ta có thể nghĩ về điều này như sau:
public.rental:superclass
Cars.rental:subclass
Thuyền.rental:subclass
row public.rental.id =1:instance of public.rental
chèo thuyền.rental.id =2:ví dụ về ô tô.rental và công cộng.rental
chèo thuyền.rental.id =3:ví dụ về thuyền.rental và public.rental

Vì các hàng thuyền.rental và ô tô.rental cũng là các trường hợp của public.rental nên điều tự nhiên là chúng xuất hiện dưới dạng các hàng public.rental. Nếu chúng ta chỉ muốn các hàng không bao gồm public.rental (nói cách khác là các hàng được chèn trực tiếp vào public.rental), chúng ta thực hiện việc đó bằng cách sử dụng từ khóa DUY NHẤT như sau:

rentaldb_hier=# select * from ONLY rental ;
 id | customerid |       vehicleno        | datestart  | dateend
----+------------+------------------------+------------+---------
  1 |          1 | SOME ABSTRACT PLATE NO | 2018-08-31 |
(1 row)

Một điểm khác biệt giữa Java và PostgreSQL về tính kế thừa là điều này:Java không hỗ trợ đa kế thừa trong khi PostgreSQL thì có, có thể kế thừa từ nhiều hơn một bảng, vì vậy về mặt này chúng ta có thể nghĩ về các bảng giống như giao diện trong Java.

Nếu chúng ta muốn tìm ra bảng chính xác trong hệ thống phân cấp nơi một hàng cụ thể thuộc về (tương đương với obj.getClass (). GetName () trong java), chúng ta có thể thực hiện bằng cách chỉ định cột đặc biệt dạng bảng (oid của bảng tương ứng trong pgclass ), được chuyển sang phân lớp cung cấp tên đầy đủ cho bảng:

rentaldb_hier=# select tableoid::regclass,* from rental ;
   tableoid   | id | customerid |       vehicleno        | datestart  | dateend
--------------+----+------------+------------------------+------------+---------
 rental       |  1 |          1 | SOME ABSTRACT PLATE NO | 2018-08-31 |
 cars.rental  |  2 |          1 | INI 8888               | 2018-08-31 |
 boats.rental |  3 |          2 | INI 9999               | 2018-08-31 |
(3 rows)

Từ các bảng trên (dạng bảng khác nhau), chúng ta có thể suy ra rằng các bảng trong hệ thống phân cấp chỉ là các bảng PostgreSQL cũ đơn thuần, được kết nối với một mối quan hệ kế thừa. Nhưng bên cạnh đó, chúng hoạt động khá giống những chiếc bàn bình thường. Và điều này sẽ được nhấn mạnh hơn trong phần sau.

Thông tin quan trọng &Thông báo trước về Kế thừa PostgreSQL

Bảng con kế thừa:

  • Ràng buộc KHÔNG ĐẦY ĐỦ
  • Ràng buộc KIỂM TRA

Bảng con KHÔNG kế thừa:

  • Ràng buộc CHÍNH CHÍNH
  • Ràng buộc DUY NHẤT
  • Ràng buộc NGOẠI KHÓA

Khi các cột có cùng tên xuất hiện trên định nghĩa của nhiều bảng trên hệ thống phân cấp, thì các cột đó phải có cùng loại và được hợp nhất thành một cột duy nhất. Nếu tồn tại ràng buộc NOT NULL đối với tên cột ở bất kỳ vị trí nào trong hệ thống phân cấp thì điều này sẽ được kế thừa vào bảng con. Các ràng buộc KIỂM TRA có cùng tên cũng được hợp nhất và phải có cùng điều kiện.

Các thay đổi của lược đồ đối với bảng cha (thông qua ALTER TABLE) được truyền trong toàn bộ cấu trúc phân cấp tồn tại bên dưới bảng cha này. Và đây là một trong những tính năng kế thừa tuyệt vời trong PostgreSQL.

Chính sách Bảo mật và Bảo mật (RLS) được quyết định dựa trên bảng thực tế mà chúng tôi sử dụng. Nếu chúng ta sử dụng bảng mẹ thì Bảo mật và RLS của bảng đó sẽ được sử dụng. Ngụ ý rằng việc cấp một đặc quyền trên bảng mẹ cũng cấp quyền cho (các) bảng con, nhưng chỉ khi được truy cập thông qua bảng mẹ. Để truy cập trực tiếp vào bảng con, thì chúng ta phải cấp GRANT rõ ràng trực tiếp cho bảng con, đặc quyền trên bảng mẹ sẽ không đủ. Điều này cũng đúng với RLS.

Về việc kích hoạt trình kích hoạt, trình kích hoạt cấp câu lệnh phụ thuộc vào bảng được đặt tên của câu lệnh, trong khi trình kích hoạt cấp hàng sẽ được kích hoạt tùy thuộc vào bảng mà hàng thực sự thuộc về (vì vậy nó có thể là bảng con).

Những điều cần chú ý:

  • Hầu hết các lệnh hoạt động trên toàn bộ hệ thống phân cấp và hỗ trợ ký hiệu DUY NHẤT. Tuy nhiên, một số lệnh cấp thấp (REINDEX, VACUUM, v.v.) chỉ hoạt động trên các bảng vật lý được đặt tên bởi lệnh. Hãy nhớ đọc tài liệu mỗi lần trong trường hợp nghi ngờ.
  • Các ràng buộc NGOẠI KHÓA (bảng mẹ ở phía tham chiếu) không được kế thừa. Điều này có thể dễ dàng giải quyết bằng cách chỉ định cùng một ràng buộc FK trong tất cả các bảng con của hệ thống phân cấp.
  • Tại thời điểm này (PostgreSQL 10), không có cách nào để có CHỈ SỐ DUY NHẤT toàn cầu (CÁC KHÓA CHÍNH hoặc các ràng buộc DUY NHẤT) trên một nhóm bảng. Kết quả là:
    • Các ràng buộc CHÍNH và UNIQUE không được kế thừa và không có cách nào dễ dàng để thực thi tính duy nhất trên một cột trên tất cả các thành viên của hệ thống phân cấp
    • Khi bảng mẹ nằm ở phía được tham chiếu của ràng buộc NGOẠI KHÓA, thì việc kiểm tra chỉ được thực hiện đối với các giá trị của cột trên các hàng thực sự (vật lý) thuộc về bảng mẹ, không phải bất kỳ bảng con nào.

Hạn chế cuối cùng là một hạn chế nghiêm trọng. Theo các tài liệu chính thức, không có giải pháp nào tốt cho việc này. Tuy nhiên, FK và tính duy nhất là cơ bản cho bất kỳ thiết kế cơ sở dữ liệu nghiêm túc nào. Chúng tôi sẽ xem xét một cách để giải quyết vấn đề này.

Tải xuống Báo cáo chính thức hôm nay Quản lý &Tự động hóa PostgreSQL với ClusterControlTìm hiểu về những điều bạn cần biết để triển khai, giám sát, quản lý và mở rộng PostgreSQLTải xuống Báo cáo chính thức

Kế thừa trong thực tế

Trong phần này, chúng tôi sẽ chuyển đổi một thiết kế cổ điển với các bảng đơn giản, các ràng buộc CHÍNH / PHÍM DUY NHẤT và NGOÀI RA, sang thiết kế nhiều người thuê dựa trên tính kế thừa và chúng tôi sẽ cố gắng giải quyết các vấn đề (dự kiến ​​như phần trước) mà chúng tôi đối mặt. Chúng ta hãy xem xét cùng một doanh nghiệp cho thuê mà chúng tôi đã sử dụng làm ví dụ trong blog trước đó và hãy tưởng tượng rằng lúc đầu doanh nghiệp chỉ cho thuê ô tô (không có thuyền hoặc các loại phương tiện khác). Hãy xem xét lược đồ sau, với các phương tiện của công ty và lịch sử dịch vụ trên các phương tiện đó:

create table vehicle (id SERIAL PRIMARY KEY, plate_no text NOT NULL, maker TEXT NOT NULL, model TEXT NOT NULL,vin text not null);
create table vehicle_service(id SERIAL PRIMARY KEY, vehicleid INT NOT NULL REFERENCES vehicle(id), service TEXT NOT NULL, date_performed DATE NOT NULL DEFAULT now(), cost real not null);
rentaldb=# insert into vehicle (plate_no,maker,model,vin) VALUES ('INI888','Hyundai','i20','HH999');
rentaldb=# insert into vehicle_service (vehicleid,service,cost) VALUES(1,'engine oil change/filters',50);

Bây giờ chúng ta hãy tưởng tượng hệ thống đang được sản xuất, và sau đó công ty mua lại một công ty thứ hai cho thuê thuyền và phải tích hợp những công ty đó vào hệ thống, bằng cách để hai công ty hoạt động độc lập trong phạm vi hoạt động, nhưng theo một cách thống nhất cho sử dụng bởi mgmt hàng đầu. Ngoài ra, hãy tưởng tượng rằng dữ liệu xe_dịch vụ không được chia nhỏ vì tất cả các hàng phải hiển thị cho cả hai công ty. Vì vậy, những gì chúng tôi đang tìm kiếm là cung cấp một giải pháp cho thuê nhiều nơi dựa trên sự kế thừa trên bảng phương tiện. Đầu tiên, chúng ta nên tạo một lược đồ mới cho ô tô, (doanh nghiệp cũ) và một cho thuyền, sau đó di chuyển dữ liệu hiện có sang ô tô.vehicle:

rentaldb=# create schema cars;
rentaldb=# create table cars.vehicle (CONSTRAINT vehicle_pkey PRIMARY KEY(id) ) INHERITS (public.vehicle);
rentaldb=# \d cars.vehicle
                              Table "cars.vehicle"
  Column  |  Type   | Collation | Nullable |               Default               
----------+---------+-----------+----------+-------------------------------------
 id       | integer |           | not null | nextval('vehicle_id_seq'::regclass)
 plate_no | text    |           | not null |
 maker    | text    |           | not null |
 model    | text    |           | not null |
 vin      | text    |           | not null |
Indexes:
    "vehicle_pkey" PRIMARY KEY, btree (id)
Inherits: vehicle
rentaldb=# create schema boats;
rentaldb=# create table boats.vehicle (CONSTRAINT vehicle_pkey PRIMARY KEY(id) ) INHERITS (public.vehicle);
rentaldb=# \d boats.vehicle
                              Table "boats.vehicle"
  Column  |  Type   | Collation | Nullable |               Default               
----------+---------+-----------+----------+-------------------------------------
 id       | integer |           | not null | nextval('vehicle_id_seq'::regclass)
 plate_no | text    |           | not null |
 maker    | text    |           | not null |
 model    | text    |           | not null |
 vin      | text    |           | not null |
Indexes:
    "vehicle_pkey" PRIMARY KEY, btree (id)
Inherits: vehicle

Chúng tôi lưu ý rằng các bảng mới chia sẻ cùng một giá trị mặc định cho cột id (cùng một dãy) với bảng cha. Mặc dù đây không phải là một giải pháp cho vấn đề tính duy nhất toàn cầu được giải thích trong phần trước, nhưng nó là một công việc xung quanh, miễn là không có giá trị rõ ràng nào được sử dụng cho các lần chèn hoặc cập nhật. Nếu tất cả các bảng con (ô tô.vehicle và thuyền.vehicle) được xác định như trên và chúng tôi không bao giờ thao túng id rõ ràng, thì chúng tôi sẽ an toàn.

Vì chúng tôi sẽ chỉ giữ lại bảng phương tiện công cộng và bảng này sẽ tham chiếu đến các hàng của bảng con, chúng tôi phải loại bỏ ràng buộc FK:

rentaldb=# alter table vehicle_service drop CONSTRAINT vehicle_service_vehicleid_fkey ;

Nhưng bởi vì chúng ta cần duy trì tính nhất quán tương đương trong cơ sở dữ liệu của mình, chúng ta phải tìm một giải pháp cho việc này. Chúng tôi sẽ thực hiện ràng buộc này bằng cách sử dụng trình kích hoạt. Chúng ta cần thêm một trình kích hoạt vào xe_service để kiểm tra xem đối với mỗi lần CHÈN hoặc CẬP NHẬT, phương tiện sẽ trỏ đến một hàng hợp lệ ở đâu đó trong hệ thống phân cấp public.vehicle * và một trình kích hoạt trên mỗi bảng của hệ thống phân cấp này sẽ kiểm tra điều đó cho mỗi DELETE hoặc CẬP NHẬT trên id, không tồn tại hàng nào trong xe_chuyển_vàng trỏ đến giá trị cũ. (lưu ý của phương tiện * ký hiệu PostgreSQL ngụ ý điều này và tất cả các bảng con)

CREATE OR REPLACE FUNCTION public.vehicle_service_fk_to_vehicle() RETURNS TRIGGER
        LANGUAGE plpgsql
AS $$
DECLARE
tmp INTEGER;
BEGIN
        IF (TG_OP = 'DELETE') THEN
          RAISE EXCEPTION 'TRIGGER : % called on unsuported op : %',TG_NAME, TG_OP;
        END IF;
        SELECT vh.id INTO tmp FROM public.vehicle vh WHERE vh.id=NEW.vehicleid;
        IF NOT FOUND THEN
          RAISE EXCEPTION '%''d % (id=%) with NEW.vehicleid (%) does not match any vehicle ',TG_OP, TG_TABLE_NAME, NEW.id, NEW.vehicleid USING ERRCODE = 'foreign_key_violation';
        END IF;
        RETURN NEW;
END
$$
;
CREATE CONSTRAINT TRIGGER vehicle_service_fk_to_vehicle_tg AFTER INSERT OR UPDATE ON public.vehicle_service FROM public.vehicle DEFERRABLE FOR EACH ROW EXECUTE PROCEDURE public.vehicle_service_fk_to_vehicle();

Nếu chúng tôi cố gắng cập nhật hoặc chèn giá trị cho cột carid không tồn tại trong xe * thì chúng tôi sẽ gặp lỗi:

rentaldb=# insert into vehicle_service (vehicleid,service,cost) VALUES(2,'engine oil change/filters',50);
ERROR:  INSERT'd vehicle_service (id=2) with NEW.vehicleid (2) does not match any vehicle
CONTEXT:  PL/pgSQL function vehicle_service_fk_to_vehicle() line 10 at RAISE

Bây giờ nếu chúng ta chèn một hàng vào bất kỳ bảng nào trong hệ thống phân cấp, ví dụ:Thuyền.vehicle (thường sẽ lấy id =2) và thử lại:

rentaldb=# insert into boats.vehicle (maker, model,plate_no,vin) VALUES('Zodiac','xx','INI000','ZZ20011');
rentaldb=# select * from vehicle;
 id | plate_no |  maker  | model |   vin   
----+----------+---------+-------+---------
  1 | INI888   | Hyundai | i20   | HH999
  2 | INI000   | Zodiac  | xx    | ZZ20011
(2 rows)
rentaldb=# insert into vehicle_service (vehicleid,service,cost) VALUES(2,'engine oil change/filters',50);

Sau đó, INSERT trước đó thành công. Bây giờ chúng ta cũng nên bảo vệ mối quan hệ FK này ở phía bên kia, chúng ta phải đảm bảo rằng không cho phép cập nhật / xóa trên bất kỳ bảng nào trong hệ thống phân cấp nếu hàng cần xóa (hoặc cập nhật) được tham chiếu bởi xe_service:

CREATE OR REPLACE FUNCTION public.vehicle_fk_from_vehicle_service() RETURNS TRIGGER
        LANGUAGE plpgsql
AS $$
DECLARE
tmp INTEGER;
BEGIN
        IF (TG_OP = 'INSERT') THEN
          RAISE EXCEPTION 'TRIGGER : % called on unsuported op : %',TG_NAME, TG_OP;
        END IF;
        IF (TG_OP = 'DELETE' OR OLD.id <> NEW.id) THEN
          SELECT vhs.id INTO tmp FROM vehicle_service vhs WHERE vhs.vehicleid=OLD.id;
          IF FOUND THEN
            RAISE EXCEPTION '%''d % (OLD id=%) matches existing vehicle_service with id=%',TG_OP, TG_TABLE_NAME, OLD.id,tmp USING ERRCODE = 'foreign_key_violation';
          END IF;
        END IF;
        IF (TG_OP = 'UPDATE') THEN
                RETURN NEW;
        ELSE
                RETURN OLD;
        END IF;
END
$$
;
CREATE CONSTRAINT TRIGGER vehicle_fk_from_vehicle_service AFTER DELETE OR UPDATE
ON public.vehicle FROM vehicle_service DEFERRABLE FOR EACH ROW EXECUTE PROCEDURE vehicle_fk_from_vehicle_service();
CREATE CONSTRAINT TRIGGER vehicle_fk_from_vehicle_service AFTER DELETE OR UPDATE
ON cars.vehicle FROM vehicle_service DEFERRABLE FOR EACH ROW EXECUTE PROCEDURE vehicle_fk_from_vehicle_service();
CREATE CONSTRAINT TRIGGER vehicle_fk_from_vehicle_service AFTER DELETE OR UPDATE
ON boats.vehicle FROM vehicle_service DEFERRABLE FOR EACH ROW EXECUTE PROCEDURE vehicle_fk_from_vehicle_service();

Hãy để chúng tôi thử nó:

rentaldb=# delete from vehicle where id=2;
ERROR:  DELETE'd vehicle (OLD id=2) matches existing vehicle_service with id=3
CONTEXT:  PL/pgSQL function vehicle_fk_from_vehicle_service() line 11 at RAISE

Bây giờ chúng ta cần chuyển dữ liệu hiện có trong public.vehicle sang ô tô.vehicle.

rentaldb=# begin ;
rentaldb=# set constraints ALL deferred ;
rentaldb=# set session_replication_role TO replica;
rentaldb=# insert into cars.vehicle select * from only public.vehicle;
rentaldb=# delete from only public.vehicle;
rentaldb=# commit ;

Việc đặt bản sao session_replication_role TO ngăn chặn việc kích hoạt các trình kích hoạt bình thường. Lưu ý rằng, sau khi di chuyển dữ liệu, chúng tôi có thể muốn vô hiệu hóa hoàn toàn bảng mẹ (public.vehicle) chấp nhận chèn (hầu hết có thể thông qua một quy tắc). Trong trường hợp này, trong phép tương tự OO, chúng ta sẽ coi public.vehicle như một lớp trừu tượng, tức là không có hàng (trường hợp). Việc sử dụng thiết kế này để cho nhiều người thuê nhà cảm thấy tự nhiên vì vấn đề cần giải quyết là một trường hợp sử dụng cổ điển để thừa kế, tuy nhiên, những vấn đề chúng tôi gặp phải không hề nhỏ. Điều này đã được thảo luận bởi cộng đồng tin tặc và chúng tôi hy vọng sẽ có những cải tiến trong tương lai.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Tham gia truy vấn đếm trên create_series () và truy xuất giá trị Null là '0'

  2. Các cột MySQL với DEFAULT NULL - sự lựa chọn theo kiểu hay là?

  3. Cách cài đặt PostgreSQL 12 trên Ubuntu 20.04 / 18.04 / 16.04

  4. Cách hoạt động của hàm to_number () trong PostgreSQL

  5. Kết nối với cơ sở dữ liệu PostgreSQL trên vùng chứa Docker