SQL: вернуть «true», если список записей существует? - PullRequest
29 голосов
/ 19 мая 2010

Альтернативное название может быть: Проверить наличие нескольких строк?

Используя комбинацию SQL и C #, я хочу, чтобы метод возвращал значение true, если все продукты в списке существуют в таблице. Если это можно сделать все на SQL, это было бы предпочтительнее. Я написал метод, который возвращает, существует ли один productID, используя следующий SQL:

SELECT productID FROM Products WHERE ProductID = @productID

Если это возвращает строку, то метод c # возвращает true, иначе false.

Теперь мне интересно, есть ли у меня список идентификаторов продуктов (не большой список, как правило, младше 20). Как я могу написать запрос, который будет возвращать строку, если все идентификаторы продукта существуют, и нет строки, если один или несколько идентификаторов продукта не существует?

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

EDIT:

Как выражается результат, для меня не важно. Возвращает ли запрос 1 или 0, пустой набор результатов или непустой, true или false, не имеет значения. Я бы предпочел ответ: 1) легко читаемый и понятный и 2) исполнитель

Я предполагал объединить список идентификаторов продуктов с SQL. Очевидно, что это открывает код до внедрения SQL (идентификаторы продукта на самом деле varchar. В этом случае вероятность невелика, но все же мы хотим избежать этой возможности). Так что, если есть способ обойти это, было бы лучше. Использование SQL Server 2005.

Идентификатор продукта: varchar

Ответы [ 13 ]

19 голосов
/ 19 мая 2010

Учитывая ваш обновленный вопрос, это самые простые формы:

Если ProductID уникален, то вы хотите

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

и затем проверьте полученный результат по 3, количеству запрашиваемых продуктов (эту последнюю часть можно выполнить в SQL, но может быть проще сделать это в C #, если вы не делаете еще больше в SQL ).

Если 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 будет действовать так, как указано или подразумевается в других ответах.

11 голосов
/ 19 мая 2010

@ Марк Херд, спасибо за указание на ошибку.

это будет работать (если вы используете 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,10100 там):

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;

[EDIT]

Как я могу написать запрос, который будет вернуть строку, если все идентификаторы продукта существует и нет строки, если один или несколько Идентификатор продукта не существует?

Относительно возврата строки (единственного числа), если все строки существуют, и нет строки , которая будет возвращена, если один или несколько идентификаторов продукта не существует:

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;
10 голосов
/ 24 июля 2015

Вот как я обычно это делаю:

Просто замените ваш запрос этим утверждением SELECT * FROM table WHERE 1

   SELECT
      CASE WHEN EXISTS 
      (
            SELECT * FROM table WHERE 1
      )
      THEN 'TRUE'
      ELSE 'FALSE'
   END
1 голос
/ 19 мая 2010
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]
0 голосов
/ 16 октября 2018

Я знаю, что это старо, но я думаю, что это поможет любому, кто придет посмотреть ...

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

Это ВСЕГДА возвращает ИСТИНА, если существует, и ЛОЖЬ, если нет (в отличие от строки).

0 голосов
/ 23 ноября 2011

Это может быть слишком просто, но я всегда использую:

SELECT COUNT(*)>0 FROM `table` WHERE condition;
0 голосов
/ 19 мая 2010

Где находится этот список продуктов, по которым вы пытаетесь определить наличие? Если этот список существует в другой таблице, вы можете сделать это

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:

Тогда делайте ВСЕ работу в 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 голосов
/ 19 мая 2010

Если вы используете 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 (оставьте здесь, где 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 голосов
/ 19 мая 2010

Если у вас есть идентификаторы, хранящиеся во временной таблице (что может быть сделано с помощью некоторой функции 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 голосов
/ 19 мая 2010

Если предложение 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 сложное, то либо поместите его в таблицу, либо напишите дважды.

...