Запрос предложения входа в систему

Я хочу предложить вход в систему пользователя, если их предпочтительный вариант был уже взят. Предположим, пользователь хотят зарегистрироваться как "Супермен". Уже существует, некоторые Суперукомплектовывают на сайте. Логины предлагаются в форме "Superman01", "Superman02" и так далее. Так, сценарий должен:

  • проверьте на вход в систему 'Супермена' в дб
  • если уже используется, добавьте '01', чтобы войти и проверить на него в DB
  • если уже используется, инкрементный счетчик ('02'), добавляют, чтобы войти и проверить снова
  • когда нетребуемый вход в систему будет найден, возвратите его пользователю

Что я не люблю в этой схеме, прямо сейчас то, что требуется несколько запросов к базе данных MySQL. Там какой-либо путь состоит в том, чтобы получить сначала невостребованный вход в систему сразу? Возможно, с хранимой процедурой или умным SQL-запросом?

UPD: предлагаемый щедрость

12
задан Carlos Gutiérrez 25 January 2010 в 08:16
поделиться

11 ответов

Пользователь Regexp Чтобы найти необходимые совпадения:

SELECT .. FROM users WHERE username REGEXP '^superman[0-9]{1,2}'

Это вернет все имена пользователей в виде «SuperManx» или «SuperManxx» (одна или две цифры).

После получения ваших результатов вы можете легко найти номер следующего строки или отсутствующие.

Для получения дополнительной информации прочитайте следующее:

http://dev.mysql.com/doc/refman/5.0/en/pattern-matching.html

http://dev.mysql.com/ doc / refman / 5.0 / ru / regexp.html


Редактировать

Предполагающее, что таблица называется «пользователям», и рассматриваемое поле называется «имя пользователя», возможный код приблизится:

/**
 * Checks a given name exists at the users table
 * and returns possible alternatives
 * or an empty string if no alternatives can be found
 */
function CheckUsername($name);
    // sanitize
    $query = sprintf("SELECT username FROM users
            REGEXP '%s[0-9]{0,2}' ORDER BY username",
            mysql_real_escape_string($name));

    $result = mysql_query($query);

    // get all possible matches
    $rows = array();
    while (list($match) = mysql_fetch_row($result)) {
        $rows[] = $match;
    }

    if (count($rows) == 0) {
        // no rows found, return the original name
        return $name;

    } else {
        // found multiple rows

        if ($rows[0] != $name) {
            // first check if the original name exists
            return $name;

        } else {
            // else go through each number until we find a good username
            $count = 1;
            while ($counter < count($rows) {
                $test = sprintf("%s%02d", $name, $counter);
                if ($rows[$counter] != $test) return $test;
                $counter++;
            }
        }
    }

    // nothing found
    return '';
}

Я надеюсь это помогает.

4
ответ дан 2 December 2019 в 04:25
поделиться

Graphviz содержит реализации нескольких различных подходов к решению этой задачи; рассмотрите возможность использования инструментов компоновки графика модели пружины в качестве основы для решения. Альтернативно, его сайт содержит хорошую коллекцию исходного материала по связанной теории.

-121--5044792-

От Для цикла

В некоторых языках (не C или C++) переменная цикла неизменяема в пределах объем корпуса петли, с любым попытается изменить его значение быть рассматривается как семантическая ошибка. Такой модификации иногда являются результат ошибки программиста, что может быть очень трудно идентифицировать один раз сделанный. Однако только открыто изменения, вероятно, будут обнаружены компилятора. Ситуации, когда передается адрес переменной цикла в качестве аргумента для подпрограммы сделать его очень трудно проверить, потому что поведение рутины в целом неизвестен компилятору.

Так что это, кажется, поможет вам не сжечь руку позже.

-121--3765845-

Почему бы просто не выбрать , где войти в систему, как 'superman%' , и выполнить итерацию над результирующим набором в вашем коде?

9
ответ дан 2 December 2019 в 04:25
поделиться

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

