我的每个用户都有一定数量的存储空间。他们可以从任何插槽中删除并且有最大数量的插槽(尚未确定,但将在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之间的每个整数的行,并使用它代替子查询,或其中哪一个更好,还是有其他方式更好?
答案 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