SQL: retourner "true" si la liste des enregistrements existe?

Un autre titre pourrait être: Vérifier l'existence de plusieurs lignes?

en utilisant une combinaison de SQL et C# je veux une méthode pour retourner true si tous les produits dans une liste existent dans une table. Si cela peut être fait tout en SQL qui serait préférable. J'ai écrit une méthode qui retourne si un seul productID existe en utilisant le SQL suivant:

SELECT productID FROM Products WHERE ProductID = @productID

si cela renvoie une ligne, alors la méthode c# renvoie true, false sinon.

maintenant je me demande si je avoir une liste de produits IDs (pas une liste énorme Esprit vous, normalement moins de 20). Comment puis-je écrire une requête qui retournera une rangée si toutes les id de produit existent et aucune rangée si un ou plusieurs id de produit n'existe pas?

(Maybe something involving "IN" like:
SELECT * FROM Products WHERE ProductID IN ('1', '10', '100', 'ABC'))

EDIT:

Comment le résultat est exprimé n'est pas important pour moi. Si la requête retourne un 1 ou 0, un jeu de résultats vide ou non vide, vrai ou faux n'a pas d'importance. Je préfère la réponse est 1) facile à lire et à comprendre et 2) performant

j'envisageais de concaténer la liste des identificateurs de produit avec le SQL. Évidemment cela ouvre le code JUSQU'à L'injection SQL (les id du produit sont en fait varchar. dans ce cas, le risque est mince, mais veulent éviter cette possibilité). Donc, si il ya un moyen de contourner ce qui serait le mieux. Utilisation de SQL Server 2005.

Produit ID varchar

28
demandé sur Mark Hurd 2010-05-19 04:23:07

12 réponses

compte tenu de votre question mise à jour, ce sont les formes les plus simples:

Si ProductID est unique, que vous voulez

SELECT COUNT(*) FROM Products WHERE ProductID IN (1, 10, 100)

puis vérifiez ce résultat par 3, le nombre de produits que vous demandez (cette dernière partie peut être faite en SQL, mais il peut être plus facile de le faire en C# à moins que vous ne fassiez encore plus en SQL).

Si ProductID n'est pas unique, c'est

SELECT COUNT(DISTINCT ProductID) FROM Products WHERE ProductID IN (1, 10, 100)

quand la question a été pensée pour exiger le retour des lignes quand tous les ProductIds sont présents et nul sinon:

SELECT ProductId FROM Products WHERE ProductID IN (1, 10, 100) AND ((SELECT COUNT(*) FROM Products WHERE ProductID IN (1, 10, 100))=3)

ou

SELECT ProductId FROM Products WHERE ProductID IN (1, 10, 100) AND ((SELECT COUNT(DISTINCT ProductID) FROM Products WHERE ProductID IN (1, 10, 100))=3)

si vous avez réellement l'intention de faire quelque chose avec les résultats. Sinon le simple SELECT 1 WHERE (SELECT ...)=3 va faire comme d'autres réponses ont exprimés ou implicites.

17
répondu Mark Hurd 2014-09-03 10:13:42

@Mark Hurd, merci de signaler l'erreur.

cela fonctionne (si vous utilisez 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

si vous utilisez MySQL, faites une table mémoire temporaire (puis peuplez 1,10,100 ici):

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

dans votre code C#:

bool isAllExist = (int)(new SqlCommand(queryHere).ExecuteScalar()) == 1;

[EDIT]

Comment puis-je écrire une requête qui va retourner une ligne si tous les id du produit existent et pas de ligne si un ou plusieurs produit id n'existe pas?

concernant, retourner une ligne (au singulier) si toutes les lignes existent, et aucune ligne pour être retournée si un ou plusieurs id de produit n'existe pas:

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) )

Puis sur votre code C#:

var da = new SqlDataAdapter(queryhere, connectionhere);
var dt = new DataTable();
da.Fill(dt);

if (dt.Rows.Count > 0) 
    return true; 
else 
    return false;

Ou tout simplement rendre l'état plus court:

return dt.Rows.Count > 0;
11
répondu Michael Buen 2010-05-19 02:51:43

Voici comment j'ai l'habitude de faire:

remplacer votre requête avec cette déclaration SELECT * FROM table WHERE 1

   SELECT
      CASE WHEN EXISTS 
      (
            SELECT * FROM table WHERE 1
      )
      THEN 'TRUE'
      ELSE 'FALSE'
   END
7
répondu Mahmoud Zalt 2015-07-24 00:26:23
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
répondu Anthony Faull 2010-05-19 06:01:48
// 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
répondu Alec 2010-05-19 00:35:57

si la clause IN est un paramètre (SP ou SQL construit à chaud), alors cela peut toujours être fait:

SELECT (SELECT COUNT(1)
          FROM product_a
         WHERE product_id IN (1, 8, 100)
       ) = (number of commas in product_id as constant)

si la clause IN est une table, alors cela peut toujours être fait:

SELECT (SELECT COUNT(*)
          FROM product_a
         WHERE product_id IN (SELECT Products
                                FROM #WorkTable)
       ) = (SELECT COUNT(*)
              FROM #WorkTable)

si la clause IN est complexe, alors soit la bobiner dans un tableau, soit l'écrire deux fois.

0
répondu Joshua 2010-05-19 01:34:17

si vous avez les ID stockés dans une table temp (qui peut être fait par une certaine fonction C# ou SQL simple) alors le problème devient facile et faisable en 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"

ceci retournera "tout existe" quand tous les produits dans #products existent dans la table cible (ProductTable) et ne retournera pas une ligne si ce qui précède n'est pas vrai.

si vous n'êtes pas prêt à écrire à une table temporaire, alors vous devez ajouter un paramètre pour le nombre de produits que vous tentez de trouver, et de remplacer le temp de la table avec un""; clause de sorte que la sous-requête ressemble à ceci:

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
répondu TerrorAustralis 2010-05-19 02:32:32

si vous utilisez SQL Server 2008, je créerais une procédure stockée qui prend un paramètre table. La requête doit alors être d'une forme particulièrement simple:

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

j'ai changé ceci pour retourner une rangée, comme vous semblez l'exiger. Il y a d'autres façons de le faire avec un "où N'existe pas" (rejoignez ici à gauche où rhs est 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
répondu Cade Roux 2010-05-19 02:38:54

de Votre c# vous avez à faire, juste un peu de travail (en comptant le nombre d'Identifiants passés), mais essayez ceci:

select (select count(*) from players where productid in (1, 10, 100, 1000)) = 4

Edit:

4 peut certainement être paramétré, tout comme la liste des entiers.

si vous n'êtes pas en train de générer le SQL à partir de la chaîne de caractères entrée par l'utilisateur, vous n'avez pas à vous soucier des attaques. Si vous l'êtes, vous devez juste vous assurer que vous obtenez seulement des entiers. Par exemple, si vous preniez la corde "1, 2, 3, 4", Tu ferais quelque chose. comme

String.Join(",", input.Split(",").Select(s => Int32.Parse(s).ToString()))

qui jettera si vous obtenez la mauvaise chose. Alors mettez ça comme paramètre.

aussi, assurez-vous d'être sûr de cas particulier si les éléments.Count = = 0, puisque votre DB s'étouffe si vous l'envoyez where ParameterID in ().

0
répondu 2010-05-19 06:14:51

Où est cette liste de produits que vous essayez de déterminer l'existence de? Si cette liste existe dans un autre tableau, vous pouvez le faire

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

Edit:

puis faire tout le travail en C#. Cache la liste réelle des produits dans votre application quelque part, et faites une requête 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;

ceci empêche la construction de requêtes SQL à la main, et garde toute la logique de votre application dans l'application.

0
répondu Josh Smeaton 2010-05-24 01:03:48

en supposant que vous utilisez SQL Server, le type booléen n'existe pas, mais le type bit existe, qui ne peut contenir que 0 ou 1 où 0 représente False, et 1 représente True.

je voudrais aller de cette façon:

select 1
    from Products
    where ProductId IN (1, 10, 100)

Ici, une valeur null ou n'ligne sera retournée (si aucune ligne n'existe).

Ou encore:

select case when EXISTS (
    select 1
        from Products
        where ProductId IN (1, 10, 100)
    ) then 1 else 0 end as [ProductExists]

Ici, l'une des valeurs scalaires 1 ou 0 sera toujours retourné (si aucune ligne n'existe).

-1
répondu Will Marcouiller 2010-05-19 00:45:09

C'est peut-être trop simple, mais j'utilise toujours:

SELECT COUNT(*)>0 FROM `table` WHERE condition;
-1
répondu NAB 2011-11-23 13:01:41