2014-12-22 6 views
2

У меня есть столбец SQL, который выглядит так.Как получить следующий открытый номер?

enter image description here

Обратите внимание, как есть номера в 1100-х и 2000-е годы (1101 - 1123 не показывают, но они существуют). Я написал сценарий, чтобы сделать так, чтобы пользователи, подписавшиеся на определенную группу, получили логин, соответствующий этой группе. Итак, если они регистрируются в основной группе, им предоставляется первый доступный логин в 1100-х годах. Если они регистрируются в умеренной группе, то они получают первый доступный логин в 2000-х годах. Скажем, что пользователь AAL2002 удален, следующий человек для присоединения должен принять вход 2002, а не 2007 (чтобы пробелы были автоматически заполнены).

Прямо сейчас у меня есть PHP-скрипт, который пытается просмотреть все и дать им новый, неиспользуемый логин. Проблема в том, что он дублирует некоторые логины. Есть ли другой способ сделать это с PHP и SQL?

Вот мой ужасный, запутанным код, если вы думаете, что может быть исправлено:

$husers = Query::runQuery("SELECT * FROM `users` WHERE `group`=? AND `login` NOT BETWEEN 'AAL1000' AND 'AAL1010'", array($post['group'])); 
      $i = 0; 
      $f = false; 
      do 
      { 
       $baseid = (substr($users[$i]['login'], 3)) + 1; 

       if($baseid != substr($users[$i+1]['login'], 3)) 
       { 
        $checkid = Query::runQuery("SELECT * FROM `users` WHERE `login`=?", array("AAL".$baseid)); 

        if($checkid[0]['login'] != "AAL".$baseid) 
        { 
         $f = true; 
        } 

       } 

       $i++; 
      } 
+3

Было бы проще, если бы у вас было число в столбце INTEGER. – Barmar

+0

@Barmar Это часть проблемы. – ChrisRockGM

+0

Ни один из двух ответов не помог мне. – ChrisRockGM

ответ

0

Это не будет работать вообще, если у вас есть более одного пользователя, регистрирующий одновременно (состояние гонки). Вы можете обойти это, используя транзакции базы данных. Кроме того, вам необходимо найти и зарегистрировать следующий бесплатный идентификатор для своего пользователя с помощью функции SQL. Вместе с транзакциями это даст вам решение, которое также работает, даже если ваш скрипт вызывается более чем одним человеком за раз.

В mysql, как правило, просто используется и автоматически увеличивать колонку, чтобы избежать такой проблемы. В большинстве других баз данных, и если вы не используете непрерывный целочисленный столбец, вам придется идти сложным путем.

+1

сделки не помогают. просто сделайте столбец уникальным. –

+0

Он все равно будет переопределять пользователей, если два скрипта выполняются одновременно и могут получить один и тот же идентификатор. Вот почему требуется блокировка, и самый простой способ - использовать транзакции. – pgampe

+0

1) вы не можете перезаписать 'insert'. 2) транзакции не решают проблему. если вы хотите * запирать *, вам нужны замки. –

0

Учитывая, что:

CREATE TABLE login (
    login VARCHAR(4) 
); 

INSERT INTO login (login) 
    VALUES ('1100'), ('1101'), ('1102'), ('1106'), ('1107'); 

Запросы:

SELECT MIN(login) + 1 AS result FROM (
    SELECT login, 
     (SELECT MIN(l2.login) FROM login l2 WHERE l2.login = l.login + 1) AS next 
    FROM login l 
    HAVING next IS NULL 
) AS list; 

дает следующий результат:

+--------+ 
| result | 
+--------+ 
| 1103 | 
+--------+ 

Мой пример использует только целую часть альфа- + десятичного поле. Это избавляет меня от необходимости делать substring operations, группируя на основе префикса («AAL11», «AAL20») и в конечном итоге (возможно, не обязательно, поскольку я демонстрирую с помощью varchar), но, тем не менее, показывает, как это сделать можно сделать. Я оставляю это как упражнение.

Как уже обсуждалось, вы можете запускать операцию поиска + вставки только вместе. Это означает, что вам нужно иметь это как атомную операцию в вашем приложении (обычно называемую транзакцией, но я не имею в виду транзакцию SQL).

+0

Я не очень разбираюсь в SQL, но думаю, это должно выглядеть так? SELECT MIN (SUBSTRING (Логин, 3, 4)) + 1 В результате из ( \t \t \t \t \t ВЫБОР SUBSTRING (Логин, 3, 4), \t \t \t \t \t \t (SELECT MIN (SUBSTRING (L2 .login, 3, 4)) ИЗ СУБСТРИРОВАНИЯ (логин, 3, 4) l2 ГДЕ СУБСТРИРОВАНИЕ (l2.login, 3, 4) = СУБСТРИРОВАНИЕ (l.login, 3, 4) + 1) AS next \t \t \t \t \t ОТ СУБСТРИРОВАНИЯ (логин, 3, 4) l \t \t \t \t \t HAVING next IS NULL \t \t \t \t) AS список – ChrisRockGM

+0

Кроме того, я понятия не имею, как сделать группировку на основе префикса. – ChrisRockGM

+0

Это не работает для меня только с номерами. – ChrisRockGM

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