2013-11-20 37 views
5

My Motiveは、ストアドプロシージャのパラメータとしてIDの長い配列を渡し、IDに基づいてデータを選択します。だから私は無効なオブジェクト名 'dbo.CategoryIdArray'

ALTER PROCEDURE [dbo].[GetNewestArticleByCatsPageWise] 
    @dt as [dbo].[CategoryIdArray] READONLY, 
    @PageIndex INT = 1 
    ,@PageSize INT = 10 
    ,@PageCount INT OUTPUT 
AS 
BEGIN 
     SET NOCOUNT ON; 
     SELECT ROW_NUMBER() OVER 
      (
        ORDER BY [dateadded] 
      )AS RowNumber,[desid] 


INTO #Results 
    FROM [DB_user1212].[dbo].[discussions] as d , [DB_user1212].[dbo].[CategoryMap] as c where d.desid=c.[Topic Id] and c.[Category Id] in (select CategoryId from [dbo].[CategoryIdArray]) and [TopicType]='1' order by [dateadded] 

    DECLARE @RecordCount INT 
    SELECT @RecordCount = COUNT(*) FROM #Results 

    SET @PageCount = CEILING(CAST(@RecordCount AS DECIMAL(10, 2))/CAST(@PageSize AS DECIMAL(10, 2))) 
    PRINT  @PageCount 

    SELECT * FROM #Results 
    WHERE RowNumber BETWEEN(@PageIndex -1) * @PageSize + 1 AND(((@PageIndex -1) * @PageSize + 1) + @PageSize) - 1 

    DROP TABLE #Results 
END 

iがInvalid object name 'dbo.CategoryIdArray'.にスローされる機能の例外の上に実行すると

public List<String> getNewestArticleByCategoryPageWise(long[] categoryId) 
    { 
     List<string> topicId= new List<string>(); 
     try 
     { 

     DataTable dt_Categories = new DataTable(); 
     dt_Categories.Columns.Add("Category", typeof(String)); 
     DataRow workRow; 
     foreach(long cat in categoryId) 
     { 
      workRow = dt_Categories.NewRow(); 
      workRow["Category"] = cat; 
      dt_Categories.Rows.Add(workRow); 
     } 
     int pageIndex = 1; 
      SqlCommand cmd = new SqlCommand("dbo.GetNewestArticleByCatsPageWise", con); 
      cmd.CommandType = CommandType.StoredProcedure; 
      cmd.Parameters.AddWithValue("@PageIndex", pageIndex); 
      cmd.Parameters.AddWithValue("@PageSize", 10); 
      cmd.Parameters.Add("@PageCount", SqlDbType.Int, 4).Direction = ParameterDirection.Output; 
      SqlParameter tvparam = cmd.Parameters.AddWithValue("@dt", dt_Categories); 
      tvparam.SqlDbType = SqlDbType.Structured; 
      con.Open(); 
      sdr= cmd.ExecuteReader(); 
     while(sdr.Read()) 
     { 
      topicId.Add(sdr.GetString(0)); 
     } 
      con.Close(); 
     } 
     catch(Exception ex) 
     { 
      con.Close(); 
      throw ex; 
     } 
     return topicId; 

    } 

以下のコードで、ストアドプロシージャの上に使用しようとした

CREATE TYPE [dbo].[CategoryIdArray] AS TABLE(
[CategoryId] [bigint] NULL 
) 

GO 

とストアドプロシージャSQL Serverでタイプを作成した。しかし私はタイプとしてそれを作成しました。私が逃したものを手伝ってください。私はthisと言いました。

私は効率的か、正しいについてはノークレーム作る
+3

古いスタイルの結合によって、私は苦痛の苦い涙を泣かせます。 – Hogan

+0

@Hogan - 最悪のことの絶対的な原型がありました。 – Brian

+0

@Hogan私の古いスタイルの結合をより効率的な結合に変換するにはどうすればいいですか? –

答えて

4

この行はストアドプロシージャのこの行に問題があります

select CategoryId from [dbo].[CategoryIdArray]。私たちは、このようなタイプから選択することはできません

、我々はここで

select CategoryId from @dt

1

- しかし、読みやすい現代的な構文お使いのベースのクエリは次のように書き込むことはできません。

