none
リンクサーバーを使用したときに、CASE文でエラーになる RRS feed

  • 質問

  • SQL Server 2005 Express から、 SQL Server 2000 へ向けて、リンクサーバーを設定しています。

    SQL Server 2005 Express 上で、以下のようなSQL文を流すと、
    「ステートメントを準備できませんでした。」「Case 式は、10 レベルまでしかネストできません。」
    とエラーメッセージが出てしまいます。

     DECLARE @aaa Integer
     SET @aaa = 1

     SELECT
     CASE WHEN @aaa = 1 THEN 'a'
      WHEN @aaa = 2 THEN 'b'
     WHEN @aaa = 3 THEN 'c'
     WHEN @aaa = 4 THEN 'd'
     WHEN @aaa = 5 THEN 'e'
     WHEN @aaa = 6 THEN 'f'
     WHEN @aaa = 7 THEN 'g'
     WHEN @aaa = 8 THEN 'h'
     WHEN @aaa = 9 THEN 'i'
     WHEN @aaa = 10 THEN 'j'
     WHEN @aaa = 11 THEN 'k'
     ELSE '' END
     FROM [リンクサーバーIP].DB名.dbo.テーブル名

    当然、リンクサーバー経由せず、普通に実行すると問題ないです。
    もう SQL Server 2000 もサポート切れですし、SQL Server 2012 から SQL Server 2000 にリンクサーバーが貼れないようなので、
    半分別の手法を模索中ですが、代替え案等がございましたら、あわせて教えていただければと思います。

    2014年5月21日 1:11

回答

  • ただ、リンクサーバーだと、CASE文をネストしたわけでもないのに、ネストエラーが出るのが解せないですね。。。
    あまり深く考えず、この件は解決といたします。

    不思議な現象で興味があったので調べてみました。正しいかどうかは別として、以下が参考になりました。

    Why do linked servers have a limitation of 10 branches in a CASE expression?
    http://dba.stackexchange.com/questions/42837/why-do-linked-servers-have-a-limitation-of-10-branches-in-a-case-expression

    簡単に意訳すれば、パーサーがcase文をネストした文を生成し、それをリンクサーバーに送るからのようです。ローカルではこの生成した文を使わないので問題が発生しないとのことです。

    #追記。言い忘れました。上のページに最後に解決策らしきものが書いてありますね。裏技っぽいですが・・・


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/


    2014年5月21日 5:28

