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

Các nguyên tắc cơ bản về biểu thức bảng, Phần 9 - Chế độ xem, so sánh với các bảng dẫn xuất và CTE

Đây là phần thứ 9 trong loạt bài về các biểu thức bảng được đặt tên. Trong Phần 1, tôi đã cung cấp thông tin cơ bản về các biểu thức bảng đã đặt tên, bao gồm các bảng dẫn xuất, các biểu thức bảng chung (CTE), các khung nhìn và các hàm có giá trị bảng nội tuyến (iTVF). Trong Phần 2, Phần 3 và Phần 4, tôi tập trung vào các bảng dẫn xuất. Trong Phần 5, Phần 6, Phần 7 và Phần 8, tôi tập trung vào CTE. Như tôi đã giải thích, các bảng dẫn xuất và CTE là các biểu thức bảng được đặt tên trong phạm vi câu lệnh. Sau khi câu lệnh xác định chúng kết thúc, chúng sẽ biến mất.

Bây giờ chúng tôi đã sẵn sàng để tiếp tục đề cập đến các biểu thức bảng được đặt tên có thể sử dụng lại. Đó là, những cái được tạo như một đối tượng trong cơ sở dữ liệu và ở đó vĩnh viễn trừ khi bị loại bỏ. Như vậy, tất cả những người có quyền phù hợp đều có thể truy cập và sử dụng lại chúng. Lượt xem và iTVF thuộc loại này. Sự khác biệt giữa cả hai chủ yếu là ở chỗ cái trước không hỗ trợ các tham số đầu vào và cái sau thì có.

Trong bài viết này, tôi bắt đầu giới thiệu về các quan điểm. Giống như tôi đã làm trước đây, trước tiên tôi sẽ tập trung vào các khía cạnh lôgic hoặc khái niệm, và sau đó, tiến hành các khía cạnh tối ưu hóa. Với bài viết đầu tiên về các chế độ xem, tôi muốn bắt đầu bằng việc tập trung vào chế độ xem là gì, sử dụng thuật ngữ chính xác và so sánh các cân nhắc về thiết kế của các chế độ xem với các bảng dẫn xuất và CTE đã thảo luận trước đây.

Trong các ví dụ của mình, tôi sẽ sử dụng cơ sở dữ liệu mẫu có tên là TSQLV5. Bạn có thể tìm thấy tập lệnh tạo và điền nó tại đây và sơ đồ ER của nó tại đây.

Chế độ xem là gì?

Như thường lệ khi thảo luận về lý thuyết quan hệ, các học viên SQL chúng tôi thường được cho biết rằng thuật ngữ chúng tôi đang sử dụng là sai. Vì vậy, với tinh thần này, ngay từ đầu, tôi sẽ bắt đầu bằng cách nói rằng khi bạn sử dụng thuật ngữ bảng và chế độ xem , nó sai. Tôi đã học được điều này từ Chris Date.

Nhớ lại rằng một bảng là bản sao của SQL với một mối quan hệ (đơn giản hóa quá trình thảo luận xung quanh các giá trị và biến một chút). Một bảng có thể là một bảng cơ sở được định nghĩa như một đối tượng trong cơ sở dữ liệu hoặc nó có thể là một bảng được trả về bởi một biểu thức — cụ thể hơn là một biểu thức bảng. Điều đó tương tự như thực tế là một quan hệ có thể là một quan hệ được trả về từ một biểu thức quan hệ. Biểu thức bảng có thể là một truy vấn.

Bây giờ, một khung nhìn là gì? Đó là một biểu thức bảng được đặt tên, giống như CTE là một biểu thức bảng được đặt tên. Giống như tôi đã nói, chế độ xem là một biểu thức bảng được đặt tên có thể sử dụng lại được tạo dưới dạng một đối tượng trong cơ sở dữ liệu và có thể truy cập được đối với những người có quyền phù hợp. Đây là tất cả để nói, một khung nhìn là một cái bàn. Nó không phải là một bảng cơ sở, nhưng vẫn là một bảng. Vì vậy, giống như việc nói “một hình chữ nhật và một hình vuông” hoặc “một rượu whisky và một ly Lagavulin” sẽ có vẻ lạ (trừ khi bạn có quá nhiều Lagavulin!), Việc sử dụng “bảng và hình chiếu” là không phù hợp.

Cú pháp