SELECT ROW_NUMBER() OVER (ORDER BY [dateadded]) AS RowNumber,[desid] 
INTO #Results 
FROM [DB_user1212].[dbo].[discussions] as d 
JOIN [DB_user1212].[dbo].[CategoryMap] as c ON d.desid=c.[Topic Id] 
JOIN [dbo].[CategoryIdArray] arr ON c.[Category Id] = arr.CategoryID 
WHERE [TopicType]='1' 
+0

このように書くことはできますが、問題はまだ解決されていません。 –

+0

@HotCoolStud - あなたは '[DB_user1212]。[dbo]。[CategoryIdArray]'を試しましたか?あなたはそれにちなんで名前を付けましたか?これは単なるネーミング/ネームスペースの問題です。 – Hogan

+0

上記と同じ方法で名前を付けました。[DB_user1212]。[dbo]。[CategoryIdArray]エラーが発生しました。タイプ名 'DB_user1212.dbo.CategoryIdArray'には、接頭辞の最大数を超えています。最大値は1です。 –

0

の代わりに:

workRow["Category"] = cat; 

使用

workRow["CategoryId"] = cat; 
+0

良い点 - この行も変更する必要があります: 'dt_Categories.Columns.Add(" Category "、typeof(String));' – Hogan

+0

私は両方を試みましたが、それは私を嫌っていません。 –

1

を使用する必要がありますあなたのソリューションです:あなたのストアドプロシージャで

、あなたのWHERE文の中で、あなたがAから*を選択しています渡されている実際のパラメータオブジェクトではなく、 "TYPE"です。これは意味をなさない "SELECT * FROM VARCHAR"のようなものです。これを試してください:

... 
and c.[Category Id] in (
    select CategoryId from @dt -- select from the actual parameter, not its TYPE 
) 
... 
4

私がこれらの質問を受けるときにまずやることは、サンプルデータベースを作成することです。以下のコードは、以下を作成します。

1 - データベースと命名[テスト]

2 - 名前のテーブル[ディスカッション]

3 -

[CategoryIdArray]という名前のユーザー定義テーブル型 - [CategoryMap]

4という名前の表

5 - 100個のレコードを持つテーブルをロードする

-- 
-- Create a test db 
-- 

USE [master]; 
go 

CREATE DATABASE [Test]; 
GO 

-- 
-- Create the user defined type 
-- 

USE [Test]; 
go 

CREATE TYPE [CategoryIdArray] AS 
TABLE 
(
[CategoryId] [bigint] NULL 
); 



-- 
-- Create skelton tables 
-- 

create table Discussions 
(
    dis_id int identity (1,1), 
    dis_name varchar(64), 
    dis_added_dte datetime default getdate() 
); 
go 

create table CategoryMap 
(
    cat_id int identity(1,1), 
    cat_topic_id int, 
    cat_topic_type char(1) 
); 
go 

-- clear tables 
truncate table Discussions; 
truncate table CategoryMap; 
go 


-- 
-- Create 100 rows of dummy data 
-- 

declare @cnt int = 0; 
while @cnt < 100 
begin 
    insert into Discussions (dis_name) 
    values ('sample discussion record # ' + str(@cnt, 2, 0)); 

    insert into CategoryMap (cat_topic_id, cat_topic_type) 
    values (@cnt+1, '1') 

    set @cnt = @cnt + 1; 
end; 
go 


-- 
-- Show the sample data 
-- 

select * from Discussions; 
go 

select * from CategoryMap; 
go 

2番目の手順は、ストアドプロシージャを書き換えることです。 2012年以下を使用している場合は、ウィンドウ関数rownumber()を使用してください。 2012年には、オーダーのオフセットとフェッチの句がページングに含まれていました。

http://technet.microsoft.com/en-us/library/ms188385(v=sql.110).aspx

-- 
-- Create my procedure 
-- 

create procedure [GetArticlesByPage] 
    @Tvp as [CategoryIdArray] READONLY, 
    @PageIndex INT = 1, 
    @PageSize INT = 10, 
    @PageCount INT OUTPUT 
