Jump to content
php.lv forumi

Query veidošana


shurix

Recommended Posts

Taisu komentēšanu lapai un netieku skaidrībā, kādu query man vajag, lai izvadītu komentārus.

Ir 3 tabulas komentari - visi komentāri, komentari_atb - atbildes uz komentāriem, users - useru dati.

Es gribu izvadīt komentāru un tad aiz viņa visas atbildes un atkal nākošo komentāru ar visām viņa atbildēm + gan komentāram gan atbildei paņemt no users vārdu un bildīti.

Pats uzmeisteroju kaut ko šādu, bet protams īsti tur nenotiek tas ko vajadzētu.

SELECT komentari.*, komentari_atb.*, users.*
from komentari
left outer join komentari_atb
on komentari.id=komentari_atb.kid
left outer join users
on komentari.user_id=users.user_id or
komentari_atb.user_id=users.user_id

Link to comment
Share on other sites

Dari tā, ka ir divas tabulas: comments un users. Comments tabulai uztaisi lauku reply_id (vai kā tā)... kurš būs 0, ja šis komentārs nav atbilde kādam citam komentāram. Ja šis komentārs ir atbilde komentāram (ironija), tad reply_id saturēs galvenā komentāra id.

 

P.S. Un pieprasījumu Es tā "uz sitienu" nemāku uzrakstīt.

Link to comment
Share on other sites

Tādu variantu es arī biju iedomājies, bet izdomāju, ka querijam, lai dabūtu atbildes ir jāiet cauri arī pašiem komentāriem, kas it kā ir lieki un patērē laiku. Atbildes atsevišķi būs mazāk un ātrāk, vismaz pēc manas loģikas :D

Link to comment
Share on other sites

Tādu variantu es arī biju iedomājies, bet izdomāju, ka querijam, lai dabūtu atbildes ir jāiet cauri arī pašiem komentāriem, kas it kā ir lieki un patērē laiku. Atbildes atsevišķi būs mazāk un ātrāk, vismaz pēc manas loģikas :D

Nu ja Tev ļoti švaka kaste, tad jā, bet pa lielam, tāds CMS kā Wordpress tikai uz tādu principu strādā, kā minēja dagrevis. Tie saucās Parent'i. Nu vismaz es tā tos saucu. Pats arī bieži praktizēju, un viss iet kā nākas.

 

šitas diezgan vecs paraugs, ko pats izmantoju vienā lapā:

$query = "SELECT c.id, c.poster, c.content, c.time, u.id as u_id, u.img FROM content c INNER JOIN users u WHERE u.id = c.author AND c.type='discussion' AND c.parent_id = (SELECT id FROM content WHERE id = '".$discussion_id."')";

 

Kokains gan jau ir, bet izlobīt ideju var ;)

Edited by Roberts.R
Link to comment
Share on other sites

Atbildes atsevišķi būs mazāk un ātrāk, vismaz pēc manas loģikas :D

Nē nebūs ne ātrāk, ne ekonomiskāk.

Jo šaurā vieta ir datu pārsūtīšana no SQL uz PHP , un kveriju sākotnējā apstrāde.

piedevām SQL ļoti labi māk nokešot pieprasījumus, bet ne bezgalīgi daudz, ja nenāks klāt neviens komentārs , tad nākamajā reizē pieprasījums tiks ņemts no keša - attiecīgi apstrādes laiks krietni saruks

edit: varu pateikt arī kāpēc glabāt atbildes uz komentāriem atsevīšķā tabulā ir slikti.

iedomājies situāciju ka kāds komentārs jaizdzēš.

No kuras tabulas tu viņu ņemsi ?

Nāksies pārsūtīt 2 datus: ID un kurai tabulai pieder ( pamat komentiem, vai atbildēm)

turpretīm ja būs viena tabula tad pietiks ar ID, samērā primitīvs PHP kods ..

1 forma (ja vajag pielabot[cenzēt]) + datu apstrāde šai formai..

Edited by Grey_Wolf
Link to comment
Share on other sites

Tas vienas tabulas piegājiens arī būs mazliet universālāks tādā veidā, ka teorētiski tajā var glabāt n līmeņus nevis tikai 2. Tiesa gan MySQL piemēram ir lielas problēmas ar šādu rekursīvu vaicājumu veidošanu, bet nu varbūt kādreiz kāds kaut ko darīs šai lietā.

Vēl dažas piebilde pie iepriekšējā:

- komentāru tabulai tā kā acīmredzit vajadzētu būt saitei uz kaut kādiem rakstiem vai whatever, kas nu tas ir kam tie komentāri pievienoti

