別のタイトルは次のとおりです。複数の行の存在を確認しますか?
SQLとC#の組み合わせを使用して、リスト内のすべての製品がテーブルに存在する場合にtrueを返すメソッドが必要です。すべてSQLで実行できる場合は望ましいでしょう。次のSQLを使用して、単一のproductID
が存在するかどうかを返すメソッドを作成しました。
SELECT productID FROM Products WHERE ProductID = @productID
これが行を返す場合、c#メソッドはtrueを返し、そうでない場合はfalseを返します。
今、私は製品IDのリストを持っているのだろうかと思っています(通常20歳未満の巨大なリストではありません)。すべての製品IDが存在する場合に行を返し、1つ以上の製品IDが存在しない場合に行を返さないクエリを作成するにはどうすればよいですか?
(Maybe something involving "IN" like:
SELECT * FROM Products WHERE ProductID IN ('1', '10', '100', 'ABC'))
編集:
結果がどのように表現されるかは重要ではありません。クエリが1
または0
を返すか、空の結果セットを返すか、空でない結果セットを返すか、trueまたはfalseは関係ありません。 1)読みやすく、理解しやすく、2)パフォーマンスが良い答えが欲しい
製品IDのリストとSQLを連結することを想定していました。明らかにこれはSQLインジェクションまでコードを開きます(製品IDは実際にはvarchar
です。この場合、チャンスはわずかですが、その可能性を回避したいです)。したがって、これを回避する方法があれば、それはより良いでしょう。 SQL Server 2005を使用します。
製品IDはvarchar
です
更新された質問を考えると、これらは最も単純な形式です。
ProductID
が一意である場合
_SELECT COUNT(*) FROM Products WHERE ProductID IN (1, 10, 100)
_
そして、その結果を_3
_、クエリしている製品の数に対してチェックします(この最後の部分はSQLで行うことができますが、SQLでさらに行うのでなければC#で行う方が簡単かもしれません) 。
ProductID
が一意でない場合
_SELECT COUNT(DISTINCT ProductID) FROM Products WHERE ProductID IN (1, 10, 100)
_
質問がすべてのProductIds
が存在し、それ以外の場合は行を返す必要があると考えられた場合:
_SELECT ProductId FROM Products WHERE ProductID IN (1, 10, 100) AND ((SELECT COUNT(*) FROM Products WHERE ProductID IN (1, 10, 100))=3)
_
または
_SELECT ProductId FROM Products WHERE ProductID IN (1, 10, 100) AND ((SELECT COUNT(DISTINCT ProductID) FROM Products WHERE ProductID IN (1, 10, 100))=3)
_
実際に結果で何かをするつもりなら。それ以外の場合は、他の回答が述べているか暗示しているように、単純なSELECT 1 WHERE (SELECT ...)=3
が実行されます。
@Mark Hurd、エラーを指摘してくれてありがとう。
これは動作します(Postgresql、Sql Server 2008を使用している場合):
create table products
(
product_id int not null
);
insert into products values(1),(2),(10),(100);
SELECT
CASE
WHEN EXISTS(
SELECT 1
FROM (values(1),(10),(100)) as x(id)
WHERE x.id NOT IN (select product_id from products))
THEN 0 --'NOT ALL'
ELSE 1 -- 'ALL'
END
MySQLを使用している場合、一時メモリテーブルを作成します(そこに1,10,100を設定します):
create table product_memory(product_id int) engine=MEMORY;
insert into product_memory values(1),(10),(100);
SELECT
CASE
WHEN EXISTS(
SELECT 1
FROM product_memory
WHERE product_memory.id NOT IN (select product_id from products))
THEN 0 -- 'NOT ALL'
ELSE 1 -- 'ALL'
END
C#コード:
bool isAllExist = (int)(new SqlCommand(queryHere).ExecuteScalar()) == 1;
[編集]
すべての製品IDが存在する場合に行を返し、1つ以上の製品IDが存在しない場合に行を返さないクエリを作成するにはどうすればよいですか?
すべての行が存在する場合はrow(singular)を返し、1つ以上の製品IDが存在しない場合はno rowを返します。
MySql:
SELECT 1
WHERE
NOT EXISTS(
SELECT 1
FROM product_memory
WHERE product_memory.id NOT IN (select product_id from products) )
Posgresql、SQL Server 2008:
SELECT 1
WHERE
NOT EXISTS(
SELECT 1
FROM (values(1),(10),(100)) as x(id)
WHERE x.id NOT IN (select product_id from products) )
次に、C#コードで:
var da = new SqlDataAdapter(queryhere, connectionhere);
var dt = new DataTable();
da.Fill(dt);
if (dt.Rows.Count > 0)
return true;
else
return false;
または、条件を短くします。
return dt.Rows.Count > 0;
私が通常行う方法は次のとおりです。
ちょうどreplaceこのステートメントを使用したクエリSELECT * FROM table WHERE 1
SELECT
CASE WHEN EXISTS
(
SELECT * FROM table WHERE 1
)
THEN 'TRUE'
ELSE 'FALSE'
END
DECLARE @values TABLE (ProductId int)
INSERT @values (1)
INSERT @values (10)
INSERT @values (100)
SELECT CASE WHEN (SELECT COUNT(*) FROM @values v) =
(SELECT COUNT(*) FROM Products p WHERE p.ProductId IN
(SELECT v.ProductId FROM @values v))
THEN CAST(1 AS bit)
ELSE CAST(0 AS bit)
END [AreAllFound]
存在を判断しようとしているこの製品リストはどこにありますか?そのリストが別のテーブル内に存在する場合、これを行うことができます
declare @are_equal bit
declare @products int
SELECT @products =
count(pl.id)
FROM ProductList pl
JOIN Products p
ON pl.productId = p.productId
select @are_equal = @products == select count(id) from ProductList
編集:
その後、すべての作業をC#で行います。アプリケーションの実際の製品リストをどこかにキャッシュし、LINQクエリを実行します。
var compareProducts = new List<Product>(){p1,p2,p3,p4,p5};
var found = From p in GetAllProducts()
Join cp in compareProducts on cp.Id equals p.Id
select p;
return compareProducts.Count == found.Count;
これにより、SQLクエリを手動で作成することを防ぎ、アプリケーション内のすべてのアプリケーションロジックを保持します。
あなたのc#はほんの少しの作業(渡されたIDの数を数える)をしなければなりませんが、これを試してください:
_select (select count(*) from players where productid in (1, 10, 100, 1000)) = 4
_
編集:
4は、整数のリストと同様に、確実にパラメーター化できます。
ユーザーが入力した文字列からSQLを生成していない場合は、攻撃を心配する必要はありません。もしそうなら、整数のみを取得することを確認する必要があります。たとえば、文字列「1、2、3、4」を取得している場合、次のようになります
_String.Join(",", input.Split(",").Select(s => Int32.Parse(s).ToString()))
_
あなたが間違ったものを取得した場合、それはスローされます。次に、それをパラメータとして設定します。
また、items.Count == 0の場合は、必ずwhere ParameterID in ()
を送信するとDBが停止するため、必ず特別なケースにしてください。
// not familiar with C#, but C#'s equivalent of PHP's:
$count = count($productIds); // where $productIds is the array you also use in IN (...)
SELECT IF ((SELECT COUNT(*) FROM Products WHERE ProductID IN (1, 10, 100)) = $count, 1, 0)
IDを一時テーブル(C#関数または単純なSQLで実行可能)に保存している場合、問題はSQLで簡単に実行可能になります。
select "all exist"
where (select case when count(distinct t.id) = (select count(distinct id) from #products) then "true" else "false" end
from ProductTable t, #products p
where t.id = p.id) = "true"
これは、#products
のすべての製品がターゲットテーブル(ProductTable
)に存在する場合に「すべて存在」を返し、上記が真でない場合は行を返しません。
一時テーブルに書き込むつもりがない場合は、検索しようとしている製品の数のパラメーターを入力し、一時テーブルを「in」に置き換える必要があります。サブクエリは次のようになります。
SELECT "All Exist"
WHERE(
SELECT case when count(distinct t.id) = @ProductCount then "true" else "false"
FROM ProductTable t
WHERE t.id in (1,100,10,20) -- example IDs
) = "true"
SQL Server 2008を使用している場合は、 テーブル値パラメーター をとるストアドプロシージャを作成します。その場合、クエリは特に単純な形式である必要があります。
CREATE PROCEDURE usp_CheckAll
(@param dbo.ProductTableType READONLY)
AS
BEGIN
SELECT CAST(1 AS bit) AS Result
WHERE (SELECT COUNT(DISTINCT ProductID) FROM @param)
= (SELECT COUNT(DISTINCT p.ProductID) FROM @param AS p
INNER JOIN Products
ON p.ProductID = Products.ProductID)
END
あなたが要求するように、私はこれを行を返すように変更しました。 WHERE NOT EXISTSでこれを行う方法は他にもあります(ここでWHERE rhs IS NULL)に左から参加してください):
CREATE PROCEDURE usp_CheckAll
(@param dbo.ProductTableType READONLY)
AS
BEGIN
SELECT CAST(1 AS bit) AS Result
WHERE NOT EXISTS (
SELECT * FROM @param AS p
LEFT JOIN Products
ON p.ProductID = Products.ProductID
WHERE Products.ProductID IS NULL
)
END
私はこれが古いことを知っていますが、これは見に来る他の誰にも役立つと思います...
SELECT CAST(COUNT(ProductID) AS bit) AS [EXISTS] FROM Products WHERE(ProductID = @ProductID)
これは、存在する場合は常にTRUEを返し、存在しない場合はFALSEを返します(行がない場合とは対照的に)。
IN節がパラメーター(SPまたはホットビルドSQLのいずれか)である場合、これはいつでも実行できます。
SELECT (SELECT COUNT(1)
FROM product_a
WHERE product_id IN (1, 8, 100)
) = (number of commas in product_id as constant)
IN句がテーブルの場合、これはいつでも実行できます。
SELECT (SELECT COUNT(*)
FROM product_a
WHERE product_id IN (SELECT Products
FROM #WorkTable)
) = (SELECT COUNT(*)
FROM #WorkTable)
IN句が複雑な場合は、テーブルにスプールするか、2回書き込みます。
次のような SELECT CASE ステートメントを使用できます。
select case when EXISTS (
select 1
from <table>
where <condition>
) then TRUE else FALSE end
親にクエリが存在する場合、TRUE
を返します。