2016-04-28 70 views
7

當查詢Oracle的INSERT語法時,我發現您可以插入到查詢中,例如,插入到查詢中

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

任何人都可以闡明這是什麼意思?我可以通過插入一個查詢來實現什麼功能,而不能直接插入表中?

UPDATE:到目前爲止,似乎這僅僅是一個替代語法,所以我可以寫,而不是

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

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

同樣的事情,同樣的執行計劃。查詢是否返回記錄無關緊要。這:

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

再次導致相同的執行計劃。所以我們可能會認爲,只要我們只從一個表中選擇列,那麼子查詢的樣子實際上並不重要。但不是。這:

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

導致「ORA-01779:不能修改它映射到非鍵保存表列」或「ORA-01732:數據處理操作這種觀點不合法」。

我的印象是,Oracle決定允許插入到查詢中,因爲它們允許插入到視圖中,還有什麼是子查詢,然後是特定視圖?所以當你可以插入到視圖中時,它們當然也可以讓你插入到臨時視圖中,但是當然沒有人在他們的正確思想中使用這種語法:-)

但是也許我錯了?也許這個語法提供了一些我還沒有意識到的東西?如果是這樣告訴我:-)

回答

0

子查詢定義了要插入行的表的列。作爲oracle's doc (12c)說:

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.

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

啊,你是說這只是一種替代語法?我可以'插入到dept(deptno,dname)值(...)'或'插入(選擇deptno,從dept的dname)值(...)'。所以這只是另一種寫同樣東西的方式,沒有一種比另一種更有優勢。 –

+0

基本上是 - 雖然我還沒有研究過可能的後果。基於我不希望他們的文檔,除非你在相應的表上只有'insert'特權而不是'select'。 – collapsar

-1

這是因爲 INSERT into SELECT語句從一個表中選擇數據並將其插入到現有表中。 目標表中的任何現有行都不受影響。

+1

我想你很困惑這與插入選擇:'插入到部門(deptno,dname)選擇deptnumber,deptname從new_departments'。 –

+0

Oh yes ... 使用子查詢的原因(如插入到(select *))是oracle不會允許對將生成子查詢中未包括的行的表進行任何更改。 –

+0

所以我只能插入已經存在的東西?這是沒有意義的。無論如何,我嘗試在子查詢中使用where 1 = 0,並且不會以任何方式影響插入。子查詢是否返回行似乎並不重要。 –

-1

基本上select * from dept查詢已經返回dept表的數據而不是列名。並插入到指定列名稱,因此它是不可能的。

而當你寫這個查詢插入到部門(deptno,dname)選擇deptnumber,deptname從new_departments那個時間選擇查詢返回數據,它是值,所以它被插入。

+0

對不起,我不明白這個答案。我可以'插入到部門(...)值(...)',我可以'插入(從部門選擇)(...)值(...)'。我沒有看到如何像在第二個語句中那樣使用查詢爲我提供了直接在第一個查詢中命名錶的優勢。 –

5

插入到子查詢允許使用WITH CHECK OPTION限制的結果。

例如,假設您希望允許任何部門名稱,除了「新部門」的。這個例子使用不同的值正常工作:

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

1 row created. 

但如果壞值插入它拋出一個錯誤:

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 

我從來沒有見過在野外使用此功能。視圖有這個選項,所以你應該能夠對子查詢做同樣的事情。我不確定爲什麼有人會想要這樣做,但對於提供INSERT的SELECT語句的限制很容易。如果INSERT使用VALUES,則將它轉換爲SELECT語句是微不足道的。

您必須真正深入語法圖才能看到此功能:​​→single_table_insert→子查詢→query_block→table_reference→query_table_expression→subquery_restriction_clause。