gguntars Posted August 21, 2008 Report Share Posted August 21, 2008 Man te tāds jautājumiņš... Lietas būtība ir šāda: Ir izveidota tabula iekš MySQL, kur tiek reģistrēti sacensību dalībnieki. Lauks 'id' ir AUTO_INCREMENT un PRIMARY KEY. Lauks 'numurs' ir unikāls INT, kas pēc būtības ir dalībnieka starta numurs. Dalībniekiem starta numurs tiek piešķirts automātiski, bet tai pat laikā ir iespējams pašam izvēlēties savu īpašo numuru. Līdz ar ko šajā laukā var būt savadīti dažādi numuri, piemēram, 1,2,3,50,88 Man ir vajadzīgs dabūt nākamo neizmantoto numuru, kas tiktu piešķirts nākamajam dalībniekam, kurš neizvēlas sev īpašu numuru Šajā gadījumā numuram vajadzētu būt 4. Vai tas ir iespējams? Un galvenais KĀ? ;) Link to comment Share on other sites More sharing options...
Grey_Wolf Posted August 21, 2008 Report Share Posted August 21, 2008 (edited) Auto incrament peec savaas buutiibas ir parasts skaitiitaajs , liidz ar to nakamais numurs buus 89, bet vari vienkarshi parbaudiit vai numurs jau nav izmantots ... un ja nav tad drosi vari vinju insertot ... tb parbaudi vai numurs eksistee id ==4 , ja nee tad inserto ... savaadak nekaa... Edited August 21, 2008 by Grey_Wolf Link to comment Share on other sites More sharing options...
werd Posted August 21, 2008 Report Share Posted August 21, 2008 Ja pareizi sapratu, tad ja lietotājs(potenciālais dalībnieks) ievada numuru, tad viņš tiek reģistrēts ar šādu numuru(ja tāds jua neeksistē protams), bet ja neievada - tad automātiski viņam tiek piešķirts nākošais lielākais skaitlis sākot no mazākā(tb, 1,2,3,5 piešķirs 4). Nepārbaudīts, bet varētu izskatīties apmērmam šādi: <? $sql = mysql_query("SELECT MAX(numurs) FROM dalibnieki"); $results = mysql_fetch_row($sql); $last = $results[0];//dabujam pedejo lielako dalibnieka numuru for($i=1;$i<=$last;$i++){ $qwerty = mysql_query("SELECT id FROM dalibnieki WHERE numurs = ".$i); $count = mysql_num_rows($qwerty); if($count==1){ //ir šāds numurs, turpnam meklēt } else{ //piemeram 4 nav DB, tad mēs varam ievietot jaunu dalibnieku ar šo 4 jeb $i numuru $mysql_query("INSERT INTO dalibnieki(vards, numurs) VALUES ('".$_POST['name']."', '".$i."')"); $i = $last;//lai cikls beigtos } } ?> Link to comment Share on other sites More sharing options...
bubu Posted August 21, 2008 Report Share Posted August 21, 2008 Tik vajag atcerēties, ka visu šo select max/insert phpjāņa kodā vajag darīt vienā transakcijā - noloko sākumā tabulu un begās to atloko. Citādi sanāks vēl, ka vienlaicīgi kāds darīs to pašu un piešķirsies viens un tas pats numurs. Link to comment Share on other sites More sharing options...
codez Posted August 21, 2008 Report Share Posted August 21, 2008 (edited) Man sanāca ar 1 kveriju. Tabulā a tiek atrasts pirmais brīvais id; SELECT g FROM (SELECT id,@i:=@i+1 as g FROM (select @i:=0) as t,a) as t WHERE g<>id LIMIT 1 EDIT: šis varētu būt ātrāks: SELECT @i as g,id FROM (select @i:=0) as t,a having (@i:=@i+1)<>id LIMIT 1 ; atbilde izvada divas kollonas, jāņem pirmā. EDIT: P.S. id protams ir primary key, ja nav, tad derētu takā vēl order pēc id taisīt: SELECT @i as g,id FROM (select @i:=0) as t,a having (@i:=@i+1)<>id order by id LIMIT 1 ; Edited August 21, 2008 by codez Link to comment Share on other sites More sharing options...
Gints Plivna Posted August 21, 2008 Report Share Posted August 21, 2008 Tā kā neesmu MySQL specs uz potenciāliem mysql mainīgo gļukiem u.c. nezināmām lietām, tad jūtieties brīvi kritizēt, bet man uz pāris piemēriem strādā: mysql> create table numuri(a int); Query OK, 0 rows affected (0.13 sec) mysql> insert into numuri values (1); Query OK, 1 row affected (0.05 sec) mysql> insert into numuri values (2); Query OK, 1 row affected (0.03 sec) mysql> insert into numuri values (4); Query OK, 1 row affected (0.03 sec) mysql> insert into numuri values (6); Query OK, 1 row affected (0.01 sec) mysql> select * from numuri; +------+ | a | +------+ | 1 | | 2 | | 4 | | 6 | +------+ 4 rows in set (0.01 sec) Kā redzams nākošās mazākās vērtības ir 3, pēc tam 5, pēc tam būtu jābūt 7: Skatamies ko darīs šis te: mysql> insert into numuri -> select min(salidz) FROM ( -> SELECT IF(rownum - a = 0, null, rownum) salidz FROM ( -> SELECT @rownum:=@rownum+1 rownum, a -> FROM (SELECT @rownum:=0) r, numuri -> ORDER BY a) q -> UNION ALL select max(a)+1 FROM numuri) q1; Query OK, 1 row affected (0.03 sec) Records: 1 Duplicates: 0 Warnings: 0 mysql> select * from numuri; +------+ | a | +------+ | 1 | | 2 | | 4 | | 6 | | 3 | +------+ 5 rows in set (0.00 sec) mysql> insert into numuri -> select min(salidz) FROM ( -> SELECT IF(rownum - a = 0, null, rownum) salidz FROM ( -> SELECT @rownum:=@rownum+1 rownum, a -> FROM (SELECT @rownum:=0) r, numuri -> ORDER BY a) q -> UNION ALL select max(a)+1 FROM numuri) q1; Query OK, 1 row affected (0.03 sec) Records: 1 Duplicates: 0 Warnings: 0 mysql> select * from numuri; +------+ | a | +------+ | 1 | | 2 | | 4 | | 6 | | 3 | | 5 | +------+ 6 rows in set (0.00 sec) mysql> insert into numuri -> select min(salidz) FROM ( -> SELECT IF(rownum - a = 0, null, rownum) salidz FROM ( -> SELECT @rownum:=@rownum+1 rownum, a -> FROM (SELECT @rownum:=0) r, numuri -> ORDER BY a) q -> UNION ALL select max(a)+1 FROM numuri) q1; Query OK, 1 row affected (0.01 sec) Records: 1 Duplicates: 0 Warnings: 0 mysql> select * from numuri; +------+ | a | +------+ | 1 | | 2 | | 4 | | 6 | | 3 | | 5 | | 7 | +------+ 7 rows in set (0.00 sec) Man izskatās ka strādā. Ideja par rownum ģenerēšanu no šejienes trešais komentārs no augšas. Pārējais no manis :) P.S. Nav ne jausmas kā tas strādā uz daudz datiem. P.P.S. Protams, ka jāatceras, ka ja vienlaicīgi darbojas vairāki lietotāji, tad pastāv risks, ka 2 var ielikt vienu un to pašu, bet tur acīmredzot vienkārši ir jāuzliek UK ierobežojums, kas arī to aizliegs. Gints Plivna http://datubazes.wordpress.com Link to comment Share on other sites More sharing options...
Gints Plivna Posted August 21, 2008 Report Share Posted August 21, 2008 Man sanāca ar 1 kveriju. Pietrūkst gadījums, kad idiem pa vidu nav cauruma ;) Gints Plivna http://datubazes.wordpress.com Link to comment Share on other sites More sharing options...
codez Posted August 21, 2008 Report Share Posted August 21, 2008 nu, ok! tagad ir arī pēdējais. SELECT IF((@i=c) and (@i=id),@i+1,@i) as g,id,c.c FROM (select @i:=0) as t,(SELECT count(id) as c from a) as c,a having (@i:=@i+1)<>id OR (@i=c) order by id LIMIT 1 Doma sekojoša: selektojam tabulu a un pie katra rowa palielinam maniīgo @i par viens. Ja kādā brīdī @i<>id, tad selektojam, vai arī pašās beigās, ja nonākam līdz pēdējajam (@i=c) un tas izrādās arī vienāds ar id "and (@i=id)" , tad arī selektojam, bet tad selektojām @i+1 ar IF((@i=c) and (@i=id),@i+1,@i) Link to comment Share on other sites More sharing options...
codez Posted August 21, 2008 Report Share Posted August 21, 2008 (edited) tad jūtieties brīvi kritizēt rownum - a = 0 ir rownum = a Sekojošais apakškverijs sākumā uzbūvē tabulu, no visiem rowiem. Ja būs daudz ierakstu, bet tukš id bieži atradīsies sākumā, tad tiks veikta daudz liekas darbības. SELECT @rownum:=@rownum+1 rownum, a FROM (SELECT @rownum:=0) r, numuri ORDER BY a Un otrs sekojošais apakškverijs vēlreiz būvē tabulu, no visiem rowiem. SELECT IF(rownum - a = 0, null, rownum) salidz FROM ( SELECT @rownum:=@rownum+1 rownum, a FROM (SELECT @rownum:=0) r, numuri ORDER BY a) q Kamēr manā variantā netiek būvēta tabula no atmetamajiem rezultātiem un pie tam selektošana apstājas, pie pirmā derīgā atrastā id. Edited August 21, 2008 by codez Link to comment Share on other sites More sharing options...
bubu Posted August 21, 2008 Report Share Posted August 21, 2008 Kā būtu ar šādu kveriju? SELECT IFNULL(MIN(id)+1, 1) FROM tabule AS t WHERE NOT EXISTS (SELECT id FROM tabule WHERE id = t.id+1) Link to comment Share on other sites More sharing options...
codez Posted August 21, 2008 Report Share Posted August 21, 2008 (edited) SELECT IFNULL(MIN(id)+1, 1) FROM tabule AS t WHERE NOT EXISTS (SELECT id FROM tabule WHERE id = t.id+1) Nezinu, kā mysql šādus optimizē, bet otrā selektošana varētu būt O(log2(N)) un tā ir jādara N reizes. Kopā O(N log2(N)). Kamēr manā variantā ir O(K), kur K ir pirmā neaizņemtā id vieta un K<=N+1 Edited August 21, 2008 by codez Link to comment Share on other sites More sharing options...
Gints Plivna Posted August 21, 2008 Report Share Posted August 21, 2008 Doma sekojoša: selektojam tabulu a un pie katra rowa palielinam maniīgo @i par viens. Ja kādā brīdī @i<>id, tad selektojam, vai arī pašās beigās, ja nonākam līdz pēdējajam (@i=c) un tas izrādās arī vienāds ar id "and (@i=id)" , tad arī selektojam, bet tad selektojām @i+1 ar IF((@i=c) and (@i=id),@i+1,@i) Izklausās forši :) Man ar' diez ko tie apakšselekti nepatika, bet šāda ideja prātā neienāca, pie tam šī bija pirmā reize, kad rakstīju MySQL selektu ar mainīgajiem ;) Gints Plivna http://datubazes.wordpress.com Link to comment Share on other sites More sharing options...
bubu Posted August 21, 2008 Report Share Posted August 21, 2008 Neesmu MySQL optimizācijas pratējs, bet explain komanda izvadīja: +----+--------------------+--------+--------+---------------+---------+---------+------+------+--------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+--------------------+--------+--------+---------------+---------+---------+------+------+--------------------------+ | 1 | PRIMARY | t | index | NULL | PRIMARY | 4 | NULL | 4 | Using where; Using index | | 2 | DEPENDENT SUBQUERY | tabule | eq_ref | PRIMARY | PRIMARY | 4 | func | 1 | Using where; Using index | +----+--------------------+--------+--------+---------------+---------+---------+------+------+--------------------------+ Cik saprotu eq_ref ir ļoti labs tips - O(1). Un "index" sakārtotu bināro koku gadījumā ir O(logN). Respektīvi O(logN) * O(1) = O(logN) < O(N). Edit: šķiet, ka kļūdos. "index" tips laikam nozīmē pilno pārlasi - O(N). Tātad nekas īpaši labāks par tavējo O(N) nav sanācis. Link to comment Share on other sites More sharing options...
gguntars Posted August 22, 2008 Author Report Share Posted August 22, 2008 Paldies visiem! Šķiet, ka šis strādā tieši tā kā man vajadzēja Kā būtu ar šādu kveriju? SELECT IFNULL(MIN(id)+1, 1) FROM tabule AS t WHERE NOT EXISTS (SELECT id FROM tabule WHERE id = t.id+1) Link to comment Share on other sites More sharing options...
Recommended Posts