web-dev-qa-db-ja.com

INSERT INTOステートメントでTOPを使用する

T-SQLのTOPキーワードに関するチュートリアルを読んでいます。しかし、私はチュートリアルで与えられた例を本当に理解していません。

例1:

INSERT TOP n INTO table_name1 (Col1, Col2)
SELECT Col3, Col4 FROM table_name2;

このチュートリアルでは、データベースには順序の概念がないので、TOPは実際には何も達成しないと述べています。

そして、table_name2から選択されたn行が完全にランダムなレコードであると想定することは正しいですか?

例2:

チュートリアルは、最初のステートメントを改善する別の例を示します。

INSERT INTO table_name1 (Col1, Col2)
  SELECT TOP n  Col3, Col4
  FROM table_name2
Order By Col1;

これは混乱する部分です。 SELECTキーワード内にTOPキーワードを配置すると、ORDER BY句によってどの行が選択および挿入されるかをより適切に制御できるようになります。したがって、2番目の例では、ORDER BY句がSELECTステートメントの一部であると想定します。ただし、Col1table_name2の一部ではありません。

これは私の地獄を混乱させました。洞察をありがとう。

4
John Smith

そして、table_name2から選択されたn行が完全にランダムなレコードであると想定することは正しいですか?

順序が指定されていない場合、通常は_table_name2_の主キーの設計からのソートフィールドと方向が使用されますが、保証はされません。 Aaron Bertrandの発言

クラスタ化インデックスが何であるかは問題ではありません。 SQL Serverは、さまざまな要因に基づく他のインデックスに基づいて注文を返す場合があります。一部の列に主キーを作成しても、順序なしのselectがその列で常に順序付けられた突然の復帰を保証するわけではありません。ほとんどの場合それを観察しましたか?承知しました。しかし、それは保証と同じではありません。私は通りでホッキョクグマを見たことがありませんが、それが起こるのを妨げるホッキョクグマの力場はありません。 – Aaron Bertrand♦2011年9月14日20:41

PKのインデックス順で返したい場合でも、order句を追加しても問題はありません。

チュートリアルの例から

_INSERT INTO table_name1 (Col1, Col2)
  SELECT TOP n Col3, Col4
  FROM table_name2 
Order By Col1;
_

ガァァァァ。それは恐ろしいコーディングです。 SELECT句が2番目のテーブルから明示的にCol1を返していなくても、table_name2の_Col1 ASC_によって順序付けされます。 2番目のテーブルの_Col3_、つまり1番目のテーブルの_Col1_によって順序付けされていません。 _INSERT INTO_のMSドキュメント _ORDER BY_句をリストしないでください -_ORDER BY_は内部SELECT句の一部です。

挿入するテーブルと選択するテーブルを明示的に指定することをお勧めします。例えば。これは少しより良い例です。

_INSERT INTO
  table_name1 (Col1, Col2)
  SELECT TOP 3
    t2.Col3
    ,t2.Col4
  FROM 
    table_name2 AS t2
  ORDER BY
    t2.Col1 ASC, t2.Col3 ASC, t2.Col4 ASC
_

この変更後、_Col1_の意味(またはその並べ替え順序)について混乱はありません。上記の例のように、Col1が_Col3_のすべてのエントリに対して一意でない場合は、_Col4_および_table_name2_のソート順でスローすることをお勧めします。レコードが挿入されるテーブル(table_name1 AS t1 (t1.Col1, t1.Col2)など)にエイリアスを設定することはできません。これは、SQL Serverの既存のバージョンでは有効な構文ではないためです。

意見に基づく推奨:見つけたチュートリアルWebサイトは避けてください。

3
mpag

本が言うことであるなら、それはせいぜい誤解を招くだけです
少なくともMSSQL 2012

挿入(col1、col2)はインデックスベースです
選択の最初の項目がcol1に入ります
データタイプは同じである必要があります
選択はそれ自体で成り立っており、挿入の列名を認識していません

Example1は、一部のデータが必要な場合にのみ有効であり、気にしない
テストにはデータが必要です

これは、table_name2にcol1がある場合にのみ有効です。
その場合、多くの人々がtable_name1.Col1を意味すると想定するので、それは恐ろしい例です。

INSERT INTO table_name1 (Col1, Col2)
SELECT TOP n  Col3, Col4
FROM table_name2
Order By Col1;

より良い例は

INSERT INTO table_name1 (Col1, Col2)
SELECT TOP (n) Col3, Col4
FROM table_name2
Order By Col3; 

Col1がクラスター化されたインデックスであり、すべて挿入してもcol3でソートする必要があるとしましょう

これは名前の競合ではありません
その順序はtable_name2です

INSERT INTO table_name1 (Col3, Col4)
SELECT TOP (n) Col3, Col4
FROM table_name2
Order By Col3; 

これは、並べ替えなしでtopを使用する可能性がある状況ですが、削除です
トランザクションログがいっぱいにならないようにするため

select 1 
while (@@rowcount > 0) 
begin 
   delete top(10000) from table1 
end

トランザクションログがいっぱいになる挿入

select 1 
while (@@rowcount > 0) 
begin 
   INSERT INTO table_name1 (Col3, Col4)
   SELECT TOP (n) T2.Col3, T2.Col4
   FROM table_name2 T2
   LEFT JOIN table_name1 T1  
          on T1.Col3 = T2.Col3
   WHERE T1.Col3 is null
   Order By Col3;
end
1
paparazzo