如何在MySQL中生成一组整数

时间:2012-01-26 05:12:58

标签: mysql sql myisam

我的每个用户都有一定数量的存储空间。他们可以从任何插槽中删除并且有最大数量的插槽(尚未确定,但将在30 - 100范围内)。因此,如果用户在前5个插槽中有一个项目,然后他们会从插槽4和2中删除。他们的项目仍然位于插槽0, 1, and 3中。我想找到他们的第一个空插槽,所以在这个例子中:插槽2。

我发现了一种方法可以做到这一点,但它似乎有点hackish,可能会进行很多优化。

这就是我目前的做法:

// Make set of ints from 0 to max size
$slots = 'SELECT 0 as `x`';
for($i = 1; $i < $max; $i++)
    $slots .= ' UNION SELECT '.$i.' as `x`';

$q = $db->prepare(' 
    SELECT  MIN(`x`)
    FROM (
        '.$slots.'
    ) as `slots` 
    WHERE 
        `x` NOT IN (
            SELECT  `slot`
            FROM `'.$table.'`
            WHERE
                `user` = ?
            )
');

$q->setFetchMode(PDO::FETCH_NUM);
$q->execute(array($user));

因此,如果MAX = 5,查询将变为:

SELECT  MIN(`x`)
FROM (
    SELECT 0 as `x` UNION
    SELECT 1 as `x` UNION
    SELECT 2 as `x` UNION
    SELECT 3 as `x` UNION
    SELECT 4 as `x`
) as `slots` 
WHERE 
    `x` NOT IN (
         SELECT `slot`
         FROM `my_table`
     WHERE
             user = 1
)

基本上我正在生成一个子查询来创建相当于PostgreSQL的generate_series(0, MAX - 1) 就像我之前说的那样,MAX将在30到100之间。

我必须做的其他一些想法是:

  • 有一个包含一列(x)的常量表和一个介于0到99之间的每个整数的行,并使用它代替子查询,或
  • 选择所有用户的已填充存储空白,然后迭代结果(在PHP中),直到找到第一个空插槽。

其中哪一个更好,还是有其他方式更好?

4 个答案:

答案 0 :(得分:3)

您可以通过将表连接到自身来找到第一个空插槽,条件是第二个表实例的插槽编号比第一个高一个:

Select a.slot+1
From my_table a
Left Join my_table b
On (a.user = 1 and b.user = 1 and a.slot = b.slot - 1)
Where b.slot is null and a.slot < 100
Order by a.slot
Limit 1

将常量1和100替换为实际用户ID和最大插槽号,这将为您提供该用户的第一个可用插槽,如果每个插槽已满,则不会显示任何行。

答案 1 :(得分:2)

不要使用这样的“内联”表:

FROM (
    SELECT 0 as `x` UNION
    SELECT 1 as `x` UNION
    SELECT 2 as `x` UNION
    SELECT 3 as `x` UNION
    SELECT 4 as `x`
) as `slots`

构建一个名为slots的真实表,并使用1到100(或其他)的值填充一次。然后你可以做这样的事情:

select min(s.slot)
from slots s
left outer join your_table t on s.slot = t.slot and t.user = 1
where t.slot is null

获取your_table子表中第一个打开的广告位user = 1

答案 2 :(得分:0)

我想也许你在想这个。为什么跟踪序列只依赖于使用/未使用的插槽总数,并根据主键执行操作。如果您每次都担心计数查询,那么请存储用户表中使用的数字。

答案 3 :(得分:0)

UNTESTED:但这个概念似乎是正确的......

Select min(a.`rNum`) 
FROM (Select `slot`,@rownum:=@rownum+1 as rNum,userID
from `slots`, (SELECT @rownum:=0) 
order by `slot`) as A
where A.userID=1 and A.`slot`<> a.rNum

内部选择将返回

1 1 1
3 2 1
5 3 1

所以外面会返回

2

更新为解决了来自:http://blog.gomilko.com/2007/04/28/mysql-rownum-imitation

的rowNum = null