Tại sao RDBMS không trả lại các bảng đã tham gia theo định dạng lồng nhau?


14

Ví dụ: giả sử tôi muốn tìm nạp Người dùng và tất cả số điện thoại và địa chỉ email của anh ấy. Các số điện thoại và email được lưu trữ trong các bảng riêng biệt, Một người dùng cho nhiều điện thoại / email. Tôi có thể làm điều này khá dễ dàng:

SELECT * FROM users user 
    LEFT JOIN emails email ON email.user_id=user.id
    LEFT JOIN phones phone ON phone.user_id=user.id

Vấn đề * với điều này là nó trả lại tên người dùng, DOB, màu yêu thích và tất cả các thông tin khác được lưu trữ trong bảng người dùng lặp đi lặp lại cho mỗi bản ghi (người dùng gửi email bản ghi điện thoại), có lẽ ăn hết băng thông và làm chậm xuống kết quả.

Sẽ không đẹp hơn nếu nó trả về một hàng cho mỗi người dùng và trong hồ sơ đó có một danh sách email và danh sách điện thoại? Nó sẽ làm cho dữ liệu dễ dàng hơn để làm việc với quá.

Tôi biết bạn có thể nhận được kết quả như thế này bằng cách sử dụng LINQ hoặc có lẽ các khung công tác khác, nhưng dường như đó là một điểm yếu trong thiết kế cơ sở của cơ sở dữ liệu quan hệ.

Chúng ta có thể khắc phục điều này bằng cách sử dụng NoQuery, nhưng không nên có một số điểm trung gian?

Tui bỏ lỡ điều gì vậy? Tại sao điều này không tồn tại?

* Có, nó được thiết kế theo cách này. Tôi hiểu rồi. Tôi đang tự hỏi tại sao không có sự thay thế nào dễ làm việc hơn. SQL có thể tiếp tục làm những gì nó đang làm nhưng sau đó họ có thể thêm một hoặc hai từ khóa để thực hiện một chút xử lý hậu kỳ trả về dữ liệu theo định dạng lồng nhau thay vì sản phẩm cartesian.

Tôi biết điều này có thể được thực hiện bằng ngôn ngữ kịch bản mà bạn chọn, nhưng nó yêu cầu máy chủ SQL phải gửi dữ liệu dư thừa (ví dụ bên dưới) hoặc bạn đưa ra nhiều truy vấn như thế nào SELECT email FROM emails WHERE user_id IN (/* result of first query */).


Thay vì có MySQL trả lại một cái gì đó giống như thế này:

[
    {
        "name": "John Smith",
        "dob": "1945-05-13",
        "fav_color": "red",
        "email": "johnsmith45@gmail.com",
    },
    {
        "name": "John Smith",
        "dob": "1945-05-13",
        "fav_color": "red",
        "email": "john@smithsunite.com",
    },
    {
        "name": "Jane Doe",
        "dob": "1953-02-19",
        "fav_color": "green",
        "email": "originaljane@deerclan.com",
    }
]

Và sau đó phải nhóm trên một số định danh duy nhất (có nghĩa là tôi cũng cần tìm nạp phía đó!) Phía khách hàng để định dạng lại tập kết quả theo cách bạn muốn, chỉ cần trả về điều này:

[
    {
        "name": "John Smith",
        "dob": "1945-05-13",
        "fav_color": "red",
        "emails": ["johnsmith45@gmail.com", "john@smithsunite.com"]
    },
    {
        "name": "Jane Doe",
        "dob": "1953-02-19",
        "fav_color": "green",
        "emails": ["originaljane@deerclan.com"],
    }
]

Ngoài ra, tôi có thể đưa ra 3 truy vấn: 1 cho người dùng, 1 cho email và 1 cho số điện thoại, nhưng sau đó bộ kết quả số email và số điện thoại cần phải chứa user_id để tôi có thể kết hợp chúng với người dùng Tôi đã lấy trước đây. Một lần nữa, dữ liệu dư thừa và xử lý hậu kỳ không cần thiết.