AS 
BEGIN 

    -- Declare variables 
    DECLARE @var_recs int = 0; 
    DECLARE @var_offset int = 0; 

    -- Do not count the records 
    SET NOCOUNT ON; 

    -- Start of paging 
    SET @var_offset = @var_offset + ((@PageIndex - 1) * @PageSize); 

    -- Set page count variable 
    SELECT @var_recs = count(*) 
    FROM 
     [dbo].[Discussions] as d 
    JOIN 
     [dbo].[CategoryMap] as c 
    ON 
     d.dis_id = c.cat_topic_id 
    JOIN 
     @TVP a 
    ON 
     c.cat_id = a.CategoryId 
    WHERE 
     cat_topic_type = '1'; 

    set @PageCount = ceiling(cast(@var_recs as real)/cast(@PageSize as real)); 


    -- 
    -- Return the record set 
    -- 

    SELECT 
     dis_id 
    FROM 
     [dbo].[Discussions] as d 
    JOIN 
     [dbo].[CategoryMap] as c 
    ON 
     d.dis_id = c.cat_topic_id 
    JOIN 
     @TVP a 
    ON 
     c.cat_id = a.CategoryId 
    WHERE 
     cat_topic_type = '1' 
    ORDER BY 
     dis_added_dte 
    OFFSET @var_offset ROWS 
    FETCH NEXT @PageSize ROWS ONLY; 

END; 
GO 

は、私が代わりにページ数を残しました。しかし、結果セットが空になるまで呼び出しを繰り返すことができるので、必要とは思われません。

レコードセットを一時テーブルにダンプしないでください。表示するすべてのカラムを返すと、レコードセットがかなり大きくなる可能性があります。私は2つの別々の呼び出しを選択します。 1つは合計カウントです。 1つのページに1つ。

最後のTSQL部分は、SSMSからストアドプロシージャをテストすることです。

-- 
-- Call the stored procedure 
-- 

-- instantiate tvp 
DECLARE @my_tvp as [CategoryIdArray]; 
DECLARE @my_page_cnt as int; 

-- add 25 entries 
declare @cnt int = 25; 
while @cnt < 50 
begin 
    insert into @my_tvp (CategoryId) 
    values (@cnt + 1); 
    set @cnt = @cnt + 1; 
end; 

-- show the data in the tvp 
select * from @my_tvp 

-- call the function 
exec [GetArticlesByPage] @my_tvp, 1, 10, @PageCount = @my_page_cnt OUTPUT; 

-- show the data in the output 
select @my_page_cnt as 'my_pages'; 

go  

私のテスト例では、26行目から50行目を10行にしたいと考えました。結果1は25行、結果2はページングされた10行、結果3はページ数です。したがって、ソリューションのTSQL部分は健全です。 C#のプログラムのデバッグセッション後の今夜のために調整

enter image description here

滞在。

http://www.mssqltips.com/sqlservertip/2112/table-value-parameters-in-sql-server-2008-and-net-c/

この記事を見てみましょう。あなたがしようとしていることを正確にやっています。

ここにいくつかのアイデアがあります。

1 - 私の例では、ログインのデフォルトデータベースが[テスト]であることを確認してください。

2 - [テスト]データベースで定義されているタイプですか?これをもう一度確認してください。

3 - これは間違いありませんか?カラム名は、データベースタイプの[CategoryId]です。あなたは次の - [Category]を持っています。 C#コードで名前を変更してみてください。

dt_Categories.Columns.Add( "Category"、typeof(String));

4 - [dbo]を削除します。 SPのタイプからこれは、MS SQLのヒントの例ではありません。問題を混乱させるかもしれません。 SQLサーバーがその名前を解決します。

5 - 型がbig intとして定義されているが、テーブルのidがintであることがわかりましたか?データ型が一貫していることを確認してください。

これらの提案をお試しください。あなたの作り方を教えてください。

これはまだ問題がある場合は、詳細なコールスタックトレースとエラーメッセージを受け取ることができますか?

ここに私が約束したC#コンソールアプリケーションがあります。

期待どおりに動作します。

ADO.NETとデータテーブルの基礎となるアイデアをいくつか混在させていました。直接のウィンドウとローカル変数を調べるのに慣れておく必要があります。これは問題を追跡するのに役立ちます。

ここでは、ストアドプロシージャのサンプル呼び出しを示します。

1 - セットアップデータテーブル

2(50 74) - 5の

3によるページデータが - 2ページ目ここ

// 
// Good Ref. - http://msdn.microsoft.com/en-us/library/ms254937(v=vs.110).aspx 
// 

// Basic stuff from C# console app 
using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 

// Required for data table 
using System.Data; 
using System.Data.SqlClient; 

