2016-04-28 28 views
7

Khi chỉ tìm kiếm cú pháp INSERT của Oracle, tôi nhận thấy bạn có thể chèn vào truy vấn, ví dụ:Chèn vào truy vấn

insert into (select * from dept) (deptno, dname) values (99, 'new department'); 

Ai có thể làm sáng tỏ điều này có ý nghĩa gì không? Tôi có thể đạt được điều gì khi chèn vào truy vấn mà tôi không thể chèn trực tiếp vào bảng?

UPDATE: Cho đến nay có vẻ như đây chỉ là một cú pháp thay thế, vì vậy tôi có thể viết

insert into (select deptno, dname from dept) values (99, 'new department'); 

thay vì

insert into dept (deptno, dname) values (99, 'new department'); 

Cùng một điều, kế hoạch thực hiện tương tự. Nó không quan trọng cho dù truy vấn trả về một bản ghi hay không. Điều này:

insert into (select deptno, dname from dept where 1 = 0) values (99, 'new department'); 

dẫn một lần nữa đến cùng một kế hoạch thực hiện. Vì vậy, chúng ta có thể giả định rằng nó thực sự không quan trọng những gì subquery trông giống như miễn là chúng tôi chỉ chọn cột từ một bảng. Nhưng không. Đây:

insert into (select deptno, dname from dept cross join some_table) 
values (99, 'new department'); 

dẫn đến "ORA-01.779: không thể sửa đổi một cột mà bản đồ vào một bảng không quan trọng bảo tồn" hay "ORA-01.732: Dữ liệu thao tác hoạt động không hợp pháp trên quan điểm này".

Tôi có ấn tượng rằng Oracle đã quyết định cho phép chèn vào truy vấn, vì chúng cho phép chèn vào chế độ xem, cho câu hỏi con khác ở đây thì xem quảng cáo hoc là gì? Vì vậy, khi bạn có thể chèn vào chế độ xem, chắc chắn chúng cũng cho phép bạn chèn vào chế độ xem quảng cáo, nhưng không ai trong tâm trí của họ sẽ sử dụng cú pháp này, tất nhiên :-)

Nhưng có thể tôi đã sai? Có lẽ cú pháp này cung cấp một cái gì đó mà tôi chưa nhận thức được? Nếu vậy hãy cho tôi biết :-)

Trả lời

0

Truy vấn phụ xác định các cột của bảng mà các hàng sẽ được chèn vào. Như oracle's doc (12c) nói:

Specify the name of the [...] column or columns returned by a subquery, into which rows are to be inserted. If you specify a view or object view, then the database inserts rows into the base table of the view.

Ví dụ

create table test_isq (
    pk integer not null primary key, data_1 varchar2(40), data_2 varchar2(40), data_3 varchar2(40) 
); 

-- ok 
insert into (select pk, data_2, data_3 from test_isq) (pk, data_2) values (1, 'Test'); 
insert into (select pk, data_2, data_3 from test_isq) values (2, 'Another', 'Test'); 

-- fail 
insert into (select data_1 from test_isq) values ('This', 'one', 'fails'); 
insert into (select data_1 from test_isq) (pk, data_1) values (42, 'Nope'); 

drop table test_isq; 
+0

Ah, vậy bạn có nói rằng đây chỉ là một cú pháp thay thế? Tôi có thể 'chèn vào các giá trị deptno (deptno, dname) (...)' hoặc 'chèn vào (chọn deptno, dname từ dept) giá trị (...)'. Vì vậy, nó chỉ là một cách khác để viết cùng một điều và không có bất kỳ lợi thế hơn khác? –

+0

Về cơ bản có - mặc dù tôi đã không nghiên cứu phân nhánh có thể. Dựa trên các tài liệu tôi sẽ không mong đợi họ, trừ khi bạn chỉ có 'chèn' đặc quyền và không' chọn' trên bảng tương ứng. – collapsar

-1

Đó là vì INSERT vào câu lệnh SELECT chọn dữ liệu từ một bảng và chèn dữ liệu đó vào bảng hiện có. Bất kỳ hàng hiện có nào trong bảng mục tiêu đều không bị ảnh hưởng.

+1

Tôi cho rằng bạn đang nhầm lẫn điều này với một chèn chọn: 'chèn vào dept (deptno, dname) chọn deptnumber, deptname từ new_departments'. –

+0

Oh yes ... Lý do sử dụng truy vấn phụ như Chèn vào (chọn *) là oracle sẽ không cho phép bất kỳ thay đổi nào đối với bảng sẽ tạo ra các hàng không được bao gồm trong truy vấn phụ. –

+0

Vì vậy, tôi chỉ có thể chèn những gì đã có? Điều đó không có ý nghĩa gì cả. Và dù sao tôi đã thử với 'where 1 = 0' trong truy vấn phụ và nó không ảnh hưởng đến việc chèn vào trong bất kỳ cách nào. Dường như không quan trọng liệu truy vấn phụ có trả về hàng hay không. –

-1

Về cơ bản select * from dept truy vấn đã trả về dữ liệu của bảng dept không phải là tên cột. Và chèn vào để chỉ định tên cột để không thể.

Và khi bạn viết này truy vấn này chèn vào nợ (deptno, dname) chọn deptnumber, deptname từ new_departments thời điểm đó dữ liệu trở lại chọn truy vấn và nó là giá trị vì vậy nó được chèn vào.

+0

Xin lỗi, tôi không hiểu câu trả lời này. Tôi có thể 'chèn vào dept (...) giá trị (...)' và tôi có thể 'chèn vào (chọn * từ dept) (...) giá trị (...)'. Tôi không thấy cách sử dụng truy vấn như trong câu lệnh thứ hai mang lại cho tôi bất kỳ lợi thế nào khi đặt tên bảng trực tiếp như trong truy vấn đầu tiên. –

5

Chèn vào một subquery cho phép hạn chế kết quả sử dụng WITH CHECK OPTION.Ví dụ:

Ví dụ: giả sử bạn muốn cho phép bất kỳ tên bộ phận nào ngoại trừ cho "bộ phận mới". Ví dụ này sử dụng một giá trị khác nhau hoạt động tốt:

SQL> insert into 
    2 (select deptno, dname from dept where dname <> 'new department' WITH CHECK OPTION) 
    3 values (98, 'old department'); 

1 row created. 

Nhưng nếu đó là giá trị xấu được chèn nó ném một lỗi:

SQL> insert into 
    2 (select deptno, dname from dept where dname <> 'new department' WITH CHECK OPTION) 
    3 values (99, 'new department'); 
(select deptno, dname from dept where dname <> 'new department' WITH CHECK OPTION) 
          * 
ERROR at line 2: 
ORA-01402: view WITH CHECK OPTION where-clause violation 

Tôi chưa từng thấy tính năng này được sử dụng trong môi trường hoang dã. Chế độ xem có tùy chọn này do đó bạn có thể thực hiện tương tự với truy vấn phụ. Tôi không chắc chắn lý do tại sao bất cứ ai muốn làm điều này mặc dù, nó chỉ là dễ dàng để đặt giới hạn trên câu lệnh SELECT mà nguồn cấp dữ liệu INSERT. Và nếu INSERT sử dụng các giá trị, nó tầm thường để chuyển nó thành câu lệnh SELECT.

Bạn phải thực sự tìm hiểu sơ đồ cú pháp để xem tính năng này: insert -> single_table_insert -> truy vấn con -> query_block -> table_reference -> query_table_expression -> subquery_restriction_clause.

Các vấn đề liên quan