6
Hãy nghĩ về SQL như một bảng tính, giống như trong Microsoft Excel, sau đó thử tìm cách tạo một giá trị ô có chứa các ô bên trong. Nó không còn hoạt động tốt như một bảng tính. Những gì bạn đang tìm kiếm là một cấu trúc cây, nhưng sau đó bạn không còn có lợi ích của bảng tính (tức là bạn không thể tổng số cột trong một cây). Các cấu trúc cây không làm cho các báo cáo rất dễ đọc của con người.
Phản ứng

54
SQL không tệ trong việc trả lại dữ liệu, bạn rất tệ trong việc truy vấn những gì bạn muốn. Theo nguyên tắc thông thường, nếu bạn nghĩ rằng một công cụ được sử dụng rộng rãi là lỗi hoặc bị hỏng đối với trường hợp sử dụng phổ biến, thì vấn đề là bạn.
Sean McS Something

12
@SeanMcS Something Thật sự rất đau, tôi không thể tự nói điều đó tốt hơn.
WernerCD

5
Đây là một câu hỏi tuyệt vời. Câu trả lời đang nói "đây là cách của nó" đang thiếu điểm. Tại sao không thể trả về các hàng với bộ sưu tập hàng được nhúng?
Chris Pitman

8
@SeanMcS Something: Trừ khi công cụ được sử dụng rộng rãi là C ++ hoặc PHP, trong trường hợp đó bạn có thể đúng. ;)
Mason Wheeler

Câu trả lời:


11

Sâu xa hơn, trong ruột của một cơ sở dữ liệu quan hệ, tất cả các hàng và cột của nó. Đó là cấu trúc mà một cơ sở dữ liệu quan hệ được tối ưu hóa để làm việc với. Con trỏ làm việc trên các hàng riêng lẻ tại một thời điểm. Một số thao tác tạo các bảng tạm thời (một lần nữa, nó cần phải là các hàng và cột).

Bằng cách làm việc chỉ với các hàng và chỉ trả lại các hàng, hệ thống có thể xử lý tốt hơn với bộ nhớ và lưu lượng mạng.

Như đã đề cập, điều này cho phép thực hiện một số tối ưu hóa nhất định (chỉ mục, tham gia, đoàn thể, v.v.)

Nếu một người muốn có một cấu trúc cây lồng nhau, điều này đòi hỏi người ta phải kéo tất cả dữ liệu cùng một lúc. Đã qua rồi các tối ưu hóa cho các con trỏ ở phía cơ sở dữ liệu. Tương tự như vậy, lưu lượng truy cập qua mạng trở thành một vụ nổ lớn có thể mất nhiều thời gian hơn so với dòng chảy chậm theo từng hàng (đây là thứ đôi khi bị mất trong thế giới web ngày nay).

Mỗi ngôn ngữ có mảng trong đó. Đây là những điều dễ dàng để làm việc và giao diện với. Bằng cách sử dụng một cấu trúc rất nguyên thủy, trình điều khiển giữa cơ sở dữ liệu và chương trình - bất kể ngôn ngữ nào - có thể hoạt động theo cách phổ biến. Khi một người bắt đầu thêm cây, các cấu trúc trong ngôn ngữ trở nên phức tạp hơn và khó đi qua hơn.

Không khó để ngôn ngữ lập trình chuyển đổi các hàng được trả lại thành một số cấu trúc khác. Biến nó thành một cây hoặc một bộ băm hoặc để nó dưới dạng một danh sách các hàng mà bạn có thể lặp lại.

Cũng có lịch sử tại nơi làm việc ở đây. Truyền dữ liệu có cấu trúc là một cái gì đó xấu xí trong thời đại cũ. Nhìn vào định dạng EDI để có ý tưởng về những gì bạn có thể yêu cầu. Cây cũng ngụ ý đệ quy - điều mà một số ngôn ngữ không hỗ trợ (hai ngôn ngữ quan trọng nhất của ngày xưa không hỗ trợ đệ quy - đệ quy không vào Fortran cho đến khi F90 và trong thời đại COBOL cũng không).