Đây là cú pháp T-SQL cho câu lệnh CREATE VIEW:

TẠO [HOẶC ALTER] XEM [. ] [(<đích các cột>)]
[VỚI ]
AS

[CÓ CHỌN KIỂM TRA]
[; ]

Câu lệnh CREATE VIEW phải là câu lệnh đầu tiên và duy nhất trong lô.

Lưu ý rằng phần CREATE OR ALTER đã được giới thiệu trong SQL Server 2016 SP1, vì vậy nếu bạn đang sử dụng phiên bản cũ hơn, bạn sẽ cần phải làm việc với các câu lệnh CREATE VIEW và ALTER VIEW riêng biệt tùy thuộc vào việc đối tượng đã tồn tại hay chưa. Như bạn có thể đã biết, việc thay đổi một đối tượng hiện có sẽ giữ lại các quyền được chỉ định. Đó là một trong những lý do tại sao việc thay đổi một đối tượng hiện có thường là hợp lý thay vì bỏ và tạo lại nó. Điều khiến một số người ngạc nhiên là việc thay đổi chế độ xem không giữ lại các thuộc tính chế độ xem hiện có; những thứ đó cần được chỉ định nếu bạn muốn giữ lại chúng.

Dưới đây là một ví dụ về định nghĩa chế độ xem đơn giản đại diện cho khách hàng Hoa Kỳ:

USE TSQLV5;
GO
 
CREATE OR ALTER VIEW Sales.USACustomers
AS
  SELECT custid, companyname
  FROM Sales.Customers
  WHERE country = N'USA';
GO

Và đây là một câu lệnh truy vấn chế độ xem:

SELECT custid, companyname
FROM Sales.USACustomers;

Giữa câu lệnh tạo chế độ xem và câu lệnh truy vấn nó, bạn sẽ tìm thấy ba phần tử giống nhau có liên quan đến một câu lệnh so với bảng dẫn xuất hoặc CTE:

  1. Biểu thức bảng bên trong (truy vấn bên trong của chế độ xem)
  2. Tên bảng được chỉ định (tên chế độ xem)
  3. Câu lệnh với truy vấn bên ngoài đối với chế độ xem

Những người trong số các bạn có con mắt tinh tường sẽ nhận thấy rằng thực sự có hai biểu thức bảng liên quan ở đây. Có cái bên trong (truy vấn bên trong của chế độ xem) và có cái bên ngoài (truy vấn trong câu lệnh chống lại chế độ xem). Trong câu lệnh có truy vấn đối với dạng xem, bản thân truy vấn là một biểu thức bảng và khi bạn thêm dấu chấm hết, nó sẽ trở thành một câu lệnh. Điều này nghe có vẻ cầu kỳ, nhưng nếu bạn hiểu được điều này và gọi mọi thứ bằng đúng tên của chúng, điều đó sẽ phản ánh kiến ​​thức của bạn. Và có tuyệt không khi bạn biết rằng bạn biết?

Ngoài ra, tất cả các yêu cầu từ biểu thức bảng trong các bảng dẫn xuất và CTE mà chúng ta đã thảo luận trước đó trong loạt bài này, đều áp dụng cho biểu thức bảng mà chế độ xem dựa trên. Xin nhắc lại, các yêu cầu là:

  • Tất cả các cột của biểu thức bảng phải có tên
  • Tất cả các tên cột của biểu thức bảng phải là duy nhất
  • Các hàng của biểu thức bảng không có thứ tự

Nếu bạn cần nâng cao hiểu biết của mình về những gì đằng sau những yêu cầu này, hãy xem phần “Biểu thức bảng là một bảng” trong Phần 2 của loạt bài này. Hãy chắc chắn rằng bạn đặc biệt hiểu phần "không đặt hàng". Xin nhắc lại một cách ngắn gọn, một biểu thức bảng là một bảng và như vậy không có thứ tự. Đó là lý do tại sao bạn không thể tạo chế độ xem dựa trên truy vấn có mệnh đề ORDER BY, trừ khi mệnh đề này ở đó để hỗ trợ bộ lọc TOP hoặc OFFSET-FETCH. Và ngay cả khi ngoại lệ này cho phép truy vấn bên trong có mệnh đề ORDER BY, bạn muốn nhớ rằng nếu truy vấn bên ngoài đối với chế độ xem không có mệnh đề ORDER BY của riêng nó, bạn không nhận được đảm bảo rằng truy vấn sẽ trả về các hàng theo bất kỳ thứ tự cụ thể nào, đừng bận tâm đến hành vi được quan sát. Điều này cực kỳ quan trọng cần phải hiểu!

