Làm thế nào để thực hiện một FULL OUTER THAM GIA trong MySQL?


654

Tôi muốn tham gia đầy đủ bên ngoài Tham gia vào MySQL. Điều này có thể không? Là một tham gia đầy đủ bên ngoài được hỗ trợ bởi MySQL?



4
Câu hỏi này có câu trả lời tốt hơn
Julio Marins

Coi chừng những câu trả lời ở đây. Tiêu chuẩn SQL cho biết tham gia đầy đủ là tham gia bên trong trên các hàng liên kết tất cả các hàng của bảng bên trái chưa được so sánh được mở rộng bằng liên kết null tất cả các hàng của bảng bên phải được mở rộng bằng null. Hầu hết các câu trả lời ở đây đều sai (xem các bình luận) & những câu trả lời không sai không xử lý trường hợp chung. Mặc dù có rất nhiều upvote (không chính đáng). (Xem câu trả lời của tôi.)
philipxy

Còn khi bạn đang cố gắng tham gia bằng các khóa không chính / cột được nhóm thì sao? như tôi có một truy vấn bán cho mỗi trạng thái "trạng thái", "bán" và một chi phí khác cho mỗi trạng thái "trạng thái", "chi phí", cả hai truy vấn đều sử dụng nhóm theo ("trạng thái"). Khi tôi thực hiện liên kết giữa bên trái và bên phải tham gia giữa hai truy vấn, tôi nhận được một vài hàng có bán nhưng không có chi phí, thêm một số chi phí nhưng không bán, mọi thứ đều đúng cho đến thời điểm này, nhưng tôi cũng nhận được một vài với cả hai bán và chi phí và một cột "trạng thái" lặp đi lặp lại ... không có vấn đề gì nhiều nhưng không cảm thấy đúng ...
Jairo Lozano

1
@JairoLozano Các ràng buộc không cần thiết để truy vấn. Mặc dù khi các ràng buộc giữ các truy vấn bổ sung trả về câu trả lời mong muốn nếu không sẽ không có. Các ràng buộc không ảnh hưởng đến những gì tham gia đầy đủ vào lợi nhuận cho các đối số đã cho. Vấn đề bạn mô tả là truy vấn bạn đã viết là truy vấn sai. . .)
philipxy

Câu trả lời:


668

Bạn không có FULL THAM GIA trên MySQL, nhưng bạn có thể chắc chắn mô phỏng chúng .

Đối với một mã SAMPLE được sao chép từ câu hỏi SO này, bạn có:

với hai bảng t1, t2:

SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
UNION
SELECT * FROM t1
RIGHT JOIN t2 ON t1.id = t2.id

Truy vấn trên hoạt động đối với các trường hợp đặc biệt trong đó thao tác FULL OUTER THAM GIA sẽ không tạo ra bất kỳ hàng trùng lặp nào. Truy vấn trên phụ thuộc vào UNIONtoán tử tập hợp để loại bỏ các hàng trùng lặp được giới thiệu bởi mẫu truy vấn. Chúng tôi có thể tránh giới thiệu các hàng trùng lặp bằng cách sử dụng mẫu chống tham gia cho truy vấn thứ hai và sau đó sử dụng toán tử UNION ALL để kết hợp hai bộ. Trong trường hợp tổng quát hơn, trong đó FULL OUTER THAM GIA sẽ trả về các hàng trùng lặp, chúng ta có thể làm điều này:

SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
UNION ALL
SELECT * FROM t1
RIGHT JOIN t2 ON t1.id = t2.id
WHERE t1.id IS NULL

33
Thật ra điều bạn viết không đúng. Bởi vì khi bạn thực hiện UNION, bạn sẽ loại bỏ các bản sao và đôi khi khi bạn tham gia hai bảng khác nhau, sẽ có các bản sao.
Pavle Lekic

158
Đây là ví dụ chính xác:(SELECT ... FROM tbl1 LEFT JOIN tbl2 ...) UNION ALL (SELECT ... FROM tbl1 RIGHT JOIN tbl2 ... WHERE tbl1.col IS NULL)
Pavle Lekic

8
Vì vậy, sự khác biệt là tôi đang tham gia bao gồm bên trái và sau đó độc quyền bằng cách sử dụng UNION ALL
Pavle Lekic

