2017-11-10 10 views
0

私はテーブルのデータを選択し、そのテーブルからいくつかの行を選択し、それらの行を別の同じテーブルに挿入するクエリを作成しています。他のデータベースを選択してから、proignを繰り返して、orignalテーブルから次の行数を選択します。これは、SQLサーバー用の.NETRow_Numberを使用してそのテーブルのselectの結果を挿入します。

にループを入れて

$" INSERT INTO {destination-table} 
    SELECT * FROM {original-table} 
    WHERE ROWID IN (SELECT B.RID 
      FROM (SELECT ROWID AS RID, rownum as RID2 
        FROM {original-table} 
        WHERE {Where Claus} 
        AND ROWNUM <= {recordsPerStatement * iteration}            
) B WHERE RID2 > {recordsPerStatement * (iteration - 1)})" 

しかし、私は取得に失敗:

参考のために

が、これは私が(すでにOracleのためにそれを構築する)やろうものですこれは終わった。私が取得するデータ:

$" Select B.* from (Select A.* from (Select Row_NUMBER() 
     OVER (order by %%physloc%%) As RowID, {original-table}.* FROM 
{original-table} where {where-claus}) 
A Where A.RowID between {recordsPerStatement * (iteration - 1)} 
AND {recordsPerStatement * iteration} B" 

ここでの問題は、上記の選択は、私は方法を見てきた宛先テーブル

に上記のデータを挿入するから私を防ぎ余分な列(ROWID)を生成することです上の選択のROWID列を取り除くか、元のテーブルのデータを元のテーブルから挿入します。 (元のテーブルのどこに存在するのか(選択クエリの残り))。 ...無駄にする

TLDR =計算で使用されるROWID列を取り除く