Lồng và nhiều tham chiếu

Khi thảo luận về các cân nhắc thiết kế của các bảng dẫn xuất và CTE, tôi đã so sánh hai bảng này theo cả cách lồng vào nhau và nhiều tham chiếu. Bây giờ, hãy xem lượt xem ở các phòng ban này như thế nào. Tôi sẽ bắt đầu với việc lồng vào nhau. Vì mục đích này, chúng tôi sẽ so sánh mã trả về những năm mà hơn 70 khách hàng đã đặt hàng bằng cách sử dụng bảng, CTE và chế độ xem có nguồn gốc. Bạn đã thấy mã với các bảng dẫn xuất và CTE trước đó trong loạt bài này. Đây là mã xử lý tác vụ bằng cách sử dụng các bảng dẫn xuất:

SELECT orderyear, numcusts
FROM ( SELECT orderyear, COUNT(DISTINCT custid) AS numcusts
       FROM ( SELECT YEAR(orderdate) AS orderyear, custid
              FROM Sales.Orders ) AS D1
       GROUP BY orderyear ) AS D2
WHERE numcusts > 70;

Tôi đã chỉ ra rằng nhược điểm chính mà tôi thấy với các bảng dẫn xuất ở đây là việc bạn lồng các định nghĩa bảng dẫn xuất và điều này có thể dẫn đến sự phức tạp trong việc hiểu, duy trì và gỡ rối mã như vậy.

Đây là mã xử lý cùng một tác vụ bằng CTE:

WITH C1 AS
(
  SELECT YEAR(orderdate) AS orderyear, custid
  FROM Sales.Orders
),
C2 AS
(
  SELECT orderyear, COUNT(DISTINCT custid) AS numcusts
  FROM C1
  GROUP BY orderyear
)
SELECT orderyear, numcusts
FROM C2
WHERE numcusts > 70;

Tôi đã chỉ ra rằng đối với tôi, điều này giống như mã rõ ràng hơn nhiều do thiếu lồng ghép. Bạn có thể thấy từng bước trong giải pháp từ đầu đến cuối riêng biệt trong đơn vị của riêng nó, với logic của giải pháp trôi chảy rõ ràng từ trên xuống dưới. Do đó, tôi thấy tùy chọn CTE là một cải tiến so với các bảng dẫn xuất về mặt này.

Bây giờ đến lượt xem. Hãy nhớ rằng, một trong những lợi ích chính của lượt xem là khả năng tái sử dụng. Bạn cũng có thể kiểm soát quyền truy cập. Sự phát triển của các đơn vị liên quan hơi giống với CTE theo nghĩa là bạn có thể tập trung sự chú ý của mình vào một đơn vị tại một thời điểm từ đầu đến cuối. Hơn nữa, bạn có thể linh hoạt để quyết định xem có nên tạo một chế độ xem riêng biệt cho mỗi đơn vị trong giải pháp hay chỉ một chế độ xem dựa trên một truy vấn liên quan đến các biểu thức bảng được đặt tên trong phạm vi câu lệnh.

Bạn sẽ sử dụng cái cũ khi mỗi đơn vị cần được tái sử dụng. Đây là mã bạn sẽ sử dụng trong trường hợp như vậy, tạo ra ba chế độ xem:

-- Sales.OrderYears
CREATE OR ALTER VIEW Sales.OrderYears
AS 
  SELECT YEAR(orderdate) AS orderyear, custid
  FROM Sales.Orders;
GO
 
-- Sales.YearlyCustCounts
CREATE OR ALTER VIEW Sales.YearlyCustCounts
AS
  SELECT orderyear, COUNT(DISTINCT custid) AS numcusts
  FROM Sales.OrderYears
  GROUP BY orderyear;
GO
 
-- Sales.YearlyCustCountsMin70
CREATE OR ALTER VIEW Sales.YearlyCustCountsAbove70
AS
  SELECT orderyear, numcusts
  FROM Sales.YearlyCustCounts
  WHERE numcusts > 70;
GO

Bạn có thể truy vấn từng chế độ xem một cách độc lập, nhưng đây là mã bạn sẽ sử dụng để trả lại nhiệm vụ ban đầu sau đó.