Và trong khi các ngôn ngữ ngày nay có hỗ trợ đệ quy và các loại dữ liệu nâng cao hơn, thực sự không có lý do chính đáng để thay đổi mọi thứ. Họ làm việc, và họ làm việc tốt. Những thứ đang thay đổi mọi thứ là cơ sở dữ liệu nosql. Bạn có thể lưu trữ cây trong các tài liệu trong một tài liệu dựa trên một tài liệu. LDAP (thực sự cũ kỹ) cũng là một hệ thống dựa trên cây (mặc dù nó có thể không phải là những gì bạn đang theo đuổi). Ai biết được, có lẽ điều tiếp theo trong cơ sở dữ liệu nosql sẽ là thứ trả về truy vấn dưới dạng đối tượng json.

Tuy nhiên, cơ sở dữ liệu quan hệ 'cũ' ... họ đang làm việc với các hàng vì đó là những gì họ giỏi và mọi thứ có thể nói chuyện với họ mà không gặp rắc rối hoặc dịch thuật.

  1. Trong thiết kế giao thức, sự hoàn hảo đã đạt được không phải khi không còn gì để thêm, mà là khi không còn gì để lấy đi.

Từ RFC 1925 - Mười hai sự thật về mạng


"Nếu người ta muốn có một cấu trúc cây lồng nhau, thì điều này đòi hỏi người ta phải rút tất cả dữ liệu cùng một lúc. Đã qua tối ưu hóa cho các con trỏ ở phía cơ sở dữ liệu." - Điều đó không đúng. Nó sẽ chỉ phải duy trì một vài con trỏ: một cho bảng chính, và một cho mỗi bảng tham gia. Tùy thuộc vào giao diện, nó có thể trả về một hàng và tất cả các bảng đã tham gia trong một đoạn (được truyền phát một phần) hoặc nó có thể truyền phát các cây con (và có lẽ thậm chí không truy vấn chúng) cho đến khi bạn bắt đầu lặp lại chúng. Nhưng vâng, điều đó làm phức tạp mọi thứ rất nhiều.
mở

3
Mỗi ngôn ngữ hiện đại nên có một số loại cây mặc dù, không? Và nó sẽ không phụ thuộc vào người lái xe để đối phó với điều đó? Tôi đoán những người SQL vẫn cần thiết kế một định dạng chung (không biết nhiều về điều đó). Mặc dù vậy, điều khiến tôi phải gửi 1 truy vấn có tham gia và quay lại và lọc dữ liệu dư thừa mà mỗi hàng (thông tin người dùng, chỉ thay đổi mỗi hàng thứ N) hoặc phát hành 1 truy vấn (người dùng) và lặp lại kết quả, sau đó gửi thêm hai truy vấn (email, điện thoại) cho mỗi bản ghi để lấy thông tin tôi cần. Hoặc là phương pháp có vẻ lãng phí.
mở

51

Nó trả về chính xác những gì bạn yêu cầu: một bộ bản ghi duy nhất chứa sản phẩm của Cartesian được xác định bởi các phép nối. Có rất nhiều kịch bản hợp lệ trong đó chính xác là những gì bạn muốn, vì vậy nói rằng SQL đang cho một kết quả tồi tệ (và do đó ngụ ý rằng sẽ tốt hơn nếu bạn thay đổi nó) thực sự sẽ làm hỏng rất nhiều truy vấn.

Những gì bạn đang gặp phải được gọi là " Sự không phù hợp đối tượng / Trở ngại quan hệ " , những khó khăn kỹ thuật phát sinh từ thực tế là mô hình dữ liệu hướng đối tượng và mô hình dữ liệu quan hệ khác nhau về cơ bản theo nhiều cách. LINQ và các khung công tác khác (được gọi là ORM, Object / Relative Mappers, không phải ngẫu nhiên,) không kỳ diệu "vượt qua điều này;" họ chỉ đưa ra các truy vấn khác nhau. Nó cũng có thể được thực hiện trong SQL. Đây là cách tôi làm:

SELECT * FROM users user where [criteria here]

Lặp lại danh sách người dùng và lập danh sách ID.

SELECT * from EMAILS where user_id in (list of IDs here)
SELECT * from PHONES where user_id in (list of IDs here)

Và sau đó bạn làm phía khách hàng tham gia. Đây là cách LINQ và các khung công tác khác làm điều đó. Không có phép thuật thực sự liên quan; chỉ là một lớp trừu tượng.


14
+1 cho "chính xác những gì bạn yêu cầu". Quá thường xuyên, chúng ta nhảy vào kết luận rằng có một cái gì đó sai với công nghệ hơn là kết luận rằng chúng ta cần học cách sử dụng công nghệ một cách hiệu quả.
Matt

1
Hibernate sẽ truy xuất thực thể gốc và các bộ sưu tập nhất định trong một truy vấn duy nhất khi chế độ tìm nạp háo hức được sử dụng cho các bộ sưu tập đó; trong trường hợp đó, nó làm giảm các thuộc tính thực thể gốc trong bộ nhớ. Các ORM khác có thể có khả năng làm tương tự.
Mike Partridge

3
Trên thực tế điều này không phải là để đổ lỗi cho mô hình quan hệ. Nó đối phó rất độc đáo với các mối quan hệ lồng nhau cảm ơn bạn. Đây hoàn toàn là một lỗi triển khai trong các phiên bản đầu tiên của SQL. Tôi nghĩ rằng các phiên bản gần đây đã thêm nó mặc dù.
John Nilsson

8
Bạn có chắc đây là một ví dụ về trở kháng quan hệ đối tượng? Dường như với tôi rằng mô hình quan hệ hoàn toàn khớp với mô hình dữ liệu khái niệm của OP: mỗi người dùng được liên kết với một danh sách 0, một hoặc nhiều địa chỉ email. Mô hình đó cũng hoàn toàn có thể sử dụng được trong mô hình OO (tổng hợp: đối tượng người dùng có một bộ sưu tập email). Hạn chế là trong kỹ thuật đang được sử dụng để truy vấn cơ sở dữ liệu, đây là một chi tiết triển khai. Có các kỹ thuật truy vấn xung quanh để trả về dữ liệu theo kiểu bá đạo, ví dụ: DataSets theo kiểu bá đạo trong .Net
MarkJ

@MarkJ bạn nên viết nó lên như một câu trả lời.
Mr.Mindor

12

Bạn có thể sử dụng một hàm dựng sẵn để ghép các bản ghi lại với nhau. Trong MySQL bạn có thể sử dụng GROUP_CONCAT()hàm và trong Oracle bạn có thể sử dụng LISTAGG()hàm.

Đây là một ví dụ về một truy vấn có thể trông như thế nào trong MySQL:

SELECT user.*, 
    (SELECT GROUP_CONCAT(DISTINCT emailAddy) FROM emails email WHERE email.user_id = user.id
    ) AS EmailAddresses,
    (SELECT GROUP_CONCAT(DISTINCT phoneNumber) FROM phones phone WHERE phone.user_id = user.id
    ) AS PhoneNumbers
FROM users user 

Điều này sẽ trả lại một cái gì đó như

username    department       EmailAddresses                        PhoneNumbers
Tim_Burton  Human Resources  hr@m.com, tb@me.com, nunya@what.com   231-123-1234, 231-123-1235

Đây dường như là giải pháp gần nhất (trong SQL) cho những gì OP đang cố gắng thực hiện. Anh ta có khả năng vẫn phải xử lý phía máy khách để chia kết quả EmailAddresses và PhoneNumbers thành danh sách.
Mr.Mindor

2
Nếu số điện thoại có "loại", như "Di động", "Nhà" hoặc "Công việc" thì sao? Hơn nữa, dấu phẩy được cho phép về mặt kỹ thuật trong các địa chỉ email (nếu chúng được trích dẫn) - sau đó tôi sẽ chia nó như thế nào?
mpen

