1 (edited by Mantas LT 2010-02-16 18:37:31)

Topic: Dvi automatiškai užpildomos reikšmės

Sveiki,

turiu lentelę:

CREATE TABLE `categories`
(
    `ID` TINYINT UNSIGNED NOT NULL auto_increment,
    `category` varchar(35) UNIQUE NOT NULL,
    `ranking` TINYINT UNSIGNED UNIQUE NOT NULL,
    PRIMARY KEY (`ID`)
) TYPE=MyISAM ;

Kaip padaryti, kad įterpiant naują įrašą skiltis "ranking" būtų automatiškai užpildyta, priskiriant tokią pačią reikšmę kaip ID? Spėju kad pačios lentelės neišeis taip sutvarkyt.
Ką tokiu atveju pasiūlytumėte? Norisi kad įterpimo užklausa būtų kuo trumpesnė. Pasirašyti funkciją? Kaip tokiu atveju ji atrodytų?

Ačiū

EDIT: dirbu su MySQL DBVS

Re: Dvi automatiškai užpildomos reikšmės

Pabandyk čia paskaityt: http://forums.mysql.com/read.php?99,186 … msg-186241

3 (edited by Mantas LT 2010-02-16 19:17:47)

Re: Dvi automatiškai užpildomos reikšmės

Sveiki dar kartą,
ačiū už greitą atsakymą.

Ilgai ieškojau, skaitinėjau, tyrinėjau, bet taip ir neturiu ką konkretaus pasakyt.
Nenoriu kurti papildomos lentelės. Ar būtų galima parašyti procedūrą, kuri gautų `category`, įrašytų jį į lentelę ir atnaujintų lentelę, pagal turimą LAST_INSERT_ID() reikšmę?

EDIT.

Pasirašiau štai tokią procedūrą:

delimiter //

CREATE PROCEDURE ADD_CATEGORY( title VARCHAR(35) )
BEGIN
  INSERT INTO `categories` (category) VALUES (title);
  UPDATE `categories` SET `ranking` = LAST_INSERT_ID() WHERE `ID` = LAST_INSERT_ID();
END//

delimiter ;

Džiaugiuosi, kad veikia, nes pradėjęs gilintis supratau, kad mano SQL žinios niekinės.

EDIT2: kai dabar bandau sukurt tokią procedūrą, meta klaidą, bet procedūrą sukuria. Kodėl taip yra? Prieš kurdamas ištrinu egzistuojančią

Re: Dvi automatiškai užpildomos reikšmės

Tau iš to link'o kurį daviau reikėjo pasinagrinėti kaip veikia trigeri'is, kurio pagalba būtų galima atlikti papildomą UPDATE. Procedūra irgi nėra blogas sprendimas.

Re: Dvi automatiškai užpildomos reikšmės

Gautą nuorodą tikrai panagrinėjau, viskas suprantama, bet nors aš ir ne profesionalas, man atrodo kad šiuo atveju geriau procedūra. Užklausų skaičius tas pats ir nereikia papildomos lentelės, kas man skamba kaip "šuniui penkta koja".

Kodėl kai aš įvedu kodą procedūrai sukurti, gaunu klaidą, nors procedūrą sukuria? Prieš tai buvusią procedūrą ištrinu su DROP. Ir kodėl rodo, kad paskutinė eilutė dubliuojasi? Kartais visas delimiter gabalas dubliuojasi.
Vaizdas: http://i50.tinypic.com/291c9og.png

čia parašiau procedūrą ranking'ams sukeisti.

delimiter //
CREATE PROCEDURE CHANGE_POSSITIONS(a TINYINT, b TINYINT)
BEGIN
  DECLARE c TINYINT;
  SELECT `ID` AS c FROM `d_categories` ORDER BY `ID` DESC LIMIT 1;
  SET c = c + 2;
  UPDATE `d_categories` SET `ranking` = c WHERE `ID` = a;
  UPDATE `d_categories` SET `ranking` = a WHERE `ID` = b;
  UPDATE `d_categories` SET `ranking` = b WHERE `ID` = a;
END//
delimiter;