5
và tôi thấy bây giờ bạn nói rằng chính mình, xin lỗi. Có lẽ bạn có thể cập nhật câu trả lời của mình, trong trường hợp này có sai và UNION ALL sẽ luôn hiệu quả hơn?
ysth

10
@ypercube: Nếu không có hàng trùng lặp trong t1t2, truy vấn trong câu trả lời này sẽ trả về một tập kết quả mô phỏng FULL OUTER THAM GIA. Nhưng trong trường hợp tổng quát hơn, ví dụ, danh sách CHỌN không chứa đủ các cột / biểu thức để làm cho các hàng được trả về là duy nhất, thì mẫu truy vấn này không đủ để tạo lại tập hợp sẽ được tạo bởi a FULL OUTER JOIN. Để có được một mô phỏng trung thực hơn, chúng ta cần một UNION ALLtoán tử được thiết lập và một trong các truy vấn sẽ cần một mẫu chống tham gia . Nhận xét từ Pavle Lekic (ở trên) đưa ra mẫu truy vấn chính xác .
spencer7593

350

Câu trả lời mà Pablo Santa Cruz đưa ra là chính xác; tuy nhiên, trong trường hợp bất kỳ ai vấp ngã trên trang này và muốn làm rõ hơn, đây là một sự cố chi tiết.

Bảng ví dụ

Giả sử chúng ta có các bảng sau:

-- t1
id  name
1   Tim
2   Marta

-- t2
id  name
1   Tim
3   Katarina

Tham gia nội bộ

Một tham gia bên trong, như thế này:

SELECT *
FROM `t1`
INNER JOIN `t2` ON `t1`.`id` = `t2`.`id`;

Sẽ chỉ cho chúng tôi các bản ghi xuất hiện trong cả hai bảng, như thế này:

1 Tim  1 Tim

Các liên kết bên trong không có hướng (như trái hoặc phải) vì chúng rõ ràng là hai chiều - chúng tôi yêu cầu một trận đấu ở cả hai bên.

Tham gia bên ngoài

Mặt khác, các phép nối ngoài là để tìm các bản ghi có thể không khớp trong bảng khác. Như vậy, bạn phải chỉ định phía nào của phép nối được phép có một bản ghi bị thiếu.

LEFT JOINRIGHT JOINlà tốc ký cho LEFT OUTER JOINRIGHT OUTER JOIN; Tôi sẽ sử dụng tên đầy đủ của họ dưới đây để củng cố khái niệm về các phép nối bên ngoài so với các phép nối bên trong.

Bên trái tham gia

Một tham gia bên ngoài bên trái, như thế này:

SELECT *
FROM `t1`
LEFT OUTER JOIN `t2` ON `t1`.`id` = `t2`.`id`;

... sẽ giúp chúng tôi có tất cả các bản ghi từ bảng bên trái bất kể họ có trận đấu ở bảng bên phải hay không, như sau:

1 Tim   1    Tim
2 Marta NULL NULL

Bên phải tham gia

Một tham gia bên ngoài bên phải, như thế này:

SELECT *
FROM `t1`
RIGHT OUTER JOIN `t2` ON `t1`.`id` = `t2`.`id`;

... sẽ giúp chúng tôi có tất cả các hồ sơ từ bảng bên phải bất kể họ có trận đấu ở bảng bên trái hay không, như thế này:

1    Tim   1  Tim
NULL NULL  3  Katarina

Tham gia đầy đủ bên ngoài

Một kết nối bên ngoài đầy đủ sẽ cung cấp cho chúng tôi tất cả các bản ghi từ cả hai bảng, cho dù chúng có khớp trong bảng kia hay không, với NULL ở cả hai bên không có kết quả khớp. Kết quả sẽ như thế này:

1    Tim   1    Tim
2    Marta NULL NULL
NULL NULL  3    Katarina

Tuy nhiên, như Pablo Santa Cruz đã chỉ ra, MySQL không hỗ trợ điều này. Chúng ta có thể mô phỏng nó bằng cách thực hiện UNION của một liên kết bên trái và một tham gia bên phải, như thế này:

SELECT *
FROM `t1`
LEFT OUTER JOIN `t2` ON `t1`.`id` = `t2`.`id`

UNION

SELECT *
FROM `t1`
RIGHT OUTER JOIN `t2` ON `t1`.`id` = `t2`.`id`;

Bạn có thể nghĩ về một UNIONý nghĩa "chạy cả hai truy vấn này, sau đó xếp kết quả lên nhau"; một số hàng sẽ đến từ truy vấn đầu tiên và một số từ truy vấn thứ hai.

Cần lưu ý rằng một UNIONtrong MySQL sẽ loại bỏ các bản sao chính xác: Tim sẽ xuất hiện trong cả hai truy vấn ở đây, nhưng kết quả của việc UNIONchỉ liệt kê anh ta một lần. Đồng nghiệp guru cơ sở dữ liệu của tôi cảm thấy rằng hành vi này không nên được dựa vào. Vì vậy, để rõ ràng hơn về nó, chúng ta có thể thêm một WHEREmệnh đề vào truy vấn thứ hai:

SELECT *
FROM `t1`
LEFT OUTER JOIN `t2` ON `t1`.`id` = `t2`.`id`

UNION

SELECT *
FROM `t1`
RIGHT OUTER JOIN `t2` ON `t1`.`id` = `t2`.`id`
WHERE `t1`.`id` IS NULL;

Mặt khác, nếu bạn muốn xem các bản sao vì một số lý do, bạn có thể sử dụng UNION ALL.


12
Câu trả lời này là hơn một năm cũ, nhưng nó chỉ ra rằng ông Atwood đã có một câu trả lời tốt hơn trên blog của mình trong năm 2007: codinghorror.com/blog/2007/10/...
Nathan dài

4
Đối với MySQL, bạn thực sự muốn tránh sử dụng UNION thay vì UNION ALL nếu không có sự trùng lặp (xem bình luận của Pavle ở trên). Nếu bạn có thể thêm một số thông tin vào hiệu ứng đó trong câu trả lời của bạn ở đây, tôi nghĩ đó là câu trả lời ưa thích cho câu hỏi này vì nó kỹ lưỡng hơn.
Garen

2
Khuyến nghị từ "đồng nghiệp guru cơ sở dữ liệu" là chính xác. Về mặt mô hình quan hệ (tất cả các công việc lý thuyết được thực hiện bởi Ted Codd và Chris Date), một truy vấn của mẫu cuối cùng mô phỏng FULL OUTER THAM GIA, bởi vì nó kết hợp hai bộ riêng biệt, Truy vấn thứ hai không giới thiệu "trùng lặp" ( các hàng đã được trả về bởi truy vấn đầu tiên) sẽ không được tạo bởi a FULL OUTER JOIN. Không có gì sai khi thực hiện các truy vấn theo cách đó và sử dụng UNION để xóa các bản sao đó. Nhưng để thực sự sao chép a FULL OUTER JOIN, chúng ta cần một trong các truy vấn là chống tham gia.
spencer7593

1
@IstiaqueAhmed: mục tiêu là mô phỏng hoạt động FULL OUTER THAM GIA. Chúng tôi cần điều kiện đó trong truy vấn thứ hai để nó chỉ trả về các hàng không khớp (mẫu chống tham gia.). Không có điều kiện đó, truy vấn là một phép nối ngoài ... nó trả về các hàng khớp với các hàng không khớp. Và các hàng khớp đã được trả về bởi truy vấn đầu tiên. Nếu truy vấn thứ hai trả về cùng các hàng đó (một lần nữa), chúng tôi đã nhân đôi các hàng và kết quả của chúng tôi sẽ không tương đương với FULL OUTER THAM GIA.
spencer7593

1
@IstiaqueAhmed: Đúng là một UNIONthao tác sẽ loại bỏ các bản sao đó; nhưng nó cũng loại bỏ TẤT CẢ các hàng trùng lặp, bao gồm các hàng trùng lặp sẽ được trả về bởi FULL OUTER THAM GIA. Để mô phỏng a FULL JOIN b, mô hình chính xác là (a LEFT JOIN b) UNION ALL (b ANTI JOIN a).
spencer7593

35