select login from usertable where login = 'Superman';

, если строки не возвращаются, вы закончите. В противном случае вам придется проверить другие возможности:

select login from usertable where login like 'Superman%' order by login;

Теперь просто найдите вариант с наивысшим числовым суффиксом и добавьте один.

Отредактируйте:
Один запрос к БД для проверки только фактического имени быстро, но один запрос для проверки всех возможностей в большой базе данных будет медленным (не из-за тойного совпадения - это быстро, если вы проиндексированы - Но скорее загружая все эти ряды и обработку их).

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

Вы также можете кэшировать результаты этого запроса, чтобы они могли быть повторно использованы без необходимости возвращаться в БД, в следующий раз, когда кто-то выберет суперманасское имя. Просто обязательно очистите результаты, когда вы добавляете подобное имя входа в БД.

3
ответ дан 2 December 2019 в 04:25
поделиться

Перед вами хэш-таблица с указателями в записях на следующую запись в отсортированном порядке. Это очень похоже на LinkedHashMap на Java, за исключением того, что ссылки отслеживают порядок сортировки, а не порядок вставки. Вы можете реализовать это полностью, обернув LinkedHashMap и имея реализацию сортировки перенести записи из LinkedHashMap в TreeMap, а затем обратно в LinkedHashMap.

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

public class SortaSortedMap<K extends Comparable<K>,V> implements Map<K,V> {

    private LinkedHashMap<K,V> innerMap;

    public SortaSortedMap() {
        this.innerMap = new LinkedHashMap<K,V>();
    }

    public SortaSortedMap(Map<K,V> map) {
        this.innerMap = new LinkedHashMap<K,V>(map);
    }

    public Collection<V> values() {
        return innerMap.values();
    }

    public int size() {
        return innerMap.size();
    }

    public V remove(Object key) {
        return innerMap.remove(key);
    }

    public V put(K key, V value) {
        return innerMap.put(key, value);
    }

    public Set<K> keySet() {
        return innerMap.keySet();
    }

    public boolean isEmpty() {
        return innerMap.isEmpty();
    }

    public Set<Entry<K, V>> entrySet() {
        return innerMap.entrySet();
    }

    public boolean containsKey(Object key) {
        return innerMap.containsKey(key);
    }

    public V get(Object key) {
        return innerMap.get(key);
    }

    public boolean containsValue(Object value) {
        return innerMap.containsValue(value);
    }

    public void clear() {
        innerMap.clear();
    }

    public void putAll(Map<? extends K, ? extends V> m) {
        innerMap.putAll(m);
    }

    public void sort() {
        List<Map.Entry<K,V>> entries = new ArrayList<Map.Entry<K,V>>(innerMap.entrySet());
        Collections.sort(entries, new KeyComparator());
        LinkedHashMap<K,V> newMap = new LinkedHashMap<K,V>();
        for (Map.Entry<K,V> e: entries) {
            newMap.put(e.getKey(), e.getValue());
        }
        innerMap = newMap;
    }

    private class KeyComparator implements Comparator<Map.Entry<K,V>> {

        public int compare(Entry<K, V> o1, Entry<K, V> o2) {
            return o1.getKey().compareTo(o2.getKey());
        }

    }

}
-121--3879929-

Обычно подключаемый модуль Clearcase (с RSA, я уверен, что это так) дает возможность «Найти ресурсы для добавления в систему управления версиями».. Здесь будут перечислены все файлы, которые не находятся в репозитории ClearCase.. Надеюсь, это помогло..: -)

-121--4321185-

Если вы можете изменить схему базы данных, решение будет тривиальным.

Разделите имя пользователя на два столбца: имя пользователя и username_suffix (INTEGER).

Если username_suffix равно 0, он не отображается. т.е. «superman» и «superman0» эквивалентны.

Затем можно просто

SELECT MAX(username_suffix)+1 WHERE username = 'superman'

, чтобы получить следующий доступный суффикс.