Tik nelabai išeina ją ištestuoti. Bandau "CALL CHANGE_POSSITIONS(2, 3)", bet gaunu atsakymą "#1312 - PROCEDURE db_table.CHANGE_POSSITIONS can't return a result set in the given context".

Re: Dvi automatiškai užpildomos reikšmės

Ten papildomos lentelės lyg nereikėtų, užtektų trigerio AFTER INSERT, kuris paimtų LAST_INSERT_ID() ir padarytų UPDATE tavo norimam stulpeliui tavo turimoje lentelėje.

Naudodamas procedūrą tu užklausų kiekio nesumažini, nes jos vykdomos tavo procedūroje. čia tik nebent turi omeny, kad kodas lakoniškesnis (-;

Re: Dvi automatiškai užpildomos reikšmės

minde wrote:

Ten papildomos lentelės lyg nereikėtų, užtektų trigerio AFTER INSERT, kuris paimtų LAST_INSERT_ID() ir padarytų UPDATE tavo norimam stulpeliui tavo turimoje lentelėje.

Tokią idėją turėjau. Bandžiau "gamint" tokį trigerį, bet nepavyko.

minde wrote:

Naudodamas procedūrą tu užklausų kiekio nesumažini, nes jos vykdomos tavo procedūroje. čia tik nebent turi omeny, kad kodas lakoniškesnis (-;

Aš ir nesakiau kad sumažės užklausų :)

Atsiprašau už tokio žemo lygio klausimą, bet kas negerai su mano procedūra CHANGE_POSSITIONS? Kaip ja naudotis?
Dabar einu IF'o ieškot, nes gali būt bėdų kai lentelėj mažiau nei du įrašai. Būsiu dėkingas jei ir dėl šito sulauksiu pagalbos. (if c ne 0 begin .. end)

Re: Dvi automatiškai užpildomos reikšmės

Mantas LT wrote:

Tokią idėją turėjau. Bandžiau "gamint" tokį trigerį, bet nepavyko.

Reikia bandyti dar (-; Tas trigeris atliktų veiksmą po INSERT'o. Kaip tik tai, ko tau reikia.

minde wrote:

Atsiprašau už tokio žemo lygio klausimą, bet kas negerai su mano procedūra CHANGE_POSSITIONS? Kaip ja naudotis?
Dabar einu IF'o ieškot, nes gali būt bėdų kai lentelėj mažiau nei du įrašai. Būsiu dėkingas jei ir dėl šito sulauksiu pagalbos. (if c ne 0 begin .. end)

Jeigu yra kažkas negerai tai reikia žiūrėti, kaip ji veikia, ar korektiškai ar ne.

Procedūras paleisti reikia su CALL operatoriumi, pvz.:

CALL CHANGE_POSSITIONS('parametras_1', 'parametras_2');

Re: Dvi automatiškai užpildomos reikšmės

Sveiki,
galėtumėte pasakyti kas blogai šioje procedūroje?

delimiter //
CREATE PROCEDURE CHANGE_POSSITIONS(a TINYINT, b TINYINT)
BEGIN
      UPDATE `d_categories` SET `ranking` = 0 WHERE `ID` = a;
      UPDATE `d_categories` SET `ranking` = a WHERE `ID` = b;
      UPDATE `d_categories` SET `ranking` = b WHERE `ID` = a;
END//
delimiter;

Kad ir kokius pakeitimus daryčiau visada ją kuriant meta vienodą klaidą (bet procedūrą sukuria; ištestuot neišeina):

#1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'delimiter' at line 1

Prieš kurdamas visada ištrinu:

DROP PROCEDURE IF EXISTS CHANGE_POSSITIONS;

Situacija panaši kaip rodžiau: http://i50.tinypic.com/291c9og.png
Kaip tai suprast? Kodėl ta eilutė kartojasi?

MySQL versija 5.0.89

Re: Dvi automatiškai užpildomos reikšmės

O kam naudoji delimiter operatorių jeigu dirbi ne klientinėje programoje?

Dirbant su PMA delimiter nusistato pačioje SQL formoje (žiūrėk apačioje).

Re: Dvi automatiškai užpildomos reikšmės

Sukuriu tuščią procedūrą, tačiau procedūrų su užklausom sukurti nepavyksta kodėl? Visada meta #1064 klaidą.
Net tokios procedūros nepavyksta sukurti:

CREATE PROCEDURE GAC() BEGIN SELECT *  FROM d_categories; END

Spėju kad trūksta nedaug, bet kažko esminio.

Re: Dvi automatiškai užpildomos reikšmės

Tai čia problema bus ta, kad tu niekaip neaprašai skirtuko (delimiter). Su procedūromis/funkcijomis yra toks dalykas, kad jų viduje reikalingas skirtukas (kabliataškis - ;) atskirti atskiras komandas, todėl tam, kad nesikirstu su pačios procedūros kūrimo komandos pabaiga yra daroma taip:
prieš procedūros kūrima pakeičiamas skirtukas, o po jos atkeičiamas atgal;

Aukščiau esančiose tavo pačio žinutėse tai gali matyti.

Re: Dvi automatiškai užpildomos reikšmės

Pradėjau testuot procedūros vidurius ir supratau, kad ne tuo keliu nuėjau. Eilutei b bandžiau priskirti eilutės a ID, o ne ranking ir atvirkščiai. (Tas pasako kodėl neveikė testas; kodėl nepavykdavo sukurti proceduros nežinau) Taigi šiuo metu veikianti procedūra atrodo štai taip:

delimiter //
CREATE PROCEDURE `CHANGE_POSSITIONS`(a TINYINT UNSIGNED, b TINYINT UNSIGNED)
 BEGIN
  DECLARE ar, br TINYINT UNSIGNED;
  SELECT `ranking` INTO ar FROM `d_categories` WHERE `ID` = a;
  SELECT `ranking` INTO br FROM `d_categories` WHERE `ID` = b;
  UPDATE `d_categories` SET `ranking` = 0 WHERE `ID` = a;
  UPDATE `d_categories` SET `ranking` = ar WHERE `ID` = b;
  UPDATE `d_categories` SET `ranking` = br WHERE `ID` = a;
 END//
delimiter ;

Manau sutiksit, procedūra atrodo kiek gremėzdiškai, atsižvelgiant į tai, kad ji turi tik sukeisti dvi unikalias (negalinčias dubliuotis) reikšmes vietomis.
Ar įmanoma šioje situacijoje kažką pakeisti, sumažinti užklausų kiekį?

Re: Dvi automatiškai užpildomos reikšmės

Iš pradžių tegul paveikia taip, kaip yra. Isitikinsi ar tikrai viskas gerai.

Taip pat nereikia pamiršti, kad mažas užklausų skaičius dar nereiškia greitesnio veikimo. Norint čia kažką supaprastinti, patį užklausų kiekį galima sumažinti, bet ar rezultate bus vizualiai mažesnė procedūra ir ar ji veiks nors kiek greičiau tai nėra jokių garantijų.

15 (edited by Mantas LT 2010-03-07 13:06:57)

Re: Dvi automatiškai užpildomos reikšmės

Pagaliau prisiruošiau padaryti testą. SQL funkcijų greitis stulbinamai mažas. Su PHP tą patį darbą atlieka bent 2 kartus greičiau. Atsižvelgiant į tai, kad PHP rašau OOP, tai SQL bent 3 kartus lėtesnė už PHP. Mėgstu tvarką, bet ne ką mažiau optimalumą, todėl nenaudosiu SQL funkcijų ir procedūrų.

Kaip minde sakė, geriausiai būtų trigeriai, jei turit galimybę juos naudot. (Iki 5.1.6 versijos tam reikalingos SUPER privilegijos).

Ačiū už pagalbą.

EDIT: dar grįšiu prie šito klausimo, nes perdariau laiko skaičiavimo mechanizmą (OOP realizacija) ir gavau kitokius rezultatus. SQL vykdymo laikas krito beveik trigubai. Nelabai suvokiu kaip taip gali būti, nes laiko reikšmės imamoms lygiai tose pačiose vietose.

EDIT2: testą pakartojau. Panašu, kad kažkur buvau klaidą padaręs. Jei į SQL funkciją kreipiatės kelis kartus, tai apsimoka ją naudot (pirmo vykdymo metu reikia dvigubai daugiau laiko nei sekančių).