【问题标题】:SQL: Return "true" if list of records exists?SQL:如果记录列表存在,则返回“true”?
【发布时间】:2011-02-21 04:03:36
【问题描述】:

另一个标题可能是: 检查是否存在多行?

结合使用 SQL 和 C#,如果列表中的所有产品都存在于表中,我希望方法返回 true。如果它可以在 SQL 中完成,那将是可取的。我编写了一个方法,使用以下 SQL 返回单个 productID 是否存在:

SELECT productID FROM Products WHERE ProductID = @productID

如果返回一行,则 c# 方法返回 true,否则返回 false。

现在我想知道我是否有一个产品 ID 列表(请注意,不是一个庞大的列表,通常在 20 个以下)。如何编写一个查询,如果所有产品 ID 都存在则返回一行,如果一个或多个产品 ID 不存在则不返回行?

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

编辑:

结果如何表达对我来说并不重要。查询是否返回10、空结果集或非空结果集,真或假都无关紧要。我更喜欢 1) 易于阅读和理解和 2) 高性能的答案

我设想将产品 ID 列表与 SQL 连接起来。显然,这会将代码打开到 SQL 注入(产品 ID 实际上是varchar。在这种情况下,机会很小,但仍然希望避免这种可能性)。所以如果有办法解决这个问题会更好。使用 SQL Server 2005。

产品 ID 是 varchar

【问题讨论】:

  • +1 以提高清晰度和质量 :)
  • 您是否愿意将产品列表写入临时表或其他可枚举列表?
  • "如何编写一个查询,如果所有产品 ID 都存在则返回一行,如果一个或多个产品 ID 不存在则不返回行?"
  • 我认为他的 C# 函数使用的是if(result.hasrows()) return true else return false
  • 真的我只需要知道它们是否都存在。如何表达对我来说并不重要。我认为空结果集与非空结果集是最简单的方法。

标签: sql boolean conditional-statements exists


【解决方案1】:

你的 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 (),您的数据库会阻塞。

【讨论】:

  • 我在 MySQL 上进行了测试,它可以工作。您可能需要在 MS SQL 上使用 select if
  • 这是迄今为止我最喜欢的简洁。 1)上例中的“4”可以参数化吗? 2)我需要动态构建产品列表,如何避免SQL注入攻击(使用varchar productid's)?
  • @User 已编辑回答这些问题。此外,如果您对 SQL Server 有任何问题(不确定您使用的是哪个数据库),请查看 Alec 的答案,该答案非常相似。
  • 我无法将字符串解析为整数,因为产品 ID(对不起,误导性名称)不是整数而是 varchar
  • 参数化仍然会阻止注入
【解决方案2】:

鉴于您更新的问题,这些是最简单的形式:

如果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 将按照其他答案所述或暗示的方式执行。

【讨论】:

  • 如果您忠实地遵守How can I write a query that will return a row if all the product id's exist and no row if one or more product id's does not exist? 的要求,那是不正确的,您的答案将始终返回一行。无论如何,要求返回no row 的逻辑让我无法理解,也许用户不想触摸代码if (result.hasRows())。如果为简单起见,我将使用您的答案。如果追求性能,仅测试数据存在性(使用 EXISTS)会更快,并且可以很好地完成工作
  • 这么多不同的答案,但最终这是我选择的路径。实际上,更难的部分是参数化“IN”列表。我使用stackoverflow.com/questions/337704/… 做到了这一点
  • 我之前没有注意到 IN 子句不能被参数化。我会找一张临时桌子。
  • 如何以参数化的方式动态构建临时表?
  • 在与最终查询在同一连接上的单独参数化查询中执行此操作(CREATE TABLE #TempTable(ProductID VARCHAR(33) NOT NULL) 和许多 INSERT INTO #TempTable(ProductID)VALUES(@ProductID))。
【解决方案3】:

假设你使用的是 SQL Server,boolean 类型不存在,但 bit 类型存在,它只能容纳 0 或 1,其中 0 代表 False,1 代表 True。

我会走这条路:

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

这里将返回一个空行或没有行(如果不存在行)。

甚至:

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

这里,标量值 1 或 0 将始终返回(如果不存在行)。

【讨论】:

  • 我认为这行不通。在上面的例子中,如果产品 ID 的 1 和 100 存在但 10 不存在,仍然会返回一行
  • 我刚刚阅读了您的编辑,这不是我最初理解的内容。你想不想知道什么产品不存在?您想知道有多少产品不存在吗?你到底想要什么?
  • 仅供参考,我没有对你投反对票,但我认为我问题中的第一句话总结得很好。 “结合使用 SQL 和 C#,如果列表中的所有产品都存在于表中,我希望方法返回 true”
【解决方案4】:
// 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)

【讨论】:

    【解决方案5】:

    如果 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 子句很复杂,那么要么将其假脱机到一个表中,要么将其写入两次。

    【讨论】:

      【解决方案6】:

      如果您将 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)中时,这将返回“all exists”,如果上述情况不成立,则不会返回一行。

      如果您不愿意写入临时表,那么您需要为您尝试查找的产品数量输入一些参数,并将临时表替换为“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"
      

      【讨论】:

        【解决方案7】:

        @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 都返回一行 如果一个或多个存在并且没有行 产品 ID 不存在?

        关于,如果所有行都存在则返回一行(单数),如果一个或多个产品id不存在则返回无行

        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;
        

        【讨论】:

        • 我不得不指出......如果所有行都不存在,OP 要求没有行。无论如何,您的解决方案都会返回一行 :)
        • 是的,这很令人困惑 :-) 即使我也不知道该行包含什么,这就是为什么我在 OP 的问题中询问行的内容是什么。我认为最好只返回包含布尔字段的行并在前端对其进行评估:-)
        【解决方案8】:

        如果您使用的是 SQL Server 2008,我将创建一个采用 a table-valued parameter 的存储过程。查询应该是一个特别简单的形式:

        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 (LEFT JOIN in here 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
        

        【讨论】:

          【解决方案9】:

          您要确定其存在的产品列表在哪里?如果该列表存在于另一个表中,您可以这样做

          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# 方法。
          【解决方案10】:
          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]
          

          【讨论】:

            【解决方案11】:

            这可能太简单了,但我总是使用:

            SELECT COUNT(*)>0 FROM `table` WHERE condition;
            

            【讨论】:

            • 这在 MS SQL Server 上是不可接受的语法。 '>' 附近的语法不正确。
            【解决方案12】:

            这是我通常的做法:

            只需替换您的查询与此语句SELECT * FROM table WHERE 1

               SELECT
                  CASE WHEN EXISTS 
                  (
                        SELECT * FROM table WHERE 1
                  )
                  THEN 'TRUE'
                  ELSE 'FALSE'
               END
            

            【讨论】:

              【解决方案13】:

              我知道这已经过时了,但我认为这将有助于其他任何前来寻找的人......

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

              如果存在则始终返回 TRUE,如果不存在则返回 FALSE(与无行相反)。

              【讨论】:

                【解决方案14】:

                您可以像这样使用SELECT CASE 语句:

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

                当您在父母中的查询存在时,它返回TRUE

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 2015-02-14
                  • 2014-09-06
                  • 1970-01-01
                  • 2015-07-06
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多