【问题标题】:How to add multiple AND's and BETWEEN's correctly in a SQL query?如何在 SQL 查询中正确添加多个 AND 和 BETWEEN?
【发布时间】:2018-12-21 15:23:32
【问题描述】:

我正在尝试构建具有多个依赖项的过滤器函数,但是当我向 SQL 查询添加 AND 时,似乎没有找到任何结果,但如果我在 AND 之前和之后使用查询进行搜索,则正确结果找到了。

我尝试构建一个过滤功能,让用户可以在范围之间进行过滤,例如:价格:100 美元到 200 美元之间,平方英尺介于 30 到 80 美元之间。

我的方法是这样的:

SELECT * FROM 'tableXY' WHERE value BETWEEN 100 AND 200 AND key ='price' 
AND value BETWEEN 2 AND 5 AND key = 'rooms'
AND value BETWEEN 40 AND 80 AND key = 'sqft'......and so on.

该表包含列 id、foreign_id、key 和 value。行中的键是价格、平方英尺、房间、地址等。 如果我过滤价格 x 和价格 y 之间的某个价格范围以及 n 个房间和 m 个房间之间的房间,它应该只返回设置的每个过滤器适用的结果。

我的方法没有找到结果,如果我使用 OR 而不是 AND,它还会显示其他过滤器不适用的结果。

【问题讨论】:

  • 请提供样本数据和期望的结果。
  • 你可能想要OR value... 而不是AND value...

标签: mysql sql database phpmyadmin


【解决方案1】:

似乎您需要在valuekey 的每对条件之间进行逻辑or 操作:

SELECT *
FROM   tableXY
WHERE  (value BETWEEN 100 AND 200 AND key ='price' ) OR 
       (value BETWEEN   2 AND   5 AND key = 'rooms') OR
       (value BETWEEN  40 AND  80 AND key = 'sqft' ) -- etc...

注意:由于and 的优先级高于or,因此圆括号不是必需的,但它们确实使查询更易于阅读。

【讨论】:

  • 感谢您的回答,但如果我使用 OR,它还会向我显示其他条件不适用的结果。
【解决方案2】:

我认为您想要聚合,因为值位于不同的行中:

SELECT something
FROM tableXY
GROUP BY something 
HAVING SUM( value BETWEEN 100 AND 200 AND key ='price' ) > 0 AND
       SUM( value BETWEEN 2 AND 5 AND key = 'rooms' ) > 0 AND
       SUM( value BETWEEN 40 AND 80 AND key = 'sqft' ) > 0 AND
       ......and so on.

【讨论】:

    【解决方案3】:

    如果你以类似的方式使用联合:

    QueryWithRoomCostFilter UNION  QueryWithRoomSizeFilter
    

    然后发生的情况是,它获取与您的成本过滤器 100$-200$ 匹配的元组集并将它们添加到结果集中,然后它将使用 40-80 平方英尺房间大小的过滤器评估第二个查询,并且将这些元组添加到结果集中,有效地组合(取并)两个结果。在这种情况下,您可以看到 union 正在工作,就好像您的条件之间存在 OR 一样。

    我不经常使用 value 和 between,但也许可以尝试一些类似的方法,如果它仍然不起作用,请告诉我们。

    SELECT * 
    FROM table_name
    WHERE (price BETWEEN 100 AND 200)
    AND (rooms BETWEEN 2 AND 5)
    AND (sqft BETWEEN 40 AND 80)
    

    【讨论】:

      【解决方案4】:

      解决方案 1:在不同键值的条件之间使用 or

      SELECT * FROM 'tableXY' WHERE (value BETWEEN 100 AND 200 AND key ='price') 
      OR (value BETWEEN 2 AND 5 AND key = 'rooms')
      OR (value BETWEEN 40 AND 80 AND key = 'sqft')......and so on.
      

      方案二:你需要使用case when

      SELECT * FROM 'tableXY' 
      WHERE 1 = (
       case 
        when key ='price' and value BETWEEN 100 AND 200 
           then 1
        when key ='rooms' and value BETWEEN 2 AND 5
           then 1
      .....
        else 0
       end
      ) 
      

      这就是您的初始子句未找到记录的原因。您在条件集之间使用AND 的初始方法基本上选择 WHERE ... value BETWEEN 2 AND 5 AND... value BETWEEN 40 AND 80 显然没有结果

      【讨论】:

      • 感谢您的回答,但如果我使用 OR,它还会向我显示其他条件不适用的结果。
      • 哦,我现在明白了。我将编辑我的答案,@DanielJohnKerschl
      • 感谢您的回答,谢谢@GabiM,我刚刚尝试过,但它仍然忽略了第一个条件,因为它正在寻找其中一个 CASEes 适用的每个结果。
      • 您能否在您的问题中添加一个具体示例?把你的表保存的一些数据、你尝试的查询、你得到的结果和你期望的结果放在一起
      【解决方案5】:

      如您的帖子所示,使用键值对表,您的数据采用 long 格式,其中不同单位类型的数据值和指标位于两列中:key。因此,每个AND 条件都试图选择一对 keyvalue 逻辑条件,并且不能同时满足所有条件,除非像 price 这样的值, roomssqftwide 格式存储在其特定列中。

      长期解决方案

      关于在关系数据库中使用诸如 SO post 之类的实体属性值模型存在一个长期争论不休的问题。有效过滤相互包含的条件的长期解决方案是将表重新设计为宽格式,其中值位于它们自己的列中,并且使用AND 条件更容易查询。

      CREATE TABLE tableXY (
          `price` DOUBLE,
          `room` INT
          `sqlft` INT,
          ... OTHER indicators ...
      );
      
      SELECT * 
      FROM tableXY 
      WHERE `price` BETWEEN 100 AND 200
        AND `rooms` BETWEEN 2 AND 5
        AND `sqft` BETWEEN 40 AND 80
      

      短期解决方案

      但现有长格式的短期解决方案是运行条件聚合以创建值的“伪列”:priceroomssqft。为任何静态属性(名称、位置、时间等)添加GROUP BY

      CREATE TABLE tableXY (
          `key` VARCHAR(10),
          `value` INT
      );
      
      SELECT sub.* 
      FROM 
         (SELECT CASE WHEN `key` = 'name' THEN `key` ELSE NULL END AS `name`,
                 SUM(CASE 
                         WHEN `key` = 'price'
                         THEN `value`
                         ELSE NULL
                     END) AS price,
                 SUM(CASE 
                         WHEN `key` = 'rooms' 
                         THEN `value`
                         ELSE NULL
                     END) AS rooms,
                 SUM(CASE 
                         WHEN `key` = 'sqlft' 
                         THEN `value
                         ELSE NULL
                     END) AS sqft,
      
                 -- ...other values...
      
           FROM tableXY
      
           GROUP BY CASE WHEN `key` = 'name' THEN `key` ELSE NULL END
        ) AS sub
      
      WHERE sub.price BETWEEN 100 AND 200
        AND sub.rooms BETWEEN 2 AND 5
        AND sub.sqft BETWEEN 40 AND 80
      

      【讨论】:

        猜你喜欢
        • 2014-06-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多