Sử dụng uniontruy vấn sẽ loại bỏ các bản sao và điều này khác với hành vi full outer joinkhông bao giờ xóa bất kỳ bản sao nào:

[Table: t1]                            [Table: t2]
value                                  value
-------                                -------
1                                      1
2                                      2
4                                      2
4                                      5

Đây là kết quả mong đợi của full outer join:

value | value
------+-------
1     | 1
2     | 2
2     | 2
Null  | 5
4     | Null
4     | Null

Đây là kết quả của việc sử dụng leftright Joinvới union:

value | value
------+-------
Null  | 5 
1     | 1
2     | 2
4     | Null

[SQL Fiddle]

Truy vấn đề xuất của tôi là:

select 
    t1.value, t2.value
from t1 
left outer join t2  
  on t1.value = t2.value
union all      -- Using `union all` instead of `union`
select 
    t1.value, t2.value
from t2 
left outer join t1 
  on t1.value = t2.value
where 
    t1.value IS NULL 

Kết quả của truy vấn trên giống như kết quả mong đợi:

value | value
------+-------
1     | 1
2     | 2
2     | 2
4     | NULL
4     | NULL
NULL  | 5

[SQL Fiddle]


@Steve Chambers : [Từ ý kiến, với nhiều lời cảm ơn!]
Lưu ý: Đây có thể là giải pháp tốt nhất, cả về hiệu quả và tạo ra kết quả tương tự như a FULL OUTER JOIN. Bài đăng trên blog này cũng giải thích rất rõ - trích dẫn từ Phương pháp 2: "Điều này xử lý các hàng trùng lặp chính xác và không bao gồm bất cứ điều gì không nên. Nó cần thiết để sử dụng UNION ALLthay vì đơn giản UNION, sẽ loại bỏ các bản sao tôi muốn giữ. có thể hiệu quả hơn đáng kể trên các tập kết quả lớn, vì không cần phải sắp xếp và loại bỏ các bản sao. "


Tôi quyết định thêm một giải pháp khác đến từ full outer jointrực quan hóa và toán học, nó không tốt hơn ở trên nhưng dễ đọc hơn:

Tham gia đầy đủ bên ngoài có nghĩa là (t1 ∪ t2): tất cả trong t1hoặc trong t2
(t1 ∪ t2) = (t1 ∩ t2) + t1_only + t2_only: tất cả trong cả hai t1t2cộng với tất cả trong t1đó không có trong t2và cộng với tất cả trong t2đó không có trong t1:

-- (t1 ∩ t2): all in both t1 and t2
select t1.value, t2.value
from t1 join t2 on t1.value = t2.value    
union all  -- And plus 
-- all in t1 that not exists in t2
select t1.value, null
from t1
where not exists( select 1 from t2 where t2.value = t1.value)    
union all  -- and plus
-- all in t2 that not exists in t1
select null, t2.value
from t2
where not exists( select 1 from t1 where t2.value = t1.value)

[SQL Fiddle]


Chúng tôi đang thực hiện cùng một thời gian kéo nhiệm vụ, Nếu có truy vấn phụ cho t1 và t2 thì mysql phải thực hiện cùng một nhiệm vụ nhiều lần hơn, phải không? Chúng ta có thể loại bỏ điều này bằng cách sử dụng bí danh trong tình huống này không ?:
Kabir Hossain

Tôi đề nghị bạn sử dụng một số bảng tạm thời;).
shA.t

5
Phương pháp này dường như là giải pháp tốt nhất, cả về hiệu quả và tạo ra kết quả tương tự như a FULL OUTER JOIN. Bài đăng trên blog này cũng giải thích rất rõ - trích dẫn từ Phương pháp 2: "Điều này xử lý các hàng trùng lặp chính xác và không bao gồm bất cứ điều gì không nên. Cần sử dụng UNION ALL thay vì UNION đơn giản, loại bỏ các trùng lặp tôi muốn giữ lại. Điều này có thể hiệu quả hơn đáng kể trên các tập kết quả lớn, vì không cần phải sắp xếp và loại bỏ các bản sao. "
Steve Chambers

2
@SteveChambers đã quá muộn, nhưng cảm ơn vì nhận xét của bạn. Tôi đã thêm nhận xét của bạn để sau đó trả lời đánh dấu thêm, Nếu bạn không đồng ý, vui lòng cuộn lại;).
shA.t