// Standard stuff ... 
namespace ConsoleApplication1 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      // Debug info 
      Console.WriteLine("Test - Start"); 

      // Create the table with one column 
      DataTable my_Table; 
      my_Table = new DataTable("Category"); 
      my_Table.Columns.Add("CategoryId", typeof(string)); 

      // Add data to table 
      for (int my_Cnt = 50; my_Cnt < 75; my_Cnt++) 
      { 
       DataRow my_Row = my_Table.NewRow(); 
       my_Row["CategoryId"] = my_Cnt.ToString(); 
       my_Table.Rows.Add(my_Row); 
      } 

      // Debug info 
      Console.WriteLine("Test - created data set"); 

      // Create a connection 
      SqlConnection my_Conn; 
      string str_Conn = "Server=localhost;Database=Test;Trusted_Connection=True;"; 
      my_Conn = new SqlConnection(str_Conn); 

      // Debug info 
      Console.WriteLine("Test - create connection"); 

      // Create the command and set its properties. 
      SqlCommand my_Cmd = new SqlCommand(); 
      my_Cmd.Connection = my_Conn; 
      my_Cmd.CommandText = "dbo.GetArticlesByPage"; 
      my_Cmd.CommandType = CommandType.StoredProcedure; 

      // Add parameter 0 
      SqlParameter my_Parm0 = new SqlParameter(); 
      my_Parm0.ParameterName = "@Tvp"; 
      my_Parm0.SqlDbType = SqlDbType.Structured; 
      my_Parm0.Direction = ParameterDirection.Input; 
      my_Parm0.Value = my_Table; 
      my_Cmd.Parameters.Add(my_Parm0); 

      // Add parameter 1 
      SqlParameter my_Parm1 = new SqlParameter(); 
      my_Parm1.ParameterName = "@PageIndex"; 
      my_Parm1.SqlDbType = SqlDbType.Int; 
      my_Parm1.Direction = ParameterDirection.Input; 
      my_Parm1.Value = 2; 
      my_Cmd.Parameters.Add(my_Parm1); 

      // Add parameter 2 
      SqlParameter my_Parm2 = new SqlParameter(); 
      my_Parm2.ParameterName = "@PageSize"; 
      my_Parm2.SqlDbType = SqlDbType.Int; 
      my_Parm2.Direction = ParameterDirection.Input; 
      my_Parm2.Value = 5; 
      my_Cmd.Parameters.Add(my_Parm2); 

      // Add parameter 3 
      SqlParameter my_Parm3 = new SqlParameter(); 
      my_Parm3.ParameterName = "@PageCount"; 
      my_Parm3.SqlDbType = SqlDbType.Int; 
      my_Parm3.Direction = ParameterDirection.Output; 
      my_Parm3.Value = 5; 
      my_Cmd.Parameters.Add(my_Parm3); 

      // Open the connection 
      my_Conn.Open(); 

      // Debug info 
      Console.WriteLine("Test - execute reader"); 

      // Execute the reader 
      SqlDataReader my_Reader = my_Cmd.ExecuteReader(); 
      if (my_Reader.HasRows) 
      { 
       while (my_Reader.Read()) 
       { 
        Console.WriteLine("{0}", my_Reader[0].ToString()); 
       } 
      } 
      else 
      { 
       Console.WriteLine("No rows found."); 
      } 

      // Close the reader 
      my_Reader.Close(); 

      // Number of pages (output after reader - order is important) 
      Console.WriteLine("Pages = "); 
      Console.WriteLine(my_Cmd.Parameters["@PageCount"].Value.ToString()); 

      // Close the connection 
      my_Conn.Close(); 

      // Debug info 
      Console.WriteLine("Test - close connection"); 

      // Debug info 
      Console.WriteLine("Test - End"); 

      // Pause to view output 
      Console.Read(); 
     } 
    } 
} 

見する正しい出力のスナップショットでありますC#コンソールアプリケーションから。

enter image description here

私はあなたの質問のためにあなたに感謝しなければなりません!

私はC#でコード化して以来、しばらくしています。しかし、バイクのように、それに戻って時間がかかりません。 T-SQLの例はSSMS 2012で行われ、C#プログラムはVS 2013で実行されました。

いいね!

+0

非常に良い解決策ですが、誰も目を打つことはありません。ハハの努力。 – user2705620

0

アクセスしようとしているデータベースにデフォルトのデータベースが設定されている場合は、SQL Server管理スタジオをチェックインします。私は同じ種類のエラーを抱え、何日も立ち往生した。最後に、ユーザがMasterをデフォルトのDBに設定していることがわかりました。

関連する問題