2012-01-26 9 views
1

Каждый из моих пользователей имеет определенное количество слотов для хранения. Они могут удаляться из любого слота и есть максимальное количество слотов (еще не определено, но будет где-то в диапазоне от 30 до 100). Поэтому, если пользователь имеет элемент в своих первых 5 слотах, а затем они удаляют из слотов 4 и 2. У них будут предметы, все еще находящиеся в слотах 0, 1, and 3. Я хочу найти их первый пустой слот, поэтому в этом примере: слот 2.Как сгенерировать набор целых чисел в MySQL

Я открыл для себя способ сделать это, но он кажется хакером и может быть оптимизирован.

Это, как я в настоящее время сделать это:

// 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), пока не будет найден первый пустой слот.

Есть ли они лучше, или есть ли другой способ, который лучше?

+1

Это, кажется, случай «если все, что у вас есть, это молот». Не будет ли вам легко использовать язык программирования для генерации ваших данных, а не для использования sql? –

+1

Я должен согласиться с адрианом. Это больше похоже на «я могу назвать эту мелодию в одном запутанном запросе», а не законное решение для набора чисел, даже если конечный результат заключается в том, чтобы прокормить их в ваш db. – atxdba

+0

Хотя друг показал мне какой-то номер MS sql, который мог бы заполнить таблицу последовательных номеров крутым трюком. –

ответ

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 с фактический идентификатор пользователя и максимальный номер слота, и это даст вам первый доступный слот для этого пользователя, или нет строк, если каждый слот заполнен.

0

Я думаю, вы, возможно, думаете об этом. Зачем следить за последовательностью, просто полагаться на общее количество используемых/неиспользуемых слотов и выполнять свои операции на основе первичного ключа. Если вы каждый раз беспокоитесь о запросе на подсчет, а затем храните номер, используемый в таблице пользователя.

+0

Должен знать первый пустой слот, если есть несколько пустых слотов. Но пустые слоты могут быть разбросаны по всей таблице хранения из-за удалений. – Paulpro

+0

Ну, это мой вопрос ... почему слоты имеют значение за пределами того факта, что они вышли из слотов? – prodigitalson

+2

Возможно, Пол хочет заполнить * первый * слот новым значением. –

0

UNTESTED: Но концепция кажется правильным ...

Select min(a.`rNum`) 
FROM (Select `slot`,@rownum:[email protected]+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 

Так внешний вернется

Обновлено обратиться RowNum = null взят с: http://blog.gomilko.com/2007/04/28/mysql-rownum-imitation

+0

Интересная идея, но ваш '@ rownum' будет NULL, чтобы начать, а добавление одного в NULL дает вам NULL. –

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.

Смежные вопросы