Không có vấn đề gì @ shA.t - IMO điều này thực sự cần có nhiều upvote hơn và / hoặc là câu trả lời được chấp nhận.
Steve Chambers

6

MySql không có cú pháp FULL-OUTER-THAM GIA. Bạn phải mô phỏng bằng cách thực hiện cả TRÁI PHẢI và THAM GIA ĐÚNG như sau-

SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id  
UNION
SELECT * FROM t1
RIGHT JOIN t2 ON t1.id = t2.id

Nhưng MySql cũng không có cú pháp RIGHT THAM GIA. Theo đơn giản hóa kết nối ngoài của MySql , phép nối bên phải được chuyển đổi thành phép nối trái tương đương bằng cách chuyển t1 và t2 trong mệnh đề FROMand ONtrong truy vấn. Do đó, Trình tối ưu hóa truy vấn MySql dịch truy vấn ban đầu thành sau -

SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id  
UNION
SELECT * FROM t2
LEFT JOIN t1 ON t2.id = t1.id

Bây giờ, không có hại khi viết truy vấn ban đầu, nhưng hãy nói nếu bạn có các vị từ như mệnh đề WHERE, đó là một vị từ trước khi tham gia hoặc một vị từ AND trên ONmệnh đề, đó là một vị từ trong quá trình tham gia , thì bạn có thể muốn nhìn vào quỷ dữ; đó là chi tiết.

Trình tối ưu hóa truy vấn MySql thường xuyên kiểm tra các vị từ nếu chúng bị từ chối . Định nghĩa và ví dụ từ chối Null Bây giờ, nếu bạn đã thực hiện RIGHT THAM GIA, nhưng với vị từ WHERE trên cột từ t1, thì bạn có thể gặp rủi ro khi chạy vào một kịch bản bị từ chối .

Ví dụ: truy vấn sau đây -

SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
WHERE t1.col1 = 'someValue'
UNION
SELECT * FROM t1
RIGHT JOIN t2 ON t1.id = t2.id
WHERE t1.col1 = 'someValue'

được dịch sang phần sau bởi Trình tối ưu hóa truy vấn-

SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
WHERE t1.col1 = 'someValue'
UNION
SELECT * FROM t2
LEFT JOIN t1 ON t2.id = t1.id
WHERE t1.col1 = 'someValue'

Vì vậy, thứ tự của các bảng đã thay đổi, nhưng vị từ vẫn được áp dụng cho t1, nhưng t1 hiện nằm trong mệnh đề 'ON'. Nếu t1.col1 được định nghĩa là NOT NULL cột, thì truy vấn này sẽ bị từ chối .

Bất kỳ tham gia ngoài nào (trái, phải, đầy đủ) bị từ chối null đều được MySql chuyển đổi thành tham gia bên trong.

Do đó, kết quả mà bạn có thể mong đợi có thể hoàn toàn khác với những gì MySql đang trả về. Bạn có thể nghĩ rằng đó là một lỗi với RIGHT THAM GIA của MySql, nhưng điều đó không đúng. Nó chỉ là cách trình tối ưu hóa truy vấn MySql hoạt động. Vì vậy, nhà phát triển phụ trách phải chú ý đến những sắc thái này khi anh ta đang xây dựng truy vấn.


4

Trong SQLite, bạn nên làm điều này:

SELECT * 
FROM leftTable lt 
LEFT JOIN rightTable rt ON lt.id = rt.lrid 
UNION
SELECT lt.*, rl.*  -- To match column set
FROM rightTable rt 
LEFT JOIN  leftTable lt ON lt.id = rt.lrid

Chúng ta có thể sử dụng nó? như: CHỌN * TỪ leftTable lt TRÁI THAM GIA bên phải rt ON lt.id = rt.lrid UNION CHỌN lt. *, rl. * - Để khớp với cột được đặt TỪ leftTable lt RIGHT THAM GIA rightTable rt ON lt.id = rt.lrid ;
Kabir Hossain

có nhưng SQLite không hỗ trợ quyền tham gia nhưng có trong MYSQL có
Rami Jamleh