- lai nebūtu viss jālasa, tad atceramies, ka esksistē taču tāda lieta kā indeksi.

 

Anyway viens no piemēriem varētu izskatīties šādi:

Ir tabula komentāri - man tai trūkst kolonas uz lietotāju, bet nu to vari pats izveidot. Un daži ieraksti.

mysql> create table comments (com_id int not null auto_increment primary key,
   ->   com_art_id int not null,
   ->   com_com_id int,
   ->   com_text varchar(100));

Query OK, 0 rows affected (0.78 sec)

mysql> insert into comments values (1, 1, null, 'pirmais kom'),
   ->  (2, 1, 1, 'atb uz pirmo kom'),
   ->  (3, 1, null, 'otrais kom'),
   ->  (4, 1, null, 'treshais kom'),
   ->  (5, 1, 1, 'otra atb uz pirmo kom'),
   ->  (6, 1, 4, 'atb uz tresho kom'),
   ->  (7, 1, 4, 'otra atb uz tresho kom');
Query OK, 7 rows affected (0.03 sec)
Records: 7  Duplicates: 0  Warnings: 0

 

Rezultātu iegūst šādi:

mysql> SELECT com_id, com_com_id, 1 as level, com_text
   -> FROM comments
   -> WHERE com_art_id = 1
   ->   AND com_com_id is null
   -> UNION ALL
   -> SELECT c2.com_id, c2.com_com_id, 2 as level, c2.com_text
   -> FROM comments c1
   -> INNER JOIN comments c2
   -> ON (c1.com_id = c2.com_com_id)
   -> WHERE c1.com_art_id = 1
   ->   AND c1.com_com_id is null
   -> ORDER BY coalesce(com_com_id, com_id), com_id;
+--------+------------+-------+------------------------+
| com_id | com_com_id | level | com_text               |
+--------+------------+-------+------------------------+
|      1 |       NULL |     1 | pirmais kom            |
|      2 |          1 |     2 | atb uz pirmo kom       |
|      5 |          1 |     2 | otra atb uz pirmo kom  |
|      3 |       NULL |     1 | otrais kom             |
|      4 |       NULL |     1 | treshais kom           |
|      6 |          4 |     2 | atb uz tresho kom      |
|      7 |          4 |     2 | otra atb uz tresho kom |
+--------+------------+-------+------------------------+
7 rows in set (0.00 sec)

 

Tagad veidojam indeksus:

mysql> create index com_idx1 on comments(com_art_id, com_com_id);
Query OK, 0 rows affected (0.23 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> create index com_idx2 on comments(com_com_id);
Query OK, 0 rows affected (0.19 sec)
Records: 0  Duplicates: 0  Warnings: 0

 

Un skatamies kā tad vaicājums izskatīsies:

mysql> explain
   -> SELECT com_id, com_com_id, 1 as level, com_text
   -> FROM comments
   -> WHERE com_art_id = 1
   ->   AND com_com_id is null
   -> UNION ALL
   -> SELECT c2.com_id, c2.com_com_id, 2 as level, c2.com_text
   -> FROM comments c1
   -> INNER JOIN comments c2
   -> ON (c1.com_id = c2.com_com_id)
   -> WHERE c1.com_art_id = 1
   ->   AND c1.com_com_id is null
   -> ORDER BY coalesce(com_com_id, com_id), com_id;
+----+--------------+------------+------+---------------------------+----------+---------+----------------+------+--------------------------
+
| id | select_type  | table      | type | possible_keys             | key      | key_len | ref            | rows | Extra
|
+----+--------------+------------+------+---------------------------+----------+---------+----------------+------+--------------------------
+
|  1 | PRIMARY      | comments   | ref  | com_idx1,com_idx2         | com_idx1 | 9       | const,const    |    3 | Using where
|
|  2 | UNION        | c1         | ref  | PRIMARY,com_idx1,com_idx2 | com_idx1 | 9       | const,const    |    3 | Using where; Using index
|
|  2 | UNION        | c2         | ref  | com_idx2                  | com_idx2 | 5       | test.c1.com_id |    1 | Using where
|
| NULL | UNION RESULT | <union1,2> | ALL  | NULL                      | NULL     | NULL    | NULL           | NULL | Using filesort
 |
+----+--------------+------------+------+---------------------------+----------+---------+----------------+------+--------------------------
+
4 rows in set (0.00 sec)

 

Principā var redzēt, ka nekur full skans (ALL iekš type) tabulām nav. Tas ir tikai rezultātu apvienošanai, no kuras īsti izbēgt šķiet nevar.

It kā jau sanāk, ka tos pirmā līmeņa komentārus lasa 2reiz, jo otrreiz tos vajag tikai priekš otrā līmeņa komentāru atrašanas un pēc tam met ārā, bet nu, ja raksta vienkārši left join, tad tie sanāk vienā rindā kopā ar otrā līmeņa komentāriem un tad tos jāķeksē ārā kaut kā programmatoriski.

Reālā dzīvē arī tur varētu parādīties vairāki using index, jo šobrīd datu daudzums ir tik mazs (tikai priekš 1 raksta), ka tas īsti neatspoguļo iespējamo realitāti.

 

Gints Plivna

http://datubazes.wordpress.com

Link to comment
Share on other sites

Jautājums Gintam - Vai tad tavā tabulas struktūras variantā, komentārus nevar atlasīt vienkārši šādi:

 

SELECT * FROM  comments WHERE com_art_id=1 ORDER BY coalesce(com_com_id,com_id),com_id

?

Edited by codez
Link to comment
Share on other sites

Jautājums Gintam - Vai tad tavā tabulas struktūras variantā, komentārus nevar atlasīt vienkārši šādi:

 

SELECT * FROM  comments WHERE com_art_id=1 ORDER BY coalesce(com_com_id,com_id),com_id

?

 

Viss ģeniālais ir vienkāršs :)