SELECT orderyear, numcusts
FROM Sales.YearlyCustCountsAbove70;

Nếu chỉ có yêu cầu về khả năng tái sử dụng đối với phần ngoài cùng (nhiệm vụ ban đầu yêu cầu) thì thực sự không cần thiết phải phát triển ba chế độ xem khác nhau. Bạn có thể tạo một dạng xem dựa trên truy vấn liên quan đến CTE hoặc bảng dẫn xuất. Đây là cách bạn sẽ làm điều đó với truy vấn liên quan đến CTE:

CREATE OR ALTER VIEW Sales.YearlyCustCountsAbove70
AS
  WITH C1 AS
  (
    SELECT YEAR(orderdate) AS orderyear, custid
    FROM Sales.Orders
  ),
  C2 AS
  (
    SELECT orderyear, COUNT(DISTINCT custid) AS numcusts
    FROM C1
    GROUP BY orderyear
  )
  SELECT orderyear, numcusts
  FROM C2
  WHERE numcusts > 70;
GO

Nhân tiện, nếu nó không rõ ràng, các CTE mà truy vấn bên trong của chế độ xem dựa trên có thể là đệ quy.

Hãy tiếp tục các trường hợp bạn cần nhiều tham chiếu đến cùng một biểu thức bảng từ truy vấn bên ngoài. Nhiệm vụ cho ví dụ này là tính toán số lượng thứ tự hàng năm mỗi năm và so sánh số lượng trong mỗi năm với năm trước đó. Cách dễ nhất để đạt được điều này thực sự là sử dụng hàm cửa sổ LAG, nhưng chúng tôi sẽ sử dụng phép nối giữa hai trường hợp của biểu thức bảng biểu thị số lượng đơn hàng hàng năm chỉ để so sánh trường hợp nhiều tham chiếu giữa ba công cụ.

Đây là mã mà chúng tôi đã sử dụng trước đó trong loạt bài để xử lý tác vụ với các bảng dẫn xuất:

SELECT CUR.orderyear, CUR.numorders,
  CUR.numorders - PRV.numorders AS diff
FROM ( SELECT YEAR(orderdate) AS orderyear, COUNT(*) AS numorders
       FROM Sales.Orders
       GROUP BY YEAR(orderdate) ) AS CUR
  LEFT OUTER JOIN
     ( SELECT YEAR(orderdate) AS orderyear, COUNT(*) AS numorders
       FROM Sales.Orders
       GROUP BY YEAR(orderdate) ) AS PRV
    ON CUR.orderyear = PRV.orderyear + 1;

Có một nhược điểm rất rõ ràng ở đây. Bạn phải lặp lại định nghĩa của biểu thức bảng hai lần. Về cơ bản, bạn đang xác định hai biểu thức bảng được đặt tên dựa trên cùng một mã truy vấn.

Đây là mã xử lý cùng một tác vụ bằng CTE:

WITH OrdCount AS
(
  SELECT YEAR(orderdate) AS orderyear, COUNT(*) AS numorders
  FROM Sales.Orders
  GROUP BY YEAR(orderdate)
)
SELECT CUR.orderyear, CUR.numorders,
  CUR.numorders - PRV.numorders AS diff
FROM OrdCount AS CUR
  LEFT OUTER JOIN OrdCount AS PRV
    ON CUR.orderyear = PRV.orderyear + 1;

Có một lợi thế rõ ràng ở đây; bạn chỉ xác định một biểu thức bảng được đặt tên dựa trên một phiên bản duy nhất của truy vấn bên trong và tham chiếu đến nó hai lần từ truy vấn bên ngoài.

Các chế độ xem tương tự như CTE hơn theo nghĩa này. Bạn chỉ xác định một chế độ xem chỉ dựa trên một bản sao của truy vấn, như sau:

CREATE OR ALTER VIEW Sales.YearlyOrderCounts
AS
  SELECT YEAR(orderdate) AS orderyear, COUNT(*) AS numorders
  FROM Sales.Orders
  GROUP BY YEAR(orderdate);
GO

Nhưng tốt hơn so với CTE, bạn không bị giới hạn chỉ sử dụng lại biểu thức bảng đã đặt tên trong câu lệnh bên ngoài. Bạn có thể sử dụng lại tên chế độ xem bất kỳ số lần nào bạn muốn, với bất kỳ số lượng truy vấn không liên quan nào, miễn là bạn có quyền phù hợp. Đây là mã để đạt được nhiệm vụ bằng cách sử dụng nhiều tham chiếu đến chế độ xem:

SELECT CUR.orderyear, CUR.numorders,
  CUR.numorders - PRV.numorders AS diff
FROM Sales.YearlyOrderCounts AS CUR
  LEFT OUTER JOIN Sales.YearlyOrderCounts AS PRV
    ON CUR.orderyear = PRV.orderyear + 1;

Có vẻ như các khung nhìn giống với CTE hơn là các bảng dẫn xuất, với chức năng bổ sung là một công cụ có thể tái sử dụng nhiều hơn, với khả năng kiểm soát quyền. Hoặc để xoay chuyển tình thế, có lẽ thích hợp để coi CTE là một chế độ xem trong phạm vi tuyên bố. Bây giờ điều có thể thực sự tuyệt vời là nếu chúng ta cũng có một biểu thức bảng được đặt tên với phạm vi rộng hơn CTE, hẹp hơn so với một khung nhìn. Ví dụ:sẽ thật tuyệt nếu chúng ta có một biểu thức bảng được đặt tên có phạm vi cấp phiên phải không?

Tóm tắt

Tôi yêu chủ đề này. Có rất nhiều biểu thức trong bảng bắt nguồn từ lý thuyết quan hệ, đến lượt nó lại bắt nguồn từ toán học. Tôi thích biết các thuật ngữ phù hợp cho mọi thứ là gì và nói chung là đảm bảo rằng tôi đã tìm hiểu kỹ các nền tảng, ngay cả khi đối với một số người, nó có vẻ như là cầu kỳ và quá rườm rà. Nhìn lại quá trình học tập của mình trong những năm qua, tôi có thể thấy một con đường rất rõ ràng giữa việc kiên trì nắm bắt tốt các nền tảng, sử dụng thuật ngữ chính xác và thực sự hiểu biết về công cụ của bạn sau này khi nó chuyển sang những thứ phức tạp và cao cấp hơn nhiều.

Vì vậy, những yếu tố quan trọng khi nói đến lượt xem là gì?

  • Chế độ xem là một bảng.
  • Đây là một bảng có nguồn gốc từ một truy vấn (một biểu thức bảng).
  • Nó được đặt một cái tên mà người dùng có vẻ giống như tên bảng, vì nó là tên bảng.
  • Nó được tạo như một đối tượng cố định trong cơ sở dữ liệu.
  • Bạn có thể kiểm soát quyền truy cập đối với chế độ xem.

Các chế độ xem tương tự như CTE theo một số cách. Theo nghĩa là bạn phát triển các giải pháp của mình theo cách mô-đun, tập trung vào một đơn vị tại một thời điểm từ đầu đến cuối. Cũng theo nghĩa là bạn có thể có nhiều tham chiếu đến tên dạng xem từ truy vấn bên ngoài. Nhưng tốt hơn CTE, các chế độ xem không chỉ giới hạn trong phạm vi của câu lệnh bên ngoài, mà còn có thể sử dụng lại cho đến khi bị loại bỏ khỏi cơ sở dữ liệu.

Còn rất nhiều điều để nói về quan điểm và tôi sẽ tiếp tục cuộc thảo luận vào tháng tới. Trong khi đó, tôi muốn để lại cho bạn một suy nghĩ. Với các bảng và CTE dẫn xuất, bạn có thể đặt trường hợp có lợi cho SELECT * trong một truy vấn bên trong. Xem trường hợp tôi đã làm cho nó trong Phần 3 của loạt bài để biết chi tiết. Bạn có thể đặt ra một trường hợp tương tự với các lượt xem hay đó là một ý tưởng tồi với những lượt xem đó?


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Sử dụng Jenkins với Kubernetes AWS, Phần 3

  2. Tối ưu hóa các truy vấn chồng chéo Phần 1:Giới thiệu &Giải pháp T-SQL nâng cao

  3. Cách lọc các bản ghi bằng hàm tổng hợp COUNT

  4. Ký hiệu IDEF1X

  5. Báo cáo cơ sở dữ liệu nguồn mở năm 2019:Cơ sở dữ liệu hàng đầu, Đám mây công cộng so với Tại chỗ, Tính bền vững của đa thức