すべての返信

  • 提示されている要件を実現するだけであれば例えば以下のような様々な手法が考えられますが、それが使えないから CASE 文で 1 つ 1 つ分岐しているという状況でしょうか?

    --方法1
    DECLARE @aaa Integer
    SET @aaa = 1

    SELECT
    CASE WHEN 1 <= @aaa AND @aaa <= 11 THEN CHAR(@aaa + 96)
    ELSE '' END
    FROM [リンクサーバーIP].DB名.dbo.テーブル名


    --方法2
    DECLARE @aaa Integer
    SET @aaa = 1

    SELECT 'a' FROM [リンクサーバーIP].DB名.dbo.テーブル名 WHERE @aaa = 1
    UNION ALL
    SELECT 'b' FROM [リンクサーバーIP].DB名.dbo.テーブル名 WHERE @aaa = 2
    UNION ALL
    SELECT 'c' FROM [リンクサーバーIP].DB名.dbo.テーブル名 WHERE @aaa = 3
    UNION ALL
    SELECT 'd' FROM [リンクサーバーIP].DB名.dbo.テーブル名 WHERE @aaa = 4
    UNION ALL
    SELECT 'e' FROM [リンクサーバーIP].DB名.dbo.テーブル名 WHERE @aaa = 5
    UNION ALL
    SELECT 'f' FROM [リンクサーバーIP].DB名.dbo.テーブル名 WHERE @aaa = 6
    UNION ALL
    SELECT 'g' FROM [リンクサーバーIP].DB名.dbo.テーブル名 WHERE @aaa = 7
    UNION ALL
    SELECT 'h' FROM [リンクサーバーIP].DB名.dbo.テーブル名 WHERE @aaa = 8
    UNION ALL
    SELECT 'i' FROM [リンクサーバーIP].DB名.dbo.テーブル名 WHERE @aaa = 9
    UNION ALL
    SELECT 'j' FROM [リンクサーバーIP].DB名.dbo.テーブル名 WHERE @aaa = 10
    UNION ALL
    SELECT 'k' FROM [リンクサーバーIP].DB名.dbo.テーブル名 WHERE @aaa = 11
    UNION ALL
    SELECT '' FROM [リンクサーバーIP].DB名.dbo.テーブル名 WHERE @aaa < 1 OR 11 < @aaa


    MCITP(Database Developer/Database Administrator)



    2014年5月21日 2:05
  • すみません、あくまでもわかりやすくするための例としてクエリを挙げているので、
    実際のクエリはもう少し複雑で、テーブル内の値のみを使っていて、変数は使っていません。

    たちまちは、nagino様の方法2のような手法で
    UNION で仮想のテーブルを作ったあと、
    LEFT OUTER JOIN で連結させて、解決いたしました。

    ただ、リンクサーバーだと、CASE文をネストしたわけでもないのに、ネストエラーが出るのが解せないですね。。。
    あまり深く考えず、この件は解決といたします。

    2014年5月21日 2:24
  • あー、それはエラーメッセージが誤解しやすい表現になっているだけです。
    WHEN 句(ELSE 句を含むかどうかは失念しました)が 11 個以上あるとそのエラーになったはずです。
    WHEN 句を減らしていくとエラーが出なくなるはずです。
    ご参考まで。

    MCITP(Database Developer/Database Administrator)


    2014年5月21日 2:57
  • 本件の解決とは関係無い上、提示されたクエリは例としてあげただけとの事ですがcase文は

    DECLARE @aaa Integer
    SET @aaa = 1
    
    SELECT
      CASE @aaa
      WHEN 1 THEN 'a'
      WHEN 2 THEN 'b'
      WHEN 3 THEN 'c'
      WHEN 4 THEN 'd'
      WHEN 5 THEN 'e'
      WHEN 6 THEN 'f'
      WHEN 7 THEN 'g'
      WHEN 8 THEN 'h'
      WHEN 9 THEN 'i'
      WHEN 10 THEN 'j'
      WHEN 11 THEN 'k'
      ELSE '' END
      FROM [リンクサーバーIP].DB名.dbo.テーブル名
    

    こんな書き方の方が私は好きです。

    2014年5月21日 3:03
  • ただ、リンクサーバーだと、CASE文をネストしたわけでもないのに、ネストエラーが出るのが解せないですね。。。
    あまり深く考えず、この件は解決といたします。

    不思議な現象で興味があったので調べてみました。正しいかどうかは別として、以下が参考になりました。

    Why do linked servers have a limitation of 10 branches in a CASE expression?
    http://dba.stackexchange.com/questions/42837/why-do-linked-servers-have-a-limitation-of-10-branches-in-a-case-expression

    簡単に意訳すれば、パーサーがcase文をネストした文を生成し、それをリンクサーバーに送るからのようです。ローカルではこの生成した文を使わないので問題が発生しないとのことです。

    #追記。言い忘れました。上のページに最後に解決策らしきものが書いてありますね。裏技っぽいですが・・・


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/


    2014年5月21日 5:28
  • なるほど、ありがとうございます。

    ちなみに、SQL Server 2000 から SQL Server 2000 へのリンクサーバーでは、この現象は発生しなかったので、
    安心して同システムを別PCに設定したらコレでした。。。
    リンクサーバーはバージョンにより色々ありますが、便利なので今後も体当たりで使ってゆきます。
    ありがとうございました。

    2014年5月21日 6:31