Если изменить схему базы данных невозможно, попробуйте работать вероятностно. Добавьте случайное 2-значное число; если он сталкивается с существующим пользователем, добавьте вместо него случайное 3-значное число; если это столкнется...

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

например.

superman not available, try superman39...  (Try 2 extra digits first)
superman39 not available, try superman491... (now try 1 extra digit each time)
superman491 not available, try superman8972... (up to (say) 4 digits)
superman9872 not available, try superman2758

Потенциальному пользователю не повезло бы повторить попытку несколько раз или два.


Почему-то я не видел решения @ Karl до того, как написал это. Если столбец дополнительной базы данных является лучшим решением, то он, вероятно, должен получить кредит - хотя я думаю, что это проще. Однако вероятностный подход имеет для меня гораздо больше смысла.

2
ответ дан 2 December 2019 в 04:25
поделиться

MathWorks делают Генератор отчетов Toolbox , который позволяет стимулировать ваш выход - в основном это очень привлекательная версия функции .

-121--4904218-

Согласно комментариям к вопросу, является желаемым фиксированным диапазоном 00 - 99 . Вы могли бы рассмотреть возможность сделать SELECT MAX () на последних двух частях имени.

SELECT max(convert(substring(name, char_length(username)-1, 2), signed)) AS max
    FROM user 
    WHERE name LIKE 'superman%'

Это, однако, не содержит в обслуживании. Что если есть 99 Супермен S?

Это также не содержит потенциальных столкновений / столкновений с именами пользователей, которые уже заканчиваются цифрами, такими как 01010101 и H4xx0R1337 . Что, если уже есть Superman01 и Superman02 и новый (и невежественный) пользователя, решает зарегистрироваться в виде Superman88 , потому что S / он рождается в 1988 году; Любой следующий Superman должен стать Superman89 Superman89 , оставляя отверстие между Superman02 и Superman88 .

Трудно дать «лучший» ответ на этот конкретный вопрос. Самый безопасный Путь было бы чем-то вроде:

if (find_user($username) != null) {
    for ($i = 0; $user != null; $i++) {
        $username = $username . $i;
        $user = find_user($username);
    }
}
// Now suggest $username.

, конечно, стоит, но это не шокирует. Также подумайте снова, как часто это произойдет? Один раз в день может быть? Или раз в год, если ваш форум в среднем только 1 новый участник в день?

1
ответ дан 2 December 2019 в 04:25
поделиться

Спросите Фраза подсказки Как это:

Пожалуйста, дополнительно предоставьте фразу подсказки, которую вы хотели бы быть частью вашего имени пользователя в случае, если вы выберете, который вы выбрали, уже предпринимается кем-то другим.
Например, если ваше имя является Иосифом, тогда Джозеф, Джозеф или Джо будут приняты уже. Таким образом, вы можете обеспечить фразу намека, которая может быть одной из:

  1. вашей фамилии - например,. Смитсон - который бы предложил «Джо.смитсон»
  2. Ваш город резиденции - например. Область залива - что бы предложить «Джозефібаяреа»
  3. . Цель аккаунта - например. Разработчик - который бы предположил «Джозеф-девль»
  4. цвет - например. Синий - который бы предложил «Buejoe»
  5. ряд, который будет суффикровал, как «Joe99»

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

Особенно, поскольку служба, которую ваш сайт предоставляет, не указан.

Другим способом приближения этой проблемы состоит в том, чтобы увидеть код за теми «умными» CAPTCHAS, которые генерируют сайты, такие как Slashdot . Некоторые остроумные деввальки ;-) имеет кучу слов семантически , связанные с темой под рукой и использует эти фразы для капчи.

Этот умный / интеллектуальный капча - это немного , как Google Sets .

Кодирование ужасов также иногда показало этих смартвых катпчч.

Играйте с этими типами услуг или получите хорошую базу данных семантически связанных терминов. Затем свяжите те термины с фразой подсказки, которую вы просите пользователя поставлять.

