0

2つの入力パラメーターに基づいてデータのセットを返すストアドプロシージャがあります。パラメータの1つはオプションなので、使用しています

WHERE 
(tbl_Process.ProjectID = @ProjectID)
AND 
(tbl_AnalysisLookup.AnalysisCodeID = 7)
AND
(tbl_ProcessSubStep.ProcessID = ISNULL(@ProcessID,tbl_ProcessSubStep.ProcessID))

@ProcessIDはオプションのパラメーターであるため、ユーザーはそれを提供する場合と提供しない場合があります。次に、複数のProcessIdに対応するようにストアドプロシージャを変更する必要があります。つまり、ユーザーは複数のProcessId、単一のProcessID、またはNo ProcessIDのリストを選択でき、ストアドプロシージャはこれらすべてのシナリオを処理する必要があります。どうしても必要な場合を除いて、動的クエリを使用せずにこれを実現するための最良の方法は何ですか。 一言で言えば、ストアドプロシージャが複数の値(WHERE IN句)を持つオプションのパラメータを処理するようにしたかったのです。私が入手したウェブページへの解決策と相対的なリンクを以下に示します。これは非常に優れた記事であり、要件に基づいて適切なソリューションを選択するのに役立ちます。

4

3 に答える 3

1

私はついにこれを達成する方法を理解しました。これを行うにはいくつかの方法があります。現在使用しているのは、区切り文字に基づいてProcessIDの文字列を分割し、それらをテーブルに挿入する関数です。次に、ストアドプロシージャでそのテーブルを使用します。これがコードとウェブページへのリンクです。

http://www.codeproject.com/Articles/58780/Techniques-for-In-Clause-and-SQL-Server

CREATE FUNCTION [dbo].[ufnDelimitedBigIntToTable]
(
@List varchar(max), @Delimiter varchar(10)
)
RETURNS @Ids TABLE
(Id bigint) AS
BEGIN
DECLARE @list1 VARCHAR(MAX), @Pos INT, @rList VARCHAR(MAX)
SET @List = LTRIM(RTRIM(@List)) + @Delimiter
SET @pos = CHARINDEX(@Delimiter, @List, 1)
WHILE @pos > 0
    BEGIN
    SET @list1 = LTRIM(RTRIM(LEFT(@List, @pos - 1)))
    IF @list1 <> ''
        INSERT INTO @Ids(Id) VALUES (CAST(@list1 AS bigint))
    SET @List = SUBSTRING(@List, @pos+1, LEN(@List))
    SET @pos = CHARINDEX(@Delimiter, @list, 1)
END
RETURN 
END

作成すると、テーブル関数をクエリで使用できます。

 Collapse | Copy Code
CREATE PROCEDURE [dbo].[GetUsingDelimitedFunctionTable]
@Ids varchar(max)
AS
BEGIN
SET NOCOUNT ON
SELECT s.Id,s.SomeString 
FROM SomeString s (NOLOCK)
WHERE EXISTS ( SELECT *
               FROM ufnDelimitedBigIntToTable(@Ids,',') Ids
               WHERE s.Id = Ids.id )
END

リンクは、これを達成するためのより多くの方法も提供します。

于 2012-11-26T23:26:07.993 に答える
0

質問でデータベース製品を指定していませんが、@Pararemterの命名スタイルからSQLServerを使用していると推測します。

空の入力を「すべて」を意味するように解釈するという珍しい要件を除いて、これはSQLの配列の問題の言い換えであり、ErlandSommarskogによって徹底的に調査されました。あなたが使用できるすべてのテクニックの良い分析のために主題に関する彼のすべての記事を読んでください。

ここでは、テーブル値パラメーターを使用して問題を解決する方法を説明します。

次のスクリプトをすべて一緒に実行して、べき等な方法でテスト環境をセットアップします。

サンプルソリューションの作成

まず、新しい空のテストデータベースを作成しますStackOverFlow13556628

USE master;
GO

IF DB_ID('StackOverFlow13556628') IS NOT NULL
BEGIN
  ALTER DATABASE StackOverFlow13556628 SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
  DROP DATABASE StackOverFlow13556628;
END;
GO

CREATE DATABASE StackOverFlow13556628;
GO

USE StackOverFlow13556628;
GO

次に、PrinciapalList1つの列を持つユーザー定義のテーブルタイプを作成しますprincipal_id。このタイプには、システムテーブルをクエリするための入力値が含まれていますsys.database_principals

CREATE TYPE PrincipalList AS TABLE (
  principal_id INT NOT NULL PRIMARY KEY
);
GO

その後、テーブル値パラメーターを入力として受け取り、から結果セットを返すストアドプロシージャGetPrincipalsを作成します。PrincipalListsys.database_principals

CREATE PROCEDURE GetPrincipals (
  @principal_ids PrincipalList READONLY
)
AS
BEGIN
  IF EXISTS(SELECT * FROM @principal_ids)
  BEGIN
    SELECT *
    FROM sys.database_principals
    WHERE principal_id IN (
      SELECT principal_id
      FROM @principal_ids
    );
  END
  ELSE
  BEGIN
    SELECT *
  FROM sys.database_principals;
  END;
END;
GO

sys.database_principalstable-valuedパラメーターに行が含まれている場合、プロシージャーは、値が一致するすべての行を返しprincipal_idます。table-valuedパラメーターが空の場合、すべての行が返されます。

ソリューションのテスト

次のように複数のプリンシパルをクエリできます。

DECLARE @principals PrincipalList;

INSERT INTO @principals (principal_id) VALUES (1);
INSERT INTO @principals (principal_id) VALUES (2); 
INSERT INTO @principals (principal_id) VALUES (3);

EXECUTE GetPrincipals
  @principal_ids = @principals;
GO

結果:

principal_id    name
1   dbo
2   guest
3   INFORMATION_SCHEMA

次のように単一のプリンシパルをクエリできます。

DECLARE @principals PrincipalList;

INSERT INTO @principals (principal_id) VALUES (1);

EXECUTE GetPrincipals
  @principal_ids = @principals;
GO

結果:

principal_id    name
1   dbo

次のようにすべてのプリンシパルにクエリを実行できます。

EXECUTE GetPrincipals;

結果:

principal_id    name
0   public
1   dbo
2   guest
3   INFORMATION_SCHEMA
4   sys
16384   db_owner
16385   db_accessadmin
16386   db_securityadmin
16387   db_ddladmin
16389   db_backupoperator
16390   db_datareader
16391   db_datawriter
16392   db_denydatareader
16393   db_denydatawriter

備考

このソリューションは、テーブル値パラメーターから常に2回読み取る必要があるため、非効率的です。実際には、テーブル値パラメーターに数百万行が含まれていない限り、それが主要なボトルネックになることはおそらくありません。

このように空のテーブル値パラメーターを使用すると、直感的ではないと感じます。より明白な設計は、2つのストアドプロシージャを持つことです。1つはすべての行を返し、もう1つは一致するIDを持つ行のみを返します。どちらを呼び出すかを選択するのは、呼び出し元のアプリケーション次第です。

于 2012-11-26T23:51:48.073 に答える
0

最善ではありませんが、1つの方法は、両側をに変換し、演算子を"varchar"使用"Like"してそれらを比較することです。大きな変更は必要ありません。パラメータのデータ型をに変更するだけ"varchar"です。以下のコードのようなもの:

'%[,]' + Convert(varchar(10), tbl_ProcessSubStep.ProcessID) + '[,]%' Like @ProcessIDs

それが役に立てば幸い。

于 2012-11-25T23:23:26.113 に答える