Giriş öneri sorgu

11 Cevap php

Ben onların ilk tercihi zaten alınmış eğer kullanıcı giriş önermek istiyorum. Varsayalım, kullanıcı "Superman" olarak kayıt etmek istiyorum. Bazı Süperman'ın sitede zaten var. Girişler böylece form "superman01", "Superman02" ve önerilmektedir. Yani, script gerekir:

  • db 'Superman' giriş kontrol
  • Zaten kullanıldığında, DB giriş ve bunun için kontrol etmek için ''01 append
  • Zaten eğer kullanılıyorsa, artım sayacı ('02 '), giriş eklemek ve tekrar kontrol edin
  • olmayan iddia giriş bulunduğunda, kullanıcıya geri

Ben şu anda bu şemada sevmiyorum o MySQL veritabanı birden fazla isteği almasıdır. Tek seferde ilk sahipsiz giriş almak için herhangi bir yolu var mı? Belki saklı yordam veya akıllı SQL sorgusu ile?

UPD: bir lütuf sundu

11 Cevap

Gerekli eşleşmeleri bulmak için Kullanıcı sıradanifade:

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

Bu 'supermanX' veya 'supermanXX' (bir ya da iki basamak) şeklinde tüm adlarını dönecektir.

Eğer sonuç almak sonra, kolayca sonraki sıralı numara veya eksik olanları bulabilirsiniz.

Daha fazla bilgi için, aşağıdaki okuyun:

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

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


Edit

Tabloyu düşünürsek 'Kullanıcılar' ve alan söz konusu 'username' denir denir, snipped olası bir kod aşağıdaki gibidir:

/**
 * 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 '';
}

Umarım işe yarar.

Neden sadece where login like 'superman%' seçeneğini seçin ve kod resultset üzerinde yinelemek değil?

Bir hint phrase bu gibi sorma:

Please additionally provide a hint phrase which you would like to be part of your username in case the one you choose is already taken by somebody else.
For example, if your name is Joseph, then Joseph, josef or joe would be taken already. So you can provide a hint phrase which could be one of:

  1. soyadınız - örn. Smithson - "joe.smithson" öneririm
  2. Oturduğunuz şehir - örn. Bay Area - "joseph_bayarea" öneririm
  3. hesabın amacı - örn. geliştirici - "joseph-devel" öneririm
  4. Bir renk - örn. mavi - "bluejoe" önermek hangi
  5. Bir sayı - "joe99" gibi suffixed olurdu

Bu ipucu bilgi almak için başka bir yolu kayıt formunda girilen diğer verileri birleştirmek olacaktır. Ben hemen kullanıcı gibi onun adı olarak önerilen yapacağını tahmin başka convenient and general-purpose düzeni düşünemiyorum.

Siteniz sağlayan hizmet belirtilmemiş Özellikle beri.

Bu sorunu yaklaşan bir başka yolu bu "akıllı" captchas that sites like Slashdot generate arkasındaki kodu görmek için. Bazı esprili devel ;-) deyişle semantically eldeki konuyla bağlantılı ve bir kaptan için bu ifadeler kullanan bir grup var.

Bu akıllı / zeki Captcha şey a bit Google Sets gibi.

Coding Horror de zaman zaman bu akıllı catpchas gösterdi.

Hizmetlerin bu tür etrafında oynamaya veya semantik bağlantılı açısından iyi bir veritabanı ele almak. Sonra tedarik kullanıcı sormak ipucu ifade ile bu terimleri bağlantı.

Google does this easily because "All your searches are belong to Google"(TM).
You have a much easier task - you dont have to crawl the web and you dont have to provide search engine results or links. All you need is a semantically database.

You could get one is you looked hard enough online.
You could start with synonyms/antonyms etc.
IIRC, one such is wordnet, but i don't know the license. So do look it up.


Additional (optional, but dont implement partially):
I suggest that if you make such a good thing, make it opensource.
It will be pretty helpful to others and get you a great rep.
And make sure to also publish code against automated logins for the inevitable situation where some coder with no ethics and lots of spare time will use the semantically linked open word database to generate registration requests against your app and every other !
Bots keep getting smarter and smarter.
Email verification is one protection against this - but that's only if that email service cannot be subverted - which it can, if it is a new email service - which keep coming up all the time.

Bu fikri uygulamak ve opensource olarak serbest bırakmak için gidiyoruz eğer Yani büyükçe bir görev. Sonra da korumak zorunda.

Yoksa sadece bunu kendi sitenizde tutabilirsiniz.

İşte bu benim gitmek olduğunu:

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

Eğer sorgu etmez aksi sonuçlar döndürüyor $username = 'Superman',:

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

Bu hile yapmak gerekir, ancak ben adınızı toplama düzeni büyük bir hayranı değilim söylemeliyim.


The revised SQL query, in light of klausbyskov's first comment:

SELECT `login`
  FROM `usertable`
WHERE `login` RLIKE '^Superman[0-9]*$'
ORDER BY `login` DESC
LIMIT 1;

Sen, (olması gereken) giriş alanında düzgün dizine varsayarak yapabilirsiniz:

select login from usertable where login = 'Superman';

Hiçbir satır varsa, bitirdiniz. Aksi takdirde, diğer olasılıklar için kontrol etmek gerekir:

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

Şimdi, en yüksek sayısal eki ile varyasyonu bulmak ve bir tane daha ekleyin.

EDIT:
One query to the db to check only the actual name is fast, but one query to check all possibilities in a big database will be slow (not because of the like match - it's fast if you are indexed - but rather downloading all of those rows and processing them).

Daha sonra sadece istenen isim çalışmıyor zaman tüm isimleri kontrol sorgu yaparken, adını kontrol etmek için 1 sorgu yaparken daha iyi olurdu.

Onlar size geri DB birisi supermanesque adı alır sefere gitmek zorunda kalmadan yeniden böylece de bu sorgunun sonuçlarını önbelleğe alabilir. Sadece db benzer bir giriş adı eklediğinizde sonuçlarını temizlemek için emin olun.

Eğer veritabanında bazı durumunu saklamak için istekli iseniz ...

Birisi bir kullanıcı adı kaydettirdiğinde, iki sütun, "base_name" (dize) ve "next_available" (tamsayı) olan "mevcut" tablosunda, sopa. Birisi iki basamak biten bir kullanıcı adı kaydederse, baz (son iki basamak önceki kısım) için, bakmak ve "mevcut" takın ya da "next_available" güncellemek ya.

Birisi mevcut olmayan bir kullanıcı adı girdiğinde, sadece "mevcut" tablosunda bu kadar bakmak ve üssü ve next_available soneki dışarı verebilir. Bu bir sorgu yapılabilir.

İhtar: Birisi "superman93" kaydederse numaraları 01-92 mevcut olsa bile, o zaman sadece, 6 daha fazla kullanıcıyı olsun.

İşte benim hafif kaçık çözüm: kullanıcı adı dize parçaları saklamak için kullanıcı tabloda (örneğin username_string_part denir) bir varchar sütunu ekleyin ve bir int ikinci sütun (örneğin, username_number_part) için Sayısal parçası saklayın. Yani superman1 username_number_part olarak username_string_part sütun ve "1" in "superman" ayrılmıştır. Yinelenen username_string_part girdileri çok sayıda beklemek değil de, muhtemelen iki sütun üzerinde ya da sadece username_string_part üzerinde, bir dizin oluşturabilirsiniz. Yani, MySQL, sizin oluşturmak tablo böyle bir şey) 'dir:

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;

(Kullanıcı adı "superman" username_number_part sıfır varsayılan olduğunu unutmayın -. Bu önemli)

Eğer birkaç girdileri var sonra, verileri bu gibi bir şey olacaktır:

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

Sonra username_number_part bu bir username_number_part değeri "artı kendini bir" veritabanında yok asgari değerini seçerek bir durumda bulunuyor. Adı "superman" Yani:

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');

Bu o username ilk örneği ise dönüş değeri, min_number_available, NULL - bu yüzden onlar olabilir - Aksi sonraki ücretsiz yuvası için veya bir tamsayı. Daha sonra "superman" + min_number_available olarak önerilen adı oluşturmak. İstediğiniz kadar sorguda veya concat yapabilirdi. Yukarıdaki örnekte veri değerini alırsınız ile "2" döndü.

Downsides: Bu depolama (kolon ve indeks) ekleyin ve çok hafif ekler yavaşlatmak için gidiyor. Ayrıca doğal "superman001" ve "superman01" arasında ayırım yapmaz. (Eğer username_string_part parçası olarak önde gelen sıfırları tedavi olabilir, yani "superman001" "superman00" ve "1" olarak bölünmüş olacağını rağmen.)

Upsides: bu dizine sütun üzerinde tek bir sorgu.

Bir sitenin birden çok veritabanı sorgu ile döngü için yaptığını gerçekten o kadar kötü o kadar çok adı çiftleri olsaydı bütün bunlardan sonra, ben şaşıracaksınız.

Eğer veritabanı şemasını değiştirmek durumunda çözüm saçmadır.

Kullanıcı adınızı ve username_suffix (TAMSAYI): iki sütuna adını bölünmüş.

Username_suffix 0 ise, o gösterilmez. yani 'superman' ve 'superman0' eşdeğerdir.

Daha sonra sadece can

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

sonraki ekini alır.

Eğer veritabanı şemasını değiştiremezsiniz Alternatif eğer, probabilistically çalışmayı deneyin. Rastgele 2 haneli bir numara ekler; o Varolan bir kullanıcı ile çarpıştığında, yerine rastgele bir 3 haneli sayıyı ekleyin; Bu çarpıştığında ...

Sadece herhangi bir basamak izleyen çıkardı ve ekstra rastgele rakamlar eklenir ve ilk veritabanı denetimi ile değil kullanıcının önerilen adı bir kullanıcı adı düşündüren potansiyel kullanıcıların hafif rahatsız edici küçük bir kısmını, sakıncası yoksa muhtemelen yeterince iyi çalışacaktır:

örn.

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

Bir potansiyel kullanıcı veya iki kez daha yeniden denemek zorunda gerçekten şanssız olması gerekir.


Ben bu yazdı önce nedense Karl'ın çözüm @ görmedim. İlave db sütun iyi çözüm ise, o zaman muhtemelen kredi almalısınız - Ben bu daha kolay olduğunu düşünüyorum rağmen. Ancak, olasılıklı yaklaşım bana çok daha mantıklı.

Sorusu üzerine yorumlar başı olarak, bir 00 sabit bir aralık - 99 arzu edilir. Sen adının son iki parça bir SELECT MAX() yapmak için düşünebiliriz.

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

Ancak bu bakım ücretsiz değil. 99 superman s var ne olur?

Bu da zaten 01010101 ve h4xx0r1337 gibi rakam ile biter adları ile potansiyel çarpışmalar / çatışmalar ücretsiz değildir. superman01 ve superman02 ve yeni (ve cahil) kullanıcı s / 1988'de doğdu, çünkü superman88 olarak kayıt yapmaya karar var zaten ne varsa; Herhangi bir sonraki superman superman02 ve superman88 arasında bir delik bırakır, superman89 önerilen olacaktı.

Bu özel soru üzerine bir "en iyi" cevabını vermek zor. safest yolu gibi bir şey olurdu:

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

Orada bir maliyet tabii ki, ama şok edici değil. Ayrıca tekrar düşünmek, ne kadar sıklıkla bu oluşacak? Belki günde bir kez? Ya da yılda bir kez forum günde ortalama sadece 1 yeni üye olsun?

Sorgu altında 10 kayıtları (''9' rakamı '0) ile bir yardımcı tablosunu kullanır ve bir çapraz ''99' dizeleri '00 listesini oluşturmak için katılın. Bu değerler kullanıcı seçilen girişi ('superman') ile birleştirilmiş ve sonuç geçerli kullanıcıların NOT IN tablo olarak test edilmiştir. Nihai sonuç şu anda kullanımda olmayan mümkün giriş adları ('superman99' için 'superman00') listesidir. Siz kullanıcı seçmek için bu birkaç gösterebilirim. Ben TSQL test, MySQL (ben 'superman'+T.i+U.i CONCAT('superman',T.i,U.i) ile değiştirmek zorunda düşünüyorum) çevirmek kolay olmalıdır:

--- 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
  )

(Çapraz http://www.tek-tips.com/viewthread.cfm?qid=755853 adlı bir fikrim katılmak)

Bu cevapların çoğu doğru ama sert-kod SQL deyiminde istenen kullanıcı adı vardır.

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

Uygun bir eki dönecektir (null kullanıcı adı zaten kullanılıyor değilse)

C.