Google легко делает это легко, потому что «все ваши поиски принадлежат Google» (TM).
У вас есть гораздо более простые задачи - вам не нужно ползать в Интернете, и вам не нужно предоставлять результаты поисковой системы или ссылки. Все, что вам нужно, это семантически база данных.

Вы можете получить один, ты выглядишь достаточно сложно онлайн.
Вы можете начать с синонимов / антонимов и т. Д.
IIRC, один такой Wordnet, но я не знаю лицензии. Так посмотрите это.


Дополнительные (необязательно, но нереагируют частично):
Я предлагаю, если вы сделаете такую ​​хорошую вещь, сделайте его Opensource.
Это будет очень полезно для других и получить отличный реп.
И обязательно публикуйте код против автоматизированных логинов для неизбежной ситуации, когда какой-то кодер без этики и множества свободного времени будет использовать семантически связанную базу данных Word Word для создания запросов на регистрацию против вашего приложения и всех других !
Боты продолжают становиться умнее и умнее.
Проверка электронной почты - это одна защита от этого - но это только в том случае, если бы эта электронная почта не может быть подорвана - что она может, если это новая электронная почта - которая продолжается все время.

Так что это значительная задача, если вы собираетесь реализовать эту идею и выпустить ее как оперативность. Тогда вы должны его защитить.

Или вы можете просто сохранить свой собственный сайт.

6
ответ дан 2 December 2019 в 04:25
поделиться

Вот что я скажу:

SELECT `login`
  FROM `usertable`
WHERE `login` LIKE 'Superman%'
ORDER BY `login` DESC
LIMIT 1;

Если запрос не вернет результатов $username = 'Superman', в противном случае:

$username = 'Superman' . (strrev(intval(strrev($result['username']))) + 1);

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


Пересмотренный SQL-запрос, в свете первого комментария Клаусбискова:

SELECT `login`
  FROM `usertable`
WHERE `login` RLIKE '^Superman[0-9]*$'
ORDER BY `login` DESC
LIMIT 1;
4
ответ дан 2 December 2019 в 04:25
поделиться

Если вы готовы хранить некоторое состояние в базе данных ...

Когда кто-то регистрирует имя пользователя Прикрепите его в «Доступном» таблице, которая имеет два столбца, «Base_name» (String) и «Next_Available» (Integer). Если кто-то регистрирует имя пользователя, которое заканчивается двумя цифрами, ищите основание (часть, предшествующая окончательному двум цифрам), и либо вставляйте его в «доступную» или обновление «Next_Wailable».

Когда кто-то входит в имя пользователя, которое недоступно, вы можете просто посмотреть его в «Доступном» таблице и выдавать базу и суффикс Next_Wailable. Это можно сделать в одном запросе.

Предостережение: если кто-то регистрирует «SuperMan93», то вы получаете только 6 дополнительных пользователей, даже если номера от 01 до 92 доступны.

2
ответ дан 2 December 2019 в 04:25
поделиться

Вот мой мягкий раствор для прививки: добавьте одну колонку Varchar (называемое, например, USERNAME_STRING_PART ) к вашей таблице пользовательской таблицы для хранения строковых частей имени пользователя и столбца в секунду ( Например, username_number_part ) для хранения числовой части. Таким образом, Superman1 разделен на «Супермен» в USERNAME_STRING_PART столбец и «1» в username_number_part . Также создайте индекс, возможно, по поводу обоих столбцов, либо только над USERNAME_STRING_PART, если вы не ожидаете большого количества дублирующихся записей USERNAME_STRING_PART. Итак, в MySQL ваша таблица создания - это что-то подобное):

CREATE TABLE `users` (
  `id` int(11) NOT NULL auto_increment,
  `username` varchar(25) NOT NULL default '',
  `username_string_part` varchar(25) NOT NULL default '',
  `username_number_part` int(11) NOT NULL default 0,
  PRIMARY KEY  (`id`),
  KEY `ix_username_string_part` (`username_string_part`)
) TYPE=MyISAM AUTO_INCREMENT=1;