Tev taisnība.

mysql> select com_id, case when com_com_id is NULL then 1 else 2 end as level, com_text
   -> FROM  comments WHERE com_art_id=1 ORDER BY coalesce(com_com_id,com_id),com_id;
+--------+-------+------------------------+
| com_id | level | com_text               |
+--------+-------+------------------------+
|      1 |     1 | pirmais kom            |
|      2 |     2 | atb uz pirmo kom       |
|      5 |     2 | otra atb uz pirmo kom  |
|      3 |     1 | otrais kom             |
|      4 |     1 | treshais kom           |
|      6 |     2 | atb uz tresho kom      |
|      7 |     2 | otra atb uz tresho kom |
+--------+-------+------------------------+
7 rows in set (0.00 sec)

 

Diviem līmeņiem var tiešām šādi. Trīs jau laikam tomēr vairs nevarētu :)

Un līdz ar to visādi tur ātrdarbības satraukumi arī izgaist pavisam.

 

Gints Plivna

http://datubazes.wordpress.com

Link to comment
Share on other sites

Kaut ko līdzīgu esmu taisījis.

Domu gājiens bija tāds ka ātrdarbība pie komentāra ievietošanas nav tik svarīga kā pie nolasīšanas. Strādā ar neierobežotiem līmeņiem. Detaļās īpaši neiedziļināšos, aprakstīšu vispārīgi.

 

Tabula:

id

topic_id

comment

level

display_order

 

Piemērs:

1	1	Komentārs_1		0	1
2	1	Atbilde_1_1		1	2
3	1	Atbilde_1_2		1	3
4	1	Atbilde_1_2_1 		2	4
5	1	Komentārs_2		0	5
6	1	Komentārs_3		0	6
7	1	Atbilde_3_1		1	7

 

Ja atbilde uz topiku tad pie inserta level = 0 un display_order = MAX(display_order topikam)+1

Ja atbilde uz komentu tad:

Skatamies komentāra uz kuru atbild id un iegūstam viņa level un display_order

UPDATE tabula SET display_order = display_order+1 WHERE display_order>$display_order AND topic_id=$topic_id
INSERT .... level=$level+1 ... display_order = komentāra display_order + 1 ...

Atbilstoši selekts ir:

SELECT FROM tabula WHERE topic_id=$topic ORDER BY display_order LIMIT cik nu vajag

 

Īsumā tā.

Trūkums tāds ka nevar selektu limitēt pēc augšējā līmeņa komentāriem. Vai var?

Edited by Rincewind
Link to comment
Share on other sites

Paldies par atbildēm, izdevās arī pievienot useru tabulu un viss gandrīz ir labi. Izņemot to, ka nemāku uzlikt limitu, lai ņemtu vērā tikai level 1 komentāru. 10 galvenie komentāri lapā, bet neierobežots skaits atbilžu.

Link to comment
Share on other sites

Paldies par atbildēm, izdevās arī pievienot useru tabulu un viss gandrīz ir labi. Izņemot to, ka nemāku uzlikt limitu, lai ņemtu vērā tikai level 1 komentāru. 10 galvenie komentāri lapā, bet neierobežots skaits atbilžu.

anyone?

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
×
×
  • Create New...