4

Không có câu trả lời nào ở trên là thực sự chính xác, vì chúng không tuân theo ngữ nghĩa khi có các giá trị trùng lặp.

Đối với một truy vấn, chẳng hạn như (từ bản sao này ):

SELECT * FROM t1 FULL OUTER JOIN t2 ON t1.Name = t2.Name;

Tương đương chính xác là:

SELECT t1.*, t2.*
FROM (SELECT name FROM t1 UNION  -- This is intentionally UNION to remove duplicates
      SELECT name FROM t2
     ) n LEFT JOIN
     t1
     ON t1.name = n.name LEFT JOIN
     t2
     ON t2.name = n.name;

Nếu bạn cần điều này để làm việc với NULLcác giá trị (cũng có thể cần thiết), thì hãy sử dụng NULLtoán tử so sánh an toàn, <=>thay vì =.


3
đây thường là một giải pháp tốt, nhưng nó có thể cho kết quả khác với FULL OUTER JOINbất cứ khi nào namecột không có giá trị. Các union alltruy vấn với-tham gia chống mẫu nên tái tạo bên ngoài tham gia hành vi một cách chính xác, nhưng mà giải pháp là hơn thích hợp phụ thuộc vào bối cảnh và những hạn chế đang hoạt động trên các bảng.
fthiella

@fthiella. . . Đó là một điểm tốt. Tôi điều chỉnh câu trả lời.
Gordon Linoff

1
không sao, nhưng toán tử so sánh null an toàn sẽ làm cho phép nối thành công, khác với hành vi nối ngoài đầy đủ trong trường hợp bạn có tên null cả trong t1 và trong t2
fthiella

@fthiella. . . Tôi sẽ phải suy nghĩ về cách tốt nhất để làm điều này. Nhưng được đưa ra như thế nào sai câu trả lời được chấp nhận, hầu như bất cứ điều gì gần với câu trả lời đúng. (Câu trả lời đó chỉ sai nếu có nhiều khóa ở hai bên.)
Gordon Linoff

1
vâng, câu trả lời được chấp nhận là sai, như một giải pháp chung tôi nghĩ rằng nó đúng khi sử dụng union all, nhưng câu trả lời đó bỏ lỡ một mẫu chống tham gia trong truy vấn đầu tiên hoặc truy vấn thứ hai sẽ giữ các bản sao hiện có nhưng ngăn không cho thêm các câu hỏi mới. Tùy thuộc vào bối cảnh, các giải pháp khác (như giải pháp này) có thể phù hợp hơn.
fthiella

3

Truy vấn của shA.t đã sửa đổi để rõ ràng hơn:

-- t1 left join t2
SELECT t1.value, t2.value
FROM t1 LEFT JOIN t2 ON t1.value = t2.value   

    UNION ALL -- include duplicates

-- t1 right exclude join t2 (records found only in t2)
SELECT t1.value, t2.value
FROM t1 RIGHT JOIN t2 ON t1.value = t2.value
WHERE t2.value IS NULL 

3

Bạn có thể làm như sau:

(SELECT 
    *
FROM
    table1 t1
        LEFT JOIN
    table2 t2 ON t1.id = t2.id
WHERE
    t2.id IS NULL)
UNION ALL
 (SELECT 
    *
FROM
    table1 t1
        RIGHT JOIN
    table2 t2 ON t1.id = t2.id
WHERE
    t1.id IS NULL);

1

Bạn nói gì về giải pháp tham gia Cross ?

SELECT t1.*, t2.*
FROM table1 t1
INNER JOIN table2 t2 
ON 1=1;

2
Không, đây là một tham gia chéo. Nó sẽ khớp mọi hàng trong t1 với mọi hàng trong t2, mang lại tập hợp tất cả các kết hợp có thể, với select (select count(*) from t1) * (select count(*) from t2))các hàng trong tập kết quả.
Marc L.

Mặc dù mã này có thể trả lời câu hỏi, việc cung cấp ngữ cảnh bổ sung về cách thứclý do giải quyết vấn đề sẽ cải thiện giá trị lâu dài của câu trả lời.
Alexander

Sự bổ sung nào có thể hữu ích? có thể ví dụ?
Super Mario