10

Vấn đề với điều này là nó trả về tên người dùng, DOB, màu yêu thích và tất cả các thông tin khác được lưu trữ

Vấn đề là bạn không đủ chọn lọc. Bạn yêu cầu mọi thứ khi bạn nói

Select * from...

... Và bạn đã có nó (bao gồm DOB và màu sắc yêu thích).

Có lẽ bạn nên thêm một chút (ahem) ... chọn lọc, và nói một cái gì đó như:

select users.name, emails.email_address, phones.home_phone, phones.bus_phone
from...

Cũng có thể bạn có thể thấy các bản ghi trông giống như bản sao vì usercó thể tham gia vào nhiều emailbản ghi, nhưng trường phân biệt hai bản ghi này không có trong Selecttuyên bố của bạn , vì vậy bạn có thể muốn nói điều gì đó như

select distinct users.name, emails.email_address, phones.home_phone, phones.bus_phone
from...

... lặp đi lặp lại nhiều lần cho mỗi bản ghi ...

Ngoài ra, tôi nhận thấy bạn đang làm a LEFT JOIN. Điều này sẽ nối tất cả các bản ghi ở bên trái của phép nối (nghĩa là users) cho tất cả các bản ghi ở bên phải hoặc nói cách khác:

Một kết nối bên ngoài bên trái trả về tất cả các giá trị từ một tham gia bên trong cộng với tất cả các giá trị trong bảng bên trái không khớp với bảng bên phải.