仕様同じ表に行を挿入することができ、その後に:

  • 大量のデータ(数百万行)(そのためのビットでそれを処理する)
  • 不明テーブル(私は上で呼び出すことはできません
  • は同じデータが2回コピーされないように順序(したがってrow_number)を持つ必要があります。
  • 挿入(最初に検索してローカルでいくつかのマジックを実行するとパフォーマンスに大きな影響を与えます)
  • 必要に応じて追加の変数を追加することができます(オーダークラウス変数など)。クエリは常に変数になります+クエリにvarriablesを追加しない方が良い場合は、それが好ましいでしょう

誰かが私がさらに何を見ることができるかについてのアイデアを得ることを望みます。

答えて

0

私が思いついた解決策:[挿入/選択クエリを構築するには、再びそれらを使用してのみからこれらの列を選択するには、

まず、データベースからCOLUMN_NAMESを読み取り、ローカルに保存しますビュー(これらはすべてROWIDから離れています)。

commandText = $"SELECT column_name 
       FROM INFORMATION_SCHEMA.COLUMNS 
       WHERE TABLE_NAME = N'{table}'" 

columnNames = "executionfunction with commandText" 
columnNamesCount = columnNames.Rows.Count 

Dim counter As Int16 = 0 
commandText = String.Empty 
commandText = $"INSERT INTO {destination} SELECT " 

    For Each row As DataRow In columnNames.Rows 

     If counter = columnNamesCount - 1 Then 
       commandText += $"B.{row("column_name")} " 
     Else 
       commandText += $"B.{row("column_name")}, " 
     End If 

     counter = counter + 1 
    Next 

    commandText += $"FROM 
        (Select A.* FROM (Select Row_NUMBER() 
        OVER(order by %%physloc%%) AS RowID, {table}.* 
        FROM {table} where {filter}) A 
        WHERE A.RowID between ({recordsPerStatement} * ({iteration}-1)) + 1 
        AND ({recordsPerStatement} * {iteration})) B" 

EDIT:%% %% physloc句ANを削除するには、次の部分が中に構築されているFETCH OFFSET。新しいアプローチ:

commandText += $"INSERT INTO {destination} SELECT * FROM {table} WHERE {filter}" 

    For i As Int16 = 1 To columnNamesCount 

     If i = 1 Then 
      commandText += $"ORDER BY {columnNames.Rows(i - 1)("column_name")} ASC" 
     Else 
      commandText += $"{columnNames.Rows(i - 1)("column_name")} ASC" 
     End If 

     If i <> columnNamesCount Then 
      commandText += ", " 
     End If 
    Next 

commandText += $" OFFSET ({recordsPerStatement} * ({iteration} -1)) ROWS FETCH Next {recordsPerStatement} ROWS ONLY" 
+0

大規模なデータセットでこれがどのように機能するかを知りたいと思います。あなたのコマンドを繰り返し実行するたびに、すべてのデータを%% physloc %%で抽出してソートする必要があり、行の適切なサブセットが得られるように思えます。また、このプロセスへの呼び出しの間に、レコードの%% physloc %%が変更される可能性があります。この場合、抽出されたセットに重複または欠落したレコードが存在する可能性があります。 – JohnRC

+0

質問の2番目の部分は、同じ列名が取り込まれることによって処理されます。クエリの最後に、これらの列名を使用して任意のORDER BY句を作成します。 (すべての列名をORDER BY {columnname} ASCとしてループに入れ、後でそのデータをパージするときに再度使用してください) 私はあなたの懸念を%% physloc %%で共有しています。代わりに、 FETCH NEXTにORDER BYがあるので、テスト後に私の好みのアプローチになるかもしれません。 – Fondas

+0

Hmmm ...ここでもリスクはあると思います。もしあなたが注文のためにどんな種類のシンボリックキーを使っても、レコードのグループを選択する順序を選択すると、抽出されたグループ間でレコードのキー値が変更されると、レコードのサブセットが選択されなくなる危険性があります。 – JohnRC

1

この手法では、ページ単位で処理する前に一時テーブルを使用してページ単位のデータを保存します。それは私のために働いていますが、非常に大きなデータセットに問題があるかどうかはわかりません。あなたはSPにすべてのものを置くことができますし、.netからのパラメータでSPを呼び出すことができます。宛先テーブル名のパラメータを追加し、最後のループにINSERT文を作成または実行する必要があります。

 -- Parameters 
     DECLARE @PageSize integer = 100; 
     DECLARE @TableName nVarchar(200) = 'WRD_WordHits'; 
     DECLARE @OrderBy nVarchar(3000) = 'WordID' 

     STEP_010: BEGIN 
     -- Get the column definitions for the table 

      DECLARE @Cols int; 
      SELECT TABLE_NAME, ORDINAL_POSITION, COLUMN_NAME, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH 
        , IS_NULLABLE 
      INTO #Tspec 
      FROM INFORMATION_SCHEMA.COLUMNS 
      WHERE TABLE_NAME = @TableName; 

      -- Number of columns 
      SET @Cols = @@ROWCOUNT; 
     END; 

     STEP_020: BEGIN 
      -- Create the temporary table that will hold the paginated data 
      CREATE TABLE #TT2 (PageNumber int, LineNumber int, SSEQ int) 
      DECLARE @STMT nvarchar(3000); 


     END; 

     STEP_030: BEGIN 
     -- Add columns to #TT2 using the column definitions 
      DECLARE @Ord int = 0; 
      DECLARE @Colspec nvarchar(3000) = ''; 
      DECLARE @AllCols nvarchar(3000) = ''; 
      DECLARE @ColName nvarchar(200) = ''; 


      WHILE @Ord < @Cols BEGIN 

         SELECT @Ord = @Ord + 1; 

         -- Get the column name and specification 
         SELECT @ColName = Column_Name 
           , @Colspec = 
            Column_Name + ' ' + DATA_TYPE + CASE WHEN CHARACTER_MAXIMUM_LENGTH IS NULL THEN '' 
             ELSE '(' + CAST(CHARACTER_MAXIMUM_LENGTH AS varchar(30)) + ')' END 

          FROM #Tspec WHERE ORDINAL_POSITION = @Ord; 

         -- Create and execute statement to add the column and the columns list used later 
         SELECT @STMT = ' ALTER TABLE #TT2 ADD ' + @Colspec + ';' 
           , @AllCols = @AllCols + ', ' + @ColName ; 
         EXEC sp_ExecuteSQL @STMT; 

      END; 

      -- Remove leading comma from columns list 
      SELECT @AllCols = SUBSTRING(@AllCols, 3, 3000); 
      PRINT @AllCols 

      -- Finished with the source table spec 
      DROP TABLE #Tspec; 

     END; 

     STEP_040: BEGIN -- Create and execute the statement used to fill #TT2 with the paginated data from the source table 

      -- The first two cols are the page number and row number within the page 
      -- The sequence is arbitrary but could use a key list for the order by clause 

      SELECT @STMT = 
         'INSERT #TT2 
         SELECT FLOOR(CAST(SSEQ as float) /' + CAST(@PageSize as nvarchar(10)) + ') + 1 PageNumber, (SSEQ) % ' + CAST(@PageSize as nvarchar(10)) + ' + 1 LineNumber, * FROM 
         ( 

           SELECT ROW_NUMBER() OVER (ORDER BY ' + @OrderBy + ' ) - 1 AS SSEQ, * FROM ' + @TableName + ' 

         ) 
          A; ' ; 
      EXEC sp_ExecuteSQL @STMT; 

      -- *** Test only to show that the table contains the data 
        --SELECT * FROM #TT2; 
        --SELECT @STMT = 'SELECT NULL AS EXECSELECT, ' + @AllCols + ' FROM #TT2;' ; 
        --EXEC sp_ExecuteSQL @STMT; 
      -- *** 
     END; 

     STEP_050: BEGIN -- Loop through paginated data, one page at a time. 
      -- Variables to control the paginated loop 
      DECLARE @PageMAX int; 
      SELECT @PageMAX = MAX(PageNumber) FROM #TT2; 
      PRINT 'Generated ' + CAST(@PageMAX AS varchar(10)) + ' pages from table'; 

      DECLARE @Page int = 0; 

      WHILE @Page < @PageMax BEGIN 
       SELECT @Page = @Page + 1; 

       -- Create and execute the statement to get one page of data - this could be any statement to process data page by page 
       SELECT @STMT = 'SELECT ' + @AllCols + ' FROM #TT2 WHERE PageNumber = ' + CAST(@Page AS Varchar(10)) + ' ORDER BY LineNumber ' 

       -- Execute the statment. 
       PRINT @STMT -- For testing 
       --EXEC sp_EXECUTESQL @STMT; 

      END; 

      -- Finished with Paginated data 
      DROP TABLE #TT2; 

     END; 
関連する問題