web-dev-qa-db-ja.com

SQL:レコードのリストが存在する場合、「true」を返しますか?

別のタイトルは次のとおりです。複数の行の存在を確認しますか?

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です

30
User

更新された質問を考えると、これらは最も単純な形式です。

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が実行されます。

20
Mark Hurd

@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;
11
Michael Buen

私が通常行う方法は次のとおりです。

ちょうどreplaceこのステートメントを使用したクエリSELECT * FROM table WHERE 1

   SELECT
      CASE WHEN EXISTS 
      (
            SELECT * FROM table WHERE 1
      )
      THEN 'TRUE'
      ELSE 'FALSE'
   END
11
Mahmoud Zalt
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]
1
Anthony Faull

存在を判断しようとしているこの製品リストはどこにありますか?そのリストが別のテーブル内に存在する場合、これを行うことができます

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クエリを手動で作成することを防ぎ、アプリケーション内のすべてのアプリケーションロジックを保持します。

0
Josh Smeaton

あなたの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が停止するため、必ず特別なケースにしてください。

0
user24359
// 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)
0
Alec

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"
0
TerrorAustralis

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
0
Cade Roux

私はこれが古いことを知っていますが、これは見に来る他の誰にも役立つと思います...

SELECT CAST(COUNT(ProductID) AS bit) AS [EXISTS] FROM Products WHERE(ProductID = @ProductID)

これは、存在する場合は常にTRUEを返し、存在しない場合はFALSEを返します(行がない場合とは対照的に)。

0
joels

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回書き込みます。

0
Joshua

次のような SELECT CASE ステートメントを使用できます。

select case when EXISTS (
 select 1 
 from <table>
 where <condition>
 ) then TRUE else FALSE end

親にクエリが存在する場合、TRUEを返します。

0
Cristian