0
SELECT
    a.name,
    b.title
FROM
    author AS a
LEFT JOIN
    book AS b
    ON a.id = b.author_id
UNION
SELECT
    a.name,
    b.title
FROM
    author AS a
RIGHT JOIN
    book AS b
    ON a.id = b.author_id

0

Cũng có thể, nhưng bạn phải đề cập đến cùng tên trường trong phần chọn.

SELECT t1.name, t2.name FROM t1
LEFT JOIN t2 ON t1.id = t2.id
UNION
SELECT t1.name, t2.name FROM t2
LEFT JOIN t1 ON t1.id = t2.id

Đây chỉ là trùng lặp kết quả từ một tham gia trái.
Matthew Đọc

-1

Tôi sửa phản hồi và các tác phẩm bao gồm tất cả các hàng (dựa trên phản hồi của Pavle Lekic)

    (
    SELECT a.* FROM tablea a
    LEFT JOIN tableb b ON a.`key` = b.key
    WHERE b.`key` is null
    )
    UNION ALL
    (
    SELECT a.* FROM tablea a
    LEFT JOIN tableb b ON a.`key` = b.key
    where  a.`key` = b.`key`
    )
    UNION ALL
    (
    SELECT b.* FROM tablea a
    right JOIN tableb b ON b.`key` = a.key
    WHERE a.`key` is null
    );

Không, đây là một loại tham gia "chỉ ngoài", sẽ chỉ trả về các hàng từ tableađó không có kết quả khớp tablebvà ngược lại. Các bạn cố gắng UNION ALL, sẽ chỉ hoạt động nếu hai bảng này có các cột được sắp xếp tương đương, không được đảm bảo.
Marc L.

nó hoạt động, tôi tạo trên tablea cơ sở dữ liệu tạm thời (1,2,3,4,5,6) và bảng (4,5,6,7,8,9) các hàng của nó có 3 cols "id", "number" và "name_number" dưới dạng văn bản và kết quả hoạt động chỉ có (1,2,3,7,8,9)
Rubén Ruíz

1
Đó không phải là một sự tham gia bên ngoài. Một tham gia bên ngoài cũng bao gồm các thành viên phù hợp.
Marc L.

câu mới đó có tất cả kết quả 1,2, ..., 9
Rubén Ruíz

-2

Câu trả lời:

SELECT * FROM t1 FULL OUTER JOIN t2 ON t1.id = t2.id;

Có thể được tạo lại như sau:

 SELECT t1.*, t2.* 
 FROM (SELECT * FROM t1 UNION SELECT name FROM t2) tmp
 LEFT JOIN t1 ON t1.id = tmp.id
 LEFT JOIN t2 ON t2.id = tmp.id;

Sử dụng câu trả lời UNION hoặc UNION ALL không bao gồm trường hợp cạnh trong đó các bảng cơ sở có các mục trùng lặp.

Giải trình:

Có một trường hợp cạnh mà UNION hoặc UNION ALL không thể bao gồm. Chúng tôi không thể kiểm tra điều này trên mysql vì nó không hỗ trợ FULL OUTER THAM GIA, nhưng chúng tôi có thể minh họa điều này trên cơ sở dữ liệu hỗ trợ nó:

 WITH cte_t1 AS
 (
       SELECT 1 AS id1
       UNION ALL SELECT 2
       UNION ALL SELECT 5
       UNION ALL SELECT 6
       UNION ALL SELECT 6
 ),
cte_t2 AS
(
      SELECT 3 AS id2
      UNION ALL SELECT 4
      UNION ALL SELECT 5
      UNION ALL SELECT 6
      UNION ALL SELECT 6
)
SELECT  *  FROM  cte_t1 t1 FULL OUTER JOIN cte_t2 t2 ON t1.id1 = t2.id2;

This gives us this answer:

id1  id2
1  NULL
2  NULL
NULL  3
NULL  4
5  5
6  6
6  6
6  6
6  6

Giải pháp của UNION:

SELECT  * FROM  cte_t1 t1 LEFT OUTER JOIN cte_t2 t2 ON t1.id1 = t2.id2
UNION    
SELECT  * FROM cte_t1 t1 RIGHT OUTER JOIN cte_t2 t2 ON t1.id1 = t2.id2

