【问题标题】:Selecting two rows in a single sql statement only if both conditions are met仅当同时满足两个条件时才在单个 sql 语句中选择两行
【发布时间】:2015-03-11 06:07:32
【问题描述】:

我有一张包含以下数据的表格。

表名:我的表

prodID   catNo   variable1  variable2
1        20      Cat        Blue
2        10      Cat        Red
2        15      Cat        Green
2        20      Cat        Black
3        20      Cat        Yellow
4        10      Cat        Orange
4        15      Cat        Brown
4        20      Cat        Black
5        30      Cat        Pink

我希望能够从 myTable 中选择满足以下条件的所有列
"(prodID = 2catNo = 10) AND (prodID = 2catNo = 15)”。因此,只有在满足两个条件时才能获得两行的结果,如果两行都不存在,它将不返回任何内容。 所以我的结果表将如下所示。

表名:结果

prodID   catNo   variable1  variable2
2        10      Cat        Red
2        15      Cat        Green

我尝试使用条件 if 语句,但似乎无法让它们在 sql 中工作。我当前的解决方案是取回 prodID = 2 的所有行,然后使用 php 执行 if 语句来决定显示什么,但这不适用于我为显示结果而设计的分页,因为我的限制会扭曲每页的结果数。 我知道我可以使用 'have count rows=2' 但我不知道如何措辞。

【问题讨论】:

  • 将 AND 替换为 OR 它将起作用“(prodID = 2 and catNo = 10) OR (prodID = 2 and catNo = 15)”。
  • where prodID = 2 and (catNo = 10 OR catNo = 15)?
  • 获取超过 1 个 catNo 的行:SELECT *, COUNT(catNo) FROM myTable HAVING COUNT(catNo) > 1
  • 很抱歉在每条评论上都发布了此内容,但大多数人似乎不理解我的要求。
    这两个条件都必须为真,因此不能选择“OR”。如果 'catNo =15' 的行不存在,那将返回一个结果。只有当它们都存在时,我才需要这两行。
    并且 count(catNo)>1 将返回所有超过 1 个 catNo 的行。

标签: php mysql sql database multiple-conditions


【解决方案1】:

条件应该是 (prodID = 2 and catNo = 10) OR (prodID = 2 and catNo = 15)

【讨论】:

  • 结果不是预期的操作......他将 prodID 的 catNo=10 和 catNo=15 因此只有在满足两个条件时才能获得两行的结果
  • 两个条件都必须为真,所以“或”不是一个选项。
  • select * from mytable where prodid in (select prodid from mytable where catno = 10 ) and prodid in (select prodid from mytable where catno = 15 )
【解决方案2】:

如果您只想在 catNo (10,15) 中找到记录时获得结果,但如果您在 (10,12) 中查找 catNo 时也返回 0 结果

SELECT * FROM `myTable` 
WHERE (`prodID` = 2 AND `catNo` IN (10,15)) 
AND (SELECT COUNT(`catNo`) FROM `myTable` WHERE `prodID` = 2 AND `catNo` IN (10,15))>1;

三个 CatNo 的

SELECT * FROM `myTable` 
WHERE (`prodID` = 4 AND `catNo` IN (10,15,20)) 
AND (SELECT COUNT(`catNo`) FROM `myTable` WHERE `prodID` = 4 AND `catNo` IN (10,15,20))>2;

SQL Fiddle

【讨论】:

  • 这两个条件都必须为真,因此“OR”不是一个选项。如果 'catNo =15' 的行不存在,那将返回一个结果。只有当它们都存在时,我才需要这两行。
  • 如果 catNo 的 og 10-15 范围内没有类别,那么第三个示例是最快的解决方案。
  • 这不是一个可行的解决方案,因为变量将由用户定义以构建结果,并且只能请求 (prodID=2 and catNo=10) AND (prodID=2 and catNo=20) 的行.这只是虚构的数据,我实际上无法从我的数据库中放置数据。
  • XOR 是其中之一,但不是两者。我两个都需要。
  • 不,将第二个变量从 15 更改为 12,它返回 1 行而不是无。抱歉,感谢您仍在尝试。
【解决方案3】:

使用下面的 SQL 查询。

SELECT * FROM myTable where prodID = 2 and (catNo = 10 OR catNo = 15)

希望对你有帮助

【讨论】:

    【解决方案4】:

    试试这个吧:

    SELECT * FROM `myTable` WHERE `prodID` = '2' AND `catNo` IN ('10','15')
    

    【讨论】:

      【解决方案5】:

      要匹配同一产品的两个类别,您可以这样做

      select t.*
      from table1 t
      join (
      select prodID
      from table1
      where catNo in (10,15)
      and prodID = 2
      group by prodID
      having count(distinct catNo ) = 2
        ) t2
      using(prodID)
      where t.catNo in (10,15)
      

      DEMO

      【讨论】:

      • 感谢您的所有努力并添加证明您的解决方案有效的证据,您的解决方案是迄今为止我所要求的唯一解决方案。我有另一个解决方案 here 没有加入
      • 我仍然无法理解为什么这不起作用 WHERE (prodID = 2 and catNo = 10) AND (prodID = 2 and catNo = 15)?谁能解释一下?
      • @OliverNilsen 当对行逐一应用过滤器时,此子句不满足,因为单行不能同时具有这些值之一
      【解决方案6】:
       SELECT DISTINCT a.*,b.catNo,c.catNo FROM myTable AS a
       JOIN mytable AS b ON b.prodID=a.prodID
       JOIN mytable AS c ON c.prodID=a.prodID
       WHERE a.prodID=2 AND b.catNo=10
       AND c.catNo=15;
      

      这个成功了。这个问题真的很棘手。

      【讨论】:

      • 我在这里运行了你的,由于连接,我得到了包含 prodID=2 的所有三行。如果您说“SELECT DISTINCT a.* FROM myTable AS a”http://www.sqlfiddle.com/#!2/6a8fe/6,您会得到相同的结果
      【解决方案7】:

      谢谢M Khalid Junaid's answer 的作品。我已经设法提出了一个不需要连接的解决方案,对于像我这样的非常大的表来说,它会相当慢:

      select * 
      from myTable 
      where ((prodID = 2 and catNo = 10) or (prodID = 2 and catNo = 15)) 
      group by catNo
      having (
              select count(distinct(catNo))
              from myTable 
              where ((prodID = 2 and catNo = 10) or (prodID = 2 and catNo = 15))
      )=2;  
      

      【讨论】:

      • 这样,如果您的数据库中有 2 行 catno=10 而不是 catno=15 的任何人,您将获得结果,因为 catno=10 的行数将为 2,这不是正如你所说的那样。
      • proID 和 catNo 的组合将是唯一的。但我明白你在说什么。如果我有两行带有 prodID =2 和 catNo = 10 的值,但没有 prodID =2 和 catNo = 15 的行
      • @PeterDarmis 我已经考虑到您的观点并修改了我的解决方案。如果有两行具有相同的信息,则此方法现在有效。
      • @PeterDarmis 如果我们处理的不是唯一的 'prodID' 和 'cat' 组合,但仍然需要存在 10 只猫和 15 只猫,则可以删除 'group by'为了获得“所有”行,即多于两行。
      【解决方案8】:

      发布的大多数解决方案都缺少关于不返回任何内容的部分,除非同时满足两个条件。因此,如果满足一个且仅一个条件,大多数解决方案将失败,因为它们仍将返回一行而不是无。

      假设您希望能够检查任意数量的 WHERE 条件,而不仅仅是两个,您可以使用基于子查询的解决方案。

      使用这种方法,您可以在输出之前检查结果集中符合条件的行数。有几种方法可以做到这一点,但想法是将符合条件的行数与您的预期行数进行比较。如果它们匹配,则输出行。如果它们不匹配,则返回一个空结果集。

      M Khalid Junaid 发布了一个解决方案,该解决方案使用 group by 在子查询中具有条件,以检查结果集大小是否为 2。此解决方案适用于您的特定示例和其他类似示例。如果您的 WHERE 条件变得更加复杂或多变,则可能不会,因为它依赖于 ProdID 在每个 WHERE 条件中都相同,但主体是合理的。此外,此特定方法需要针对源表处理 WHERE 条件两次,而下面的方法只处理一次。对于非常大的表和/或许多 WHERE 条件,此方法应该更有效。

      您可以像其他示例一样直接在 FROM 条件中构造子查询,也可以通过 WITH 语句构造子查询。我在这里使用了后者,因为它更清楚地显示了正在发生的事情:

      With ResultSet as (select * from myTable
              where (prodID = 2 AND catNo = 10) OR (prodID = 2 AND catNo = 15)), -- your WHERE condition
          TotalRows as (select COUNT(*) as TRows from ResultSet) -- count of result set
      select ResultSet.*
      from ResultSet
          inner join TotalRows on 1=1 -- force the join to work no matter what the tables contain
      where TRows = 2 -- this is where you check against how many result rows you expect
      

      “ResultSet”子查询是您的 WHERE 原因所在,它可以根据需要简单或复杂。 “TotalRows”对结果集进行计数,因此只包含一行。然后,您将子查询连接在一起,但仅在结果集计数 (TRows) 与您预期的后者行大小匹配时才输出前者的行。

      【讨论】:

        【解决方案9】:

        您可以尝试编写一个函数。很长,但很容易理解

        DROP FUNCTION getIt();
        CREATE OR REPLACE FUNCTION getIt()
        RETURNS TABLE (prodID INTEGER, catNo INTEGER, variable1 TEXT, variable2 TEXT) AS
        $BODY$
        BEGIN
          IF (CAST ((SELECT "prodID" 
             FROM "myTable" 
             where "prodID"=2 and "catNo" = 10) AS INTEGER)>0 AND CAST ((SELECT "prodID" 
             FROM "myTable" 
             where "prodID"=2 and "catNo" = 15) AS INTEGER)>0)
          THEN RETURN QUERY SELECT * 
             FROM "myTable" 
             where "prodID"=2 and ("catNo" = 10 or "catNo" = 15 );
          END IF;
        END;
        $BODY$ 
        LANGUAGE 'plpgsql';
        SELECT * FROM getIt();
        

        可以参数化

        DROP FUNCTION getIt(pid integer, cid1 integer, cid2 integer);
        CREATE OR REPLACE FUNCTION getIt(pid integer, cid1 integer, cid2 integer)
        RETURNS TABLE (prodID INTEGER, catNo INTEGER, variable1 TEXT, variable2 TEXT) AS
        $BODY$
        BEGIN
          IF (CAST ((SELECT "prodID" 
             FROM "myTable" 
             where "prodID"=$1 and "catNo" = $2) AS INTEGER)>0 AND CAST ((SELECT "prodID" 
             FROM "myTable" 
             where "prodID"=$1 and "catNo" = $3) AS INTEGER)>0)
          THEN RETURN QUERY SELECT * 
             FROM "myTable" 
             where "prodID"=$1 and ("catNo" = $2 or "catNo" = $3 );
          END IF;
        END;
        $BODY$ 
        LANGUAGE 'plpgsql';
        SELECT * FROM getIt(2, 10, 15);
        

        【讨论】:

        • 您能否详细记录一下这个函数的设计目的以及它是如何实现的?
        • 此函数旨在为给定的参数值从表 myTable 中获取适当的内容。如果表中有两行,它会返回这两个所需的行。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-28
        • 1970-01-01
        相关资源
        最近更新 更多