最近、CTE を使用するクエリでカーソルからフェッチ中にエラーが発生しました。
「[Microsoft][SQL Server ネイティブ クライアント 10.0]接続が別のコマンドの結果で切断されました」
エラーは、フェッチの各反復で実行される後続のカーソルで発生していました。
CTE を派生テーブルに置き換えることでエラーを解決できました。
CTE が失敗するのに派生テーブルが正常に機能する理由と、CTE の例で何か間違ったことをしたかどうかを知る必要があります。
元のクエリは比較的複雑で、複数の結合が含まれていましたが、基本的には次のようになります。
WITH cteResults AS (
SELECT Account.Id AS AccountId
FROM Accounts AS Account
WHERE Account.Number = '12345'
UNION
SELECT SubAccount.Id
FROM SubAccounts AS SubAccount
WHERE SubAccount.Number = '12345')
SELECT
Invoice.Value AS InvoiceValue,
CASE
WHEN Representative.Sequence IS NOT NULL THEN THEN Representative.Name
ELSE Account.OwnerName
END AS InvoiceName
FROM cteResults
INNER JOIN Invoices AS Invoice ON
Invoice.AccountId = cteResults.AccountId
LEFT OUTER JOIN Accounts AS Account ON
Account.Id = Invoice.AccountId
LEFT OUTER JOIN AccountRepresentatives AS Representative ON
Representative.Id = Invoices.AccountRepresentativeId
問題のコードは、上記のステートメントを使用してカーソルをループし、FETCH の反復ごとに 2 番目のカーソルを実行します。
FOREACH InvoicesCursor INTO InvoiceResults.*
OPEN FormattingRulesCursor
FETCH FormattingRulesCursor into FormattingRules.*
// Error appears here
CLOSE FormattingRulesCursor
END FOREACH
FOREACH ステートメント中にアプリケーションから開かれたカーソルは、上記のエラーで失敗します。
ただし、CTE を削除して派生テーブルを使用すると、エラーは発生せず、すべてが適切に機能します。
SELECT
Invoice.Value AS InvoiceValue,
CASE
WHEN Representative.Sequence IS NOT NULL THEN THEN Representative.Name
ELSE Account.OwnerName
END AS InvoiceName
FROM (SELECT Account.Id AS AccountId
FROM Accounts AS Account
WHERE Account.Number = '12345'
UNION
SELECT SubAccount.Id
FROM SubAccounts AS SubAccount
WHERE SubAccount.Number = '12345') AS cteResults
INNER JOIN Invoices AS Invoice ON
Invoice.AccountId = cteResults.AccountId
LEFT OUTER JOIN Accounts AS Account ON
Account.Id = Invoice.AccountId
LEFT OUTER JOIN AccountRepresentatives AS Representative ON
Representative.Id = Invoices.AccountRepresentativeId