marrtins Posted October 22, 2010 Report Share Posted October 22, 2010 (edited) Dots pieprasījums (vienkāršots) SELECT SQL_CALC_FOUND_ROWS @vendor_id:=(<SELECT bla bla LIMIT 1>) AS vendor_id, // INTEGER vai NULL @has_vendor:=(<SELECT bla bla LIMIT 1>) AS has_vendor, // INTEGER vai NULL @has_vendor_id:=COALESCE(@vendor_id, @has_vendor) AS has_vendor_id FROM _preces Jebkāda filtrēšana pēc has_vendor_id vai @has_vendor_id NEDARBOJAS. WHERE specid =1191 AND (@has_vendor_id = 2) ---- WHERE specid =1191 HAVING has_vendor_id = 2 Savukārt, pēc katra individuāli DARBOJAS WHERE specid =1191 AND (@vendor_id = 2) --- WHERE specid =1191 AND (@has_vendor = 2) --- WHERE specid =1191 HAVING vendor_id = 2 Selektā bez nosacījumiem skaidri redzams, ka has_vendor_id aizpildās kā vajadzīgs kā būtu jābūt izmantojot COALESCE. Aizdomas, ka tur kaut-kur pa vidu veidojas BLOB, taču nekādi CAST vai CONVERT arī nelīdz. Subkveriji šajā gadījumā ir nepieciešami, joinus nepiedāvāt. Idejas? :O Edited October 22, 2010 by marrtins Quote Link to comment Share on other sites More sharing options...
Gints Plivna Posted October 22, 2010 Report Share Posted October 22, 2010 Ja godīgi, maz ko zinu par MySQL mainīgajiem, bet vai šai gadījumā nav tā, ka vispirms tiek izpildīta where klauza un tad tikai iniciēts mainīgais @has_vendor_id. Līdz ar to ir vismaz 2 iespējas, manuprāt: 1) rakstīt nosacījumu uz individuālajiem mainīgajiem, jo coalesce jau ir tikai f-ja un to var gana viegli nosimulēt papildus where nosacījumos ar mazliet garākiem AND/OR nosacījumiem 2) rakstīt virsselektu, kuram subselekts ir šis te jau dotais (iespējams bez SQL_CALC_FOUND_ROWS, kuru var iznest virsselektā) un where klauzu pielietot virsselektā, kur @has_vendor_id jau būtu jābūt izrēķinātam. Gints Plivna http://datubazes.wordpress.com Quote Link to comment Share on other sites More sharing options...
marrtins Posted October 22, 2010 Author Report Share Posted October 22, 2010 (edited) Ja godīgi, maz ko zinu par MySQL mainīgajiem, bet vai šai gadījumā nav tā, ka vispirms tiek izpildīta where klauza un tad tikai iniciēts mainīgais @has_vendor_id. Diezvai, jo plain selektā viss rādās "kā vajag", kā arī, selektējot pēc abiem pirmajiem mainīgajiem, arī viss darbojas. Līdz ar to ir vismaz 2 iespējas, manuprāt: 1) rakstīt nosacījumu uz individuālajiem mainīgajiem, jo coalesce jau ir tikai f-ja un to var gana viegli nosimulēt papildus where nosacījumos ar mazliet garākiem AND/OR nosacījumiem Jā, patlaban esmu izlīdzējies ar šo variantu, bet baisi negribas šo lieko drazu katrā vietā, kur tiek uzstādīti filtri. Protams, var jau ieviest kādu f-iju. Lai nu kā, bet rezultāts ir visai interesants, gribētos zināt kāpēc tā. 2) rakstīt virsselektu, kuram subselekts ir šis te jau dotais (iespējams bez SQL_CALC_FOUND_ROWS, kuru var iznest virsselektā) un where klauzu pielietot virsselektā, kur @has_vendor_id jau būtu jābūt izrēķinātam. Šis nebūs risinājums jo 1) performance aizies dupsītī 2) pieprasījums jau tā ir visai liels, papildu un papildus sarežģītības slāni negribas ieviest. Paldies par ātru atbildi! Edited October 22, 2010 by marrtins Quote Link to comment Share on other sites More sharing options...
Gints Plivna Posted October 22, 2010 Report Share Posted October 22, 2010 Tur BTW ir kaut kādas acīmredzamas dīvainības kad tie mianīgie tiek un netiek inicializēti. Skat uzskatāms testpiemērs. Man ir tabula t1 kurā ir kolona a, tabulā t1 ir ieraksts ar vērtību 2, bet nav ieraksta ar vērtību 77. Šis testpiemērs īsti nestrādā, kā domāts (vismaz nezinot mainīgo inicializācijas smalkumus), jo viņam vajadzētu atgriezt ierakstu: mysql> select @i := (select a from t1 where a = 77) as k1, -> @j := (select a from t1 where a = 2) as k2, -> @e := coalesce(@i, @j) as k3 -> from dual -> where @e = 2; Empty set (0.00 sec) OK tagad izpildam šo pašu selektu vienreiz bez where klauzas: mysql> select @i := (select a from t1 where a = 77) as k1, -> @j := (select a from t1 where a = 2) as k2, -> @e := coalesce(@i, @j) as k3 -> from dual; +------+------+------+ | k1 | k2 | k3 | +------+------+------+ | NULL | 2 | 2 | +------+------+------+ 1 row in set (0.00 sec) UN TAGAD lai dzīve kā medus nelikto izpildam precīzi to pašu pirmo SQL teikumu: mysql> select @i := (select a from t1 where a = 77) as k1, -> @j := (select a from t1 where a = 2) as k2, -> @e := coalesce(@i, @j) as k3 -> from dual -> where @e = 2; +------+------+------+ | k1 | k2 | k3 | +------+------+------+ | NULL | 2 | 2 | +------+------+------+ 1 row in set (0.00 sec) Bingo! šoreiz ir rezultāts atgriezts! Ļoti jau nu ož pēc tā ka pirmā SQL teikumā tomēr @e netika izrēķināts, tb vispirms bija where klauza, kas visu jau nogrieza nost. Tad otrā SQL teikumā @e tika izrēķināts, jo where klauzas vispār nebija. Tad trešajā SQL teikumā jau izmantoja to pašu @e, kas jau bija izrēķināts otrā SQL teikumā. Un galu galā jālasa MySQL dokumentācija, jo tur jau patiesība viss ir rakstīts: As a general rule, you should never assign a value to a user variable and read the value within the same statement. You might get the results you expect, but this is not guaranteed. The order of evaluation for expressions involving user variables is undefined and may change based on the elements contained within a given statement. In SELECT @a, @a:=@a+1, ..., you might think that MySQL will evaluate @a first and then do an assignment second. However, changing the statement (for example, by adding a GROUP BY, HAVING, or ORDER BY clause) may cause MySQL to select an execution plan with a different order of evaluation. Gints Plivna http://datubazes.wordpress.com Quote Link to comment Share on other sites More sharing options...
marrtins Posted October 22, 2010 Author Report Share Posted October 22, 2010 (edited) Nē nu bāc, tas MySQL man sāk tracināt uz šīm niansēm. Praktiski šāda variabļu "fīča" SELECT pieprasījumā sanāk bezjēdzīga. Būs viss jāpārraksta. It kā jau loģiski, ka tā inicializēšanās secība nav definēta, ja darbojas ar kopām, bet nu tad nafig tādi vispār vajadzīgi SELECTā? :E Atminos, vēl pirms laika, kad šāda tipa nesaprotami MySQL gļuki parādījās pie datubāzes ar procedūrām dump un restore uz citu serveri, kad mysqldump pie procedūras definīcijas piekabināja DEFINER = 'user@host'. Gala serverī tāds users neeksistē, viss saimportējas, bet procedūra nedarbojas un nekādi skaļi paziņojumi par to netiek doti. Kamēr to gļuku atradu... :E Paldies \m/ Edited October 22, 2010 by marrtins Quote Link to comment Share on other sites More sharing options...
Gints Plivna Posted October 22, 2010 Report Share Posted October 22, 2010 Nu kā jau dokā rakstīts vismaz sākotnējais šo mainīgo mērķis ir bijis šāds: You can store a value in a user-defined variable in one statement and then refer to it later in another statement. This enables you to pass values from one statement to another. Bet tad šo fīču izdomas pilni cilvēki izmanto visādām vajadzībām, kuras arī tai pašā lapā zemāk var redzēt un šķiet vairums no tām mainīgos lieto viena selekta ietvaros. Kas jau laikam tomēr vairuma gadījumā arī strādā. Bet iespējas nepareiza lietošana (abuse) jau nav tikai šai konkrētajai MySQL fīčai, tā ir daudz kur :) Bet nu īstenībā šai gadījumā visās citās DB (ok vismaz Oraclē un SQL Serverī), kur tādu mainīgo nav, es lietotu iekļauto selektu ar where klauzu virsselektā. It kā jau MySQLā tā mantra ir, ka apakšvaicājumi ir bremzīgi, bet man ir aizdomas, ka tas itin bieži ir mīts, tāpat kā daudzi citi mīti citās DBVS. Katrā ziņā vismaz ir vērts pamēģināt. Ak jā un vēl vajag atcerēties, ka mainīgie ir konekcijas ietvaros, tātad, ja vienas konekcijas ietvaros to pašu izpilda atkal, jāuzmanās, lai iepriekšējos SQL teikumos inicializētās vērtības nesāk jaukt gaisu... Gints Plivna http://datubazes.wordpress.com Quote Link to comment Share on other sites More sharing options...
marrtins Posted October 22, 2010 Author Report Share Posted October 22, 2010 Man tūliņ procedūra būs gatava. Sākumā negribējās krāmēties ar procedūrām (lieks piedēklis), bet, acīmredzot, nekur neaizmukšu. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.