( http://en.wikipedia.org/wiki/Join_(SQL)#Left_outer_join )

Vì vậy, một câu hỏi khác là bạn thực sự cần một tham gia trái, hoặc sẽ INNER JOINlà đủ? Họ là những loại tham gia rất khác nhau.

Sẽ không đẹp hơn nếu nó trả về một hàng cho mỗi người dùng và trong bản ghi đó có một danh sách các email

Nếu bạn thực sự muốn một cột duy nhất trong tập kết quả có chứa một danh sách được tạo nhanh chóng, điều đó có thể được thực hiện nhưng nó khác nhau tùy thuộc vào cơ sở dữ liệu bạn đang sử dụng. Oracle có listaggchức năng .


Cuối cùng, tôi nghĩ rằng vấn đề của bạn có thể được giải quyết nếu bạn viết lại truy vấn của mình gần giống như thế này:

select distinct users.name, users.id, emails.email_address, phones.phone_number
from users
  inner join emails on users.user_id = emails.user_id
  inner join phones on users.user_id = phones.user_id

1
sử dụng * không được khuyến khích nhưng không phải là mấu chốt của vấn đề. Ngay cả khi anh ta chọn 0 cột người dùng, anh ta vẫn có thể gặp hiệu ứng trùng lặp vì cả Điện thoại và Email đều có mối quan hệ 1-nhiều với Người dùng. Khác biệt sẽ không ngăn một số điện thoại xuất hiện hai lần ala phone1/name@hotmail.com, phone1/name@google.com.
mike30

6
-1: "vấn đề của bạn có thể được giải quyết" nói rằng bạn không biết sự thay đổi từ left jointhành inner join. Trong trường hợp này, điều này sẽ không làm giảm "sự lặp lại" mà người dùng đang phàn nàn; nó chỉ đơn giản là bỏ qua những người dùng thiếu điện thoại hoặc email. hầu như không cải thiện. đồng thời, khi diễn giải "tất cả các bản ghi bên trái cho tất cả các bản ghi bên phải" bỏ qua các ONtiêu chí, điều này sẽ cắt xén tất cả các quan hệ 'sai' vốn có trong sản phẩm của Cartesian nhưng vẫn giữ tất cả các trường lặp lại.
Javier

@Javier: Vâng, đó là lý do tại sao tôi cũng nói rằng bạn thực sự cần tham gia trái, hoặc một INNER THAM GIA đã đủ? * Mô tả của OP về vấn đề này khiến nó * nghe như thể họ đang mong đợi kết quả của một sự tham gia bên trong. Tất nhiên, không có bất kỳ dữ liệu mẫu hoặc mô tả nào về những gì họ thực sự muốn, thật khó để nói. Tôi đã đưa ra đề nghị bởi vì tôi thực sự đã thấy những người (những người tôi làm việc cùng) làm điều này: chọn tham gia sai và sau đó phàn nàn khi họ không hiểu kết quả họ nhận được. Nhìn thấy nó, tôi nghĩ nó có thể đã xảy ra ở đây.
Thất vọngWithFormsDesigner

3
Bạn đang thiếu điểm của câu hỏi. Trong ví dụ giả thuyết này, tôi muốn tất cả dữ liệu người dùng (tên, dob, v.v.) tôi muốn tất cả số điện thoại của anh ấy / cô ấy. Một kết nối bên trong loại trừ người dùng không có email hoặc không có điện thoại - điều đó giúp ích như thế nào?
mở

4

Các truy vấn luôn tạo ra một tập hợp dữ liệu dạng bảng hình chữ nhật (không bị lởm chởm). Không có bộ phụ lồng nhau trong một bộ. Trong thế giới của tập hợp, mọi thứ là một hình chữ nhật không lồng nhau.

Bạn có thể nghĩ về việc tham gia như đặt 2 bộ cạnh nhau. Điều kiện "bật" là cách các bản ghi trong mỗi bộ được khớp với nhau. Nếu người dùng có 3 số điện thoại, thì bạn sẽ thấy sự trùng lặp 3 lần trong thông tin người dùng. Một bộ hình chữ nhật không răng cưa phải được tạo bởi truy vấn. Đó đơn giản là bản chất của việc tham gia các bộ với mối quan hệ 1-nhiều.

Để có được những gì bạn muốn, bạn phải sử dụng một truy vấn riêng như Mason Wheeler được mô tả.

select * from Phones where user_id=344;

Kết quả của truy vấn này vẫn là một tập hợp hình chữ nhật không có răng cưa. Như là tất cả mọi thứ trong thế giới của bộ.


2

Bạn phải quyết định nơi tắc nghẽn tồn tại. Băng thông giữa cơ sở dữ liệu và ứng dụng của bạn thường khá nhanh. Không có lý do gì hầu hết các cơ sở dữ liệu không thể trả lại 3 bộ dữ liệu riêng biệt trong một cuộc gọi và không tham gia. Sau đó, bạn có thể tham gia tất cả cùng nhau trong ứng dụng của mình nếu bạn muốn.

Mặt khác, bạn muốn cơ sở dữ liệu đặt tập dữ liệu này lại với nhau và sau đó xóa tất cả các giá trị lặp lại trong mỗi hàng là kết quả của các phép nối và không nhất thiết là các hàng có dữ liệu trùng lặp như hai người có cùng tên hoặc số điện thoại. Có vẻ như rất nhiều đầu để tiết kiệm băng thông. Bạn nên tập trung vào việc trả lại ít dữ liệu hơn bằng cách lọc và loại bỏ các cột bạn không cần tốt hơn. Bởi vì Chọn * không bao giờ được sử dụng trong sản xuất - điều đó phụ thuộc.


"Không có lý do gì hầu hết các cơ sở dữ liệu không thể trả về 3 bộ dữ liệu riêng biệt trong một cuộc gọi và không tham gia" - Làm thế nào để bạn có được nó để trả lại 3 bộ dữ liệu riêng biệt với một cuộc gọi? Tôi nghĩ bạn phải gửi 3 truy vấn khác nhau, trong đó giới thiệu độ trễ giữa mỗi truy vấn?
mở

Một thủ tục được lưu trữ có thể được gọi trong 1 giao dịch, và sau đó trả lại nhiều bộ dữ liệu như bạn muốn. Có thể cần một sproc "SelectUserWithEmailsPhones".
Graham

1
@Mark: bạn có thể gửi (ít nhất là trong máy chủ sql) nhiều hơn một lệnh tại cùng một đợt. cmdText = "select * from b; select * from a; select * from c" và sau đó sử dụng nó làm văn bản lệnh cho sqlcommand.
jmoreno

2

Rất đơn giản, không tham gia dữ liệu của bạn nếu bạn muốn có kết quả khác biệt cho truy vấn người dùng và truy vấn số điện thoại, nếu không, như những người khác đã chỉ ra "Đặt" hoặc dữ liệu sẽ chứa các trường bổ sung cho mỗi hàng.

Phát hành 2 truy vấn riêng biệt thay vì một truy vấn.

Trong thủ tục được lưu trữ hoặc truy vấn sql craft 2 tham số nội tuyến và trả về kết quả của cả hai trở lại. Hầu hết các cơ sở dữ liệu và ngôn ngữ hỗ trợ nhiều bộ kết quả.

Ví dụ: SQL Server và C # thực hiện chức năng này bằng cách sử dụng IDataReader.NextResult().


1

Bạn đang thiếu một cái gì đó. Nếu bạn muốn không chuẩn hóa dữ liệu của mình, bạn phải tự làm điều đó.

;with toList as (
    select  *, Stuff(( select ',' + (phone.phoneType + ':' + phone.PhoneNumber) 
                    from phones phone
                    where phone.user_id = user.user_id
                    for xml path('')
                  ), 1,1,'') as phoneNumbers
from users user
)
select *
from toList

1

Khái niệm về đóng cửa quan hệ về cơ bản có nghĩa là kết quả của bất kỳ truy vấn nào là mối quan hệ có thể được sử dụng trong các truy vấn khác như thể đó là một bảng cơ sở. Đây là một khái niệm mạnh mẽ vì nó làm cho các truy vấn có thể kết hợp được.

Nếu SQL cho phép bạn viết các truy vấn đầu ra cấu trúc dữ liệu lồng nhau, bạn sẽ phá vỡ nguyên tắc này. Cấu trúc dữ liệu lồng nhau không phải là một mối quan hệ, vì vậy bạn sẽ cần một ngôn ngữ truy vấn mới hoặc các phần mở rộng phức tạp cho SQL, để truy vấn thêm hoặc tham gia vào nó mà quan hệ khác.

Về cơ bản, bạn sẽ xây dựng một DBMS phân cấp trên đầu trang của một DBMS quan hệ. Nó sẽ phức tạp hơn nhiều đối với một lợi ích đáng ngờ, và bạn mất đi những lợi thế của một hệ thống quan hệ nhất quán.

Tôi hiểu tại sao đôi khi có thể thuận tiện để có thể xuất dữ liệu có cấu trúc phân cấp từ SQL, nhưng chi phí trong sự phức tạp được thêm vào trong DBMS để hỗ trợ điều này chắc chắn không đáng.


-4

Xin tham khảo cách sử dụng hàm STUFF, nhóm nhiều hàng (số điện thoại) của một cột (số liên lạc) có thể được trích xuất dưới dạng một ô gồm các giá trị được phân tách của một hàng (người dùng).

Ngày nay chúng ta sử dụng rộng rãi điều này nhưng phải đối mặt với một số vấn đề về CPU và hiệu năng cao. Kiểu dữ liệu XML là một tùy chọn khác nhưng là một thay đổi thiết kế không phải là mức truy vấn.


5
Vui lòng mở rộng về cách giải quyết câu hỏi này. Thay vì nói "Xin vui lòng đề cập đến việc sử dụng", hãy cung cấp một ví dụ về cách điều này sẽ đạt được câu hỏi được hỏi. Nó cũng có thể hữu ích để trích dẫn các nguồn của bên thứ 3, nơi nó làm cho mọi thứ rõ ràng hơn.
bitoflogic

1
Hình như STUFFlà giống như mối nối. Không chắc làm thế nào điều đó áp dụng cho câu hỏi của tôi.
mpen
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.