(Обратите внимание, что имя пользователя «Superman» имеет по умолчанию username_number_part Zero - это важно.)

Как только у вас есть Несколько записей, ваши данные будут выглядеть что-то подобное:

+----+-----------+----------------------+----------------------+
| id | username  | username_string_part | username_number_part |
+----+-----------+----------------------+----------------------+
|  1 | superman  | superman             |                    0 |
|  2 | superman1 | superman             |                    1 |
|  3 | superman3 | superman             |                    3 |
+----+-----------+----------------------+----------------------+

, тогда это случай выбора минимального значения username_number_part , который не имеет username_number_part значение "сама плюс один" в базе данных. Так что для имени пользователя «Superman»:

select min(username_number_part) + 1 as min_number_available from users
    where username_string_part = 'superman' and username_number_part not in
    (select username_number_part - 1 from users where
        username_string_part = 'superman');

возвращаемое значение, min_number_available , это null , если это первый экземпляр этого имени пользователя - чтобы они могли иметь его - или целое число Для следующего свободного слота в противном случае. Затем вы построите рекомендуемое имя пользователя AS «Супермен» + MIN_NUMBER_AVAILABLABLABLABLABLABLABLABLE . Вы могли бы сделать Concat в запросе или не так, как вам нравится. При примере данных выше вы получите значение «2».

Даунсид: Он собирается добавить хранилище (столбец и индекс), и замедлить вставки очень незначительно. Это также не естественно различает «Superman001» и «Superman01». (Хотя это может быть, если вы относились к ведущим нулям как часть USERNAME_STRING_PART , поэтому «Superman001» будет разделен как «Superman00» и «1».)

APSIDES: это единственный запрос на индексированные столбцы Отказ

После всего этого, я был бы удивлен, если у сайта было так много дубликатов имени пользователя, которые выполняют петлю для цикла с несколькими вариантами базы данных, было действительно все такое плохое.

2
ответ дан 2 December 2019 в 04:25
поделиться

Большинство из этих ответов верны, но сложный код запрошенного имени пользователя в операторе SQL.

SELECT MAX(SUBSTR(user,LENGTH('{$request}')+1))+1
FROM users
WHERE username LIKE '{$request}%'

вернет подходящий суффикс (NULL, если имя пользователя уже не используется)

c.

0
ответ дан 2 December 2019 в 04:25
поделиться

Запрос ниже использует вспомогательную таблицу с 10 записями (цифры от '0' до '9') и перекрестное соединение для создания списка строк от '00' до '99'. Эти значения соединены с выбранным пользователем логином ("супермен"), и результат проверки - NOT IN ваша таблица текущих пользователей. Окончательный результат - список возможных имен пользователей ("superman00" - "superman99"), которые в настоящее время не используются. Вы можете показать пользователю несколько из них на выбор. Я протестировал на TSQL, должно быть легко перевести на MySQL (я думаю, вы должны заменить 'superman'+T.i+U.i на CONCAT('superman',T.i,U.i)):

--- prepare a digits table
 create table digits (i char(1));
 insert into digits (i) values ('0')
 insert into digits (i) values ('1')
 insert into digits (i) values ('2')
 insert into digits (i) values ('3')
 insert into digits (i) values ('4')
 insert into digits (i) values ('5')
 insert into digits (i) values ('6')
 insert into digits (i) values ('7')
 insert into digits (i) values ('8')
 insert into digits (i) values ('9')

--- This query returns all 'superman00' to 'superman99' records currently not used

SELECT 'superman'+T.i+U.i AS suggestedlogin
  FROM digits T cross join digits U
  WHERE 'superman'+T.i+U.i NOT IN (
    SELECT login FROM usertable
  )

(Идея кросс-сочетания с http://www.tek-tips.com/viewthread.cfm?qid=755853)

.
1
ответ дан 2 December 2019 в 04:25
поделиться
Другие вопросы по тегам:

Похожие вопросы: