単一のテーブル(結合なし)から列を選択しようとしていますが、理想的には行の取得を開始する前に、行数のカウントが必要です。必要な情報を提供する2つのアプローチに到達しました。
アプローチ1:
SELECT COUNT( my_table.my_col ) AS row_count
FROM my_table
WHERE my_table.foo = 'bar'
それから
SELECT my_table.my_col
FROM my_table
WHERE my_table.foo = 'bar'
またはアプローチ2
SELECT my_table.my_col, ( SELECT COUNT ( my_table.my_col )
FROM my_table
WHERE my_table.foo = 'bar' ) AS row_count
FROM my_table
WHERE my_table.foo = 'bar'
SQLドライバー(SQL Native Client 9.0)ではSELECTステートメントでSQLRowCountを使用できないため、これを行っていますが、情報を割り当てる前に配列を割り当てるために結果の行数を知る必要があります。残念ながら、動的に割り当てられたコンテナの使用は、私のプログラムのこの分野では選択肢ではありません。
次のシナリオが発生する可能性があることを心配しています。
アプローチ2はこの問題を禁止していますか?
また、2つのアプローチのいずれかが高速になりますか?もしそうなら、どれ?
最後に、考慮する必要があるより良いアプローチがあります(おそらく、SQLRowCountを使用してSELECT結果の行数を返すようにドライバーに指示する方法ですか?)
尋ねた人のために、私はネイティブのC++と前述のSQLドライバー(Microsoft提供)を使用しています。
COUNT(*)
と実際のクエリで一貫した結果が得られることを100%確実にする方法は2つしかありません。
COUNT(*)
をクエリと組み合わせます。kogusのコメントに示されている相関サブクエリフォームではなく、例で示すフォームをお勧めします。SNAPSHOT
またはSERIALIZABLE
分離レベルでトランザクションを開始した後、アプローチ1のように2つのクエリを使用します。これらの分離レベルのいずれかを使用することは重要です。他の分離レベルを使用すると、他のクライアントが作成した新しい行を現在のトランザクションで表示できるようになるためです。 SET TRANSACTION ISOLATION
詳細については。
SQL Serverを使用している場合、クエリ後に @@ RowCount 関数を選択できます(または、結果セットに20億行を超える可能性がある場合は RowCount_Big() を使用します=関数)。これは、前のステートメントで選択された行数、または挿入/更新/削除ステートメントの影響を受ける行数を返します。
SELECT my_table.my_col
FROM my_table
WHERE my_table.foo = 'bar'
SELECT @@Rowcount
または、アプローチ2と同様に送信された結果に行カウントを含める場合は、 OVER句 を使用できます。
SELECT my_table.my_col,
count(*) OVER(PARTITION BY my_table.foo) AS 'Count'
FROM my_table
WHERE my_table.foo = 'bar'
OVER句を使用すると、サブクエリを使用して行数を取得するよりもパフォーマンスが大幅に向上します。 @@ RowCountステートメントを使用すると、select @@ RowCountステートメントのクエリコストが発生しないため、最高のパフォーマンスが得られます。
コメントへの応答で更新します。この例では、パーティション内の行数を示します-この場合は「PARTITION BY my_table.foo」で定義されています。各行の列の値は、my_table.fooと同じ値を持つ行の数です。サンプルクエリには句「WHERE my_table.foo = 'bar'」があるため、結果セットのすべての行はmy_table.fooの同じ値を持ち、したがって列の値はすべての行で同じで(inこの場合)これはクエリの行数です。
結果セットの行の合計数である各行に列を含める方法のより良い/簡単な例を次に示します。オプションのPartition By句を削除するだけです。
SELECT my_table.my_col, count(*) OVER() AS 'Count'
FROM my_table
WHERE my_table.foo = 'bar'
クエリの実行と結果の取得から数ミリ秒で条件を満たす行の数が変わる可能性がある場合は、トランザクション内でクエリを実行できます/実行する必要があります。
BEGIN TRAN bogus
SELECT COUNT( my_table.my_col ) AS row_count
FROM my_table
WHERE my_table.foo = 'bar'
SELECT my_table.my_col
FROM my_table
WHERE my_table.foo = 'bar'
ROLLBACK TRAN bogus
これにより、常に正しい値が返されます。
さらに、SQL Serverを使用している場合は、@@ ROWCOUNTを使用して最後のステートメントの影響を受ける行数を取得し、realクエリの出力を一時テーブルまたはテーブル変数にリダイレクトできます。すべてをすべて返すことができ、トランザクションは不要です。
DECLARE @dummy INT
SELECT my_table.my_col
INTO #temp_table
FROM my_table
WHERE my_table.foo = 'bar'
SET @dummy=@@ROWCOUNT
SELECT @dummy, * FROM #temp_table
アプローチ2は、常に結果セットに一致するカウントを返します。
ただし、カウントの条件がデータセットの条件と一致することを保証するために、サブクエリを外部クエリにリンクすることをお勧めします。
SELECT
mt.my_row,
(SELECT COUNT(mt2.my_row) FROM my_table mt2 WHERE mt2.foo = mt.foo) as cnt
FROM my_table mt
WHERE mt.foo = 'bar';
ここにいくつかのアイデアがあります:
行カウントがselectカウントとselectステートメントの間で変化することを本当に心配している場合は、まず、一時テーブルに行を選択してみませんか?そうすれば、同期が取れることになります。
IF (@@ROWCOUNT > 0)
BEGIN
SELECT my_table.my_col
FROM my_table
WHERE my_table.foo = 'bar'
END
結果をベクトルに入れてみませんか?そうすれば、サイズを事前に知る必要はありません。
これは、この質問に対するgoogleの上位結果であるため、追加するだけです。 sqliteでは、これを使用して行カウントを取得しました。
WITH temptable AS
(SELECT one,two
FROM
(SELECT one, two
FROM table3
WHERE dimension=0
UNION ALL SELECT one, two
FROM table2
WHERE dimension=0
UNION ALL SELECT one, two
FROM table1
WHERE dimension=0)
ORDER BY date DESC)
SELECT *
FROM temptable
LEFT JOIN
(SELECT count(*)/7 AS cnt,
0 AS bonus
FROM temptable) counter
WHERE 0 = counter.bonus
このタイプのデータを処理するためのより良いパターンについて考えたいかもしれません。
回答が変更される可能性があるため(独自の問題を引き起こすトランザクションを使用しない限り)、行を返す前にクエリが返す行数を自己予測SQLドライバーが通知することはありません。
行数は変更されません-ACIDおよびSQLのgoogle。