在WHERE子句中限制SQL?

时间:2014-06-13 13:45:02

标签: mysql sql

是否可以在sql中的WHERE子句中设置限制?

表名:_mct_dot

列:a_ID (auto inc) number (index) qty (index) com_val

SELECT
        *
    FROM
        _mct_dot
    WHERE
        (
            number = 4
            OR
            number = 7
            OR
            number = 13
        )
        AND 
        (
            qty = 3
            OR
            qty = 5
            OR
            qty = 7
        )
    ORDER BY
        number ASC, qty ASC

所以上面的查询,它基本上会返回一个按顺序分组的数组。然而,它将拉出所有的数量'值3,5和7.我需要的是来自数量'的5个结果的样本。 3,5和7.即。我需要结果看起来像:

'number' 4's with 'qty' = 3's where 'qty' limited to max 5 
'number' 4's with 'qty' = 5's where 'qty' limited to max 5 
'number' 4's with 'qty' = 7's where 'qty' limited to max 5 
'number' 7's with 'qty' = 3's where 'qty' limited to max 5 
'number' 7's with 'qty' = 5's where 'qty' limited to max 5 
'number' 7's with 'qty' = 7's where 'qty' limited to max 5 
'number' 13's with 'qty' = 3's where 'qty' limited to max 5 
'number' 13's with 'qty' = 5's where 'qty' limited to max 5 
'number' 13's with 'qty' = 7's where 'qty' limited to max 5 

2 个答案:

答案 0 :(得分:2)

不,在WHERE子句中添加LIMIT子句是不可能的。

可以实现您想要的结果集,但是这样做的SQL并不漂亮。它需要JOIN,相关子查询或内联视图。


如果_mct_dot中的行存在“顺序”,则可以使用相关子查询来检查“拉”行之前的行数,并仅使用少于四行的行。

SELECT d.*
  FROM _mct_dot d
  JOIN ( SELECT n.number
              , q.qty
           FROM (SELECT 4 AS `number` UNION ALL SELECT 7 UNION ALL SELECT 13) n
          CROSS
           JOIN (SELECT 3 AS `qty` UNION ALL SELECT 5 UNION ALL SELECT 7) q
       ) p
    ON p.number = d.number
   AND p.qty = d.qty
   AND 5 > ( SELECT SUM(1)
               FROM _mct_dot c
              WHERE c.number = d.number
                AND c.qty = d.qty
                AND c.a_ID < d.a_ID
           )
 ORDER BY ...

相关子查询可能会被执行很多次,因此为了获得最佳性能,您需要一个包含numberqty前导列的索引,并包含{{1} }专栏。

或者:

a_id

... ON `_mct_dot` (`number`, `qty`, `a_ID`)

另一种选择是使用MySQL用户变量来模拟... ON `_mct_dot` (`qty`, `number`, `a_ID`) 分析函数,如下所示:

row_number()

(这些查询仅限桌面检查;尚未设置SQL Fiddle演示。)

<强>后续

对于第一个查询,我刚刚使用了内联视图(别名为“p”),它生成了所请求的所有SELECT t.* FROM ( SELECT d.a_ID , IF(d.number = @prev_number AND d.qty = @prev_qty , @rn := @rn + 1 , @rn := 1 ) AS rn , @prev_number := d.number , @prev_qty := d.qty FROM (SELECT @prev_number := NULL, @prev_qty := NULL, @rn := 0 ) i CROSS JOIN ( SELECT n.number , q.qty FROM (SELECT 4 AS `number` UNION ALL SELECT 7 UNION ALL SELECT 13) n CROSS JOIN (SELECT 3 AS `qty` UNION ALL SELECT 5 UNION ALL SELECT 7) q ) p JOIN _mct_dot d ON d.number = p.number AND d.qty = p.qty ORDER BY d.number, d.qty ) s JOIN _mct_dot t ON t.a_ID = s.a_ID WHERE s.rn <= 5 ORDER BY t.number ASC, t.qty ASC number值对的集合。 / p>

我们可以使用JOIN操作来查找与_mct_dot表中每对匹配的所有行。

棘手的部分是相关子查询。 (我们可以使用几种方法。)上面查询中的方法是获得具有匹配“number”和“qty”的行的“计数”,但id值小于id的值。当前行,基本上找出当前行“之前”有多少行。我们将它与文字5进行比较,因为我们只希望返回每组中的前5行。


对于第二个查询,

qty 为别名的内联视图正在初始化一些MySQL用户变量。我们并不关心查询返回什么,除了它只返回一行(因为我们在JOIN操作中引用它)...我们真正感兴趣的是在开始时初始化变量执行。这是因为MySQL在执行引用视图的外部查询之前实现了内联视图(派生表)。

内联视图别名为 i ,为我们提供了我们想要检索的p对,我们对_mct_dot使用JOIN操作来获取匹配的行。

内联视图中的“技巧”别名为 number,qty 是使用MySQL用户变量。我们正在检查当前值与前一行的值...如果数字和数量匹配,那么我们在同一个“组”中,所以我们可以将行数计数器增加1。任何一个值都会改变,那么它就是一个新组,所以我们将行号计数器重置为1,因为当前行是新组中的“第一”行。

我们可以针对内嵌视图 s 运行查询,并看到我们得到行号(s col)1,2,3等。对于每个小组。

然后,最外面的查询只过滤掉rn行号大于5的所有行。实际上,从 rn ,我们只返回行的唯一标识符;最外层的查询也在做一个JOIN操作,根据唯一的id来检索整行。


正如我在答案的顶部提到的,执行此操作的SQL并不漂亮。 (取消这些查询正在进行的操作需要花费一些工作。)

答案 1 :(得分:0)

我不确定我是否理解你的问题,因为它不是很清楚,但根据我所理解的情况,我认为你可以尝试这样的事情:

SELECT     attribute_number,
           grade_number //, other columns

FROM       _mct_dot
WHERE      (number = 4 AND qty IN (3, 5 ,7))
OR         (number = 7 AND qty IN (3, 5, 7))
OR         (number = 13 AND qty IN (3, 5, 7))
GROUP BY   attribute_number, grade_number
ORDER BY   attribute_number ASC, grade_number ASC
LIMIT      5

希望这有帮助!!!