Đưa ra một câu trả lời không chính xác:

 id1  id2
NULL  3
NULL  4
1  NULL
2  NULL
5  5
6  6

Giải pháp UNION ALL:

SELECT  * FROM cte_t1 t1 LEFT OUTER join cte_t2 t2 ON t1.id1 = t2.id2
UNION ALL
SELECT  * FROM  cte_t1 t1 RIGHT OUTER JOIN cte_t2 t2 ON t1.id1 = t2.id2

Cũng không đúng.

id1  id2
1  NULL
2  NULL
5  5
6  6
6  6
6  6
6  6
NULL  3
NULL  4
5  5
6  6
6  6
6  6
6  6

Trong khi đó truy vấn này:

SELECT t1.*, t2.*
FROM (SELECT * FROM t1 UNION SELECT name FROM t2) tmp 
LEFT JOIN t1 ON t1.id = tmp.id 
LEFT JOIN t2 ON t2.id = tmp.id;

Cung cấp như sau:

id1  id2
1  NULL
2  NULL
NULL  3
NULL  4
5  5
6  6
6  6
6  6
6  6

Thứ tự là khác nhau, nhưng mặt khác phù hợp với câu trả lời chính xác.


Đó là dễ thương, nhưng trình bày sai UNION ALLgiải pháp. Ngoài ra, nó trình bày một giải pháp sử dụng UNIONsẽ chậm hơn trên các bảng nguồn lớn do việc sao chép được yêu cầu. Cuối cùng, nó sẽ không biên dịch, vì trường idkhông tồn tại trong truy vấn con tmp.
Marc L.

Tôi chưa bao giờ đưa ra yêu cầu về tốc độ và OP cũng không đề cập gì về tốc độ. Giả sử UNION ALL (bạn không dựa vào chỉ định cái nào) và cả hai đều đưa ra câu trả lời chính xác, nếu chúng tôi muốn đưa ra khẳng định rằng cái nào nhanh hơn, chúng tôi sẽ cần cung cấp điểm chuẩn và điều đó sẽ lạc đề từ OP câu hỏi
Angelos

Đối với việc quan sát về id không có trong truy vấn phụ, tôi đã sửa lỗi chính tả - cảm ơn bạn đã chỉ ra nó. Yêu cầu trình bày sai của bạn là mơ hồ - nếu có thể bạn có thể cung cấp thêm thông tin, tôi có thể giải quyết điều đó. Về quan sát cuối cùng của bạn về sự dễ thương, tôi không có bất kỳ bình luận nào, tôi muốn tập trung vào logic của sql.
Angelos

3
Trình bày sai: " UNION ALLGiải pháp: ... Cũng không chính xác." Mã bạn trình bày loại bỏ giao lộ loại trừ khỏi tham gia phải ( where t1.id1 is null) phải được cung cấp trong UNION ALL. Có thể nói, giải pháp của bạn hơn hẳn các giải pháp khác, chỉ khi một trong những giải pháp đó được thực hiện không chính xác. Về "sự dễ thương", điểm lấy. Đó là vô cớ, lời xin lỗi của tôi.
Marc L.

-3

Tiêu chuẩn SQL cho biết full join oninner join oncác hàng union allkhông khớp với các hàng của bảng bên trái được mở rộng bằng null union allcác hàng của bảng bên phải được mở rộng bằng null. Tức là inner join onhàng union allhàng trong left join onnhưng không inner join on union allhàng trong right join onnhưng không inner join on.

Tức là left join onhàng union all right join onhàng không trong inner join on. Hoặc nếu bạn biết inner join onkết quả của mình không thể có null trong một cột trong bảng bên phải cụ thể thì " right join onhàng không trong inner join on" là các hàng right join onvới onđiều kiện được mở rộng bởi andcột đó is null.

Tức là hàng right join on union allthích hợp tương tự left join on.

Từ sự khác biệt giữa các thành viên của IN IN THAM GIA và trực tiếp ra mắt là gì? :

(Tiêu chuẩn SQL 2006 SQL / Foundation 7.7 Quy tắc cú pháp 1, Quy tắc chung 1 b, 3 c & d, 5 b.)

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.