Go Back   vb.org Archive > vBulletin 3 Discussion > vB3 Programming Discussions
FAQ Community Calendar Today's Posts Search

Reply
 
Thread Tools Display Modes
  #1  
Old 06-24-2007, 08:40 PM
Antivirus's Avatar
Antivirus Antivirus is offline
 
Join Date: Sep 2004
Location: Black Lagoon
Posts: 1,090
Благодарил(а): 0 раз(а)
Поблагодарили: 0 раз(а) в 0 сообщениях
Default Boggled by GROUP_CONCAT in query...

Working on a query and having a difficult time with this. If anyone can help i'll be very happy

My data:
For Table things...
=================
| thingid | stringcodeids |
=================
| 1 | 1 |
| 2 | 1,3,4 |
| 3 | |
| 4 | 2 |
=================

For Table stuff...
=================
| stuffid | code |
=================
| 1 | AAA |
| 2 | BBB |
| 3 | CCC |
| 4 | DDD |
| 5 | EEE |
| 6 | FFF |
=================


My query:
PHP Code:
$sql $db->query_read("
     SELECT things*, GROUP_CONCAT(stuff.code ORDER BY code SEPARATOR ', ') AS thingcodes
     FROM things
     LEFT JOIN stuff ON stuff.stuffid IN ( things.stringcodeids )
     WHERE things.stringcodeids = 2
     GROUP BY things.thingid
"
); 
Problem is that I can't get a concatenated list of related fields stuff.code based upon the string of code ids within things.stringcodeids

What I want specifically is for alias thingcodes to return 'AAA, CCC, DDD', however thingcodes is returning as empty

Thanks!
Reply With Quote
  #2  
Old 06-25-2007, 04:07 AM
Eikinskjaldi's Avatar
Eikinskjaldi Eikinskjaldi is offline
 
Join Date: Feb 2006
Location: Hell, never looked better
Posts: 572
Благодарил(а): 0 раз(а)
Поблагодарили: 0 раз(а) в 0 сообщениях
Default

whilst you could probably get this to work if you split the stringcodeids, this is a horribly inefficient query which will bog down as soon as you get a decent number of rows in either table, since the primary join will require an ALL join (it has to look in every row to see if its ID is present)


You should restructure table things so that it has 1 row per association. Either add an increment as a primary key or make both columns dual primary key

For Table things...
=================
| thingid | stuffid |
=================
| 1 | 1 |
| 2 | 1 |
| 2 | 3 |
| 2 | 4 |
| 4 | 2 |
=================

and the sql
[sql]
SELECT things.*, GROUP_CONCAT(stuff.code ORDER BY code SEPARATOR ', ') AS thingcodes
FROM things
LEFT JOIN stuff USING (stuffid)
WHERE things.stuffid = 2
GROUP BY things.thingid
[/sql]

note your where clause makes the group_concat irrelevant, as you are only selecting 1 row from that column.
Reply With Quote
  #3  
Old 06-25-2007, 02:52 PM
Antivirus's Avatar
Antivirus Antivirus is offline
 
Join Date: Sep 2004
Location: Black Lagoon
Posts: 1,090
Благодарил(а): 0 раз(а)
Поблагодарили: 0 раз(а) в 0 сообщениях
Default

eikin,
Thanks for the help. I can get it to work your way, but I really wanted to avoid using an additional table for the joins. I was however able to get the query to work using the following:

[SQL]
SELECT things.*, GROUP_CONCAT(stuff.code ORDER BY stuff.code SEPARATOR ', ') AS thingcodes
FROM things
LEFT JOIN stuff ON FIND_IN_SET(stuff.stuffid, things.stringcodeids) > 0
WHERE things.thingid = 2
GROUP BY things.thingid
[/SQL]

Is this really that much more inefficient than using an additional table to handle the stringcodeids -> stuffcode relationship?
Thanks again
Reply With Quote
  #4  
Old 06-25-2007, 08:44 PM
Eikinskjaldi's Avatar
Eikinskjaldi Eikinskjaldi is offline
 
Join Date: Feb 2006
Location: Hell, never looked better
Posts: 572
Благодарил(а): 0 раз(а)
Поблагодарили: 0 раз(а) в 0 сообщениях
Default

Firstly, I wasn't suggesting an extra table, but a replacement table.

Secondly, "FIND_IN_SET"...nice, I didn't know that existed.

Anyway, my guess is yes, the find in set method will be horribly inefficient. Run it through explain, see what the join looks like.
Reply With Quote
  #5  
Old 06-27-2007, 06:49 PM
Antivirus's Avatar
Antivirus Antivirus is offline
 
Join Date: Sep 2004
Location: Black Lagoon
Posts: 1,090
Благодарил(а): 0 раз(а)
Поблагодарили: 0 раз(а) в 0 сообщениях
Default

well, i see by using explain that it takes almost twice as long to do the query with the FIND_IN_SET then with the way you suggested. I can imagine that as the db grows it will certainly take longer. I really don't want to have to re-write all the different queries that access this however, is there any other way such as creating a special type of index for the JOIN using the things.stringcodeids column? I see different types, but have to say that the mysql manual doesn't really give many examples of when to use which types of indexes and why. t's somewhat confusing...
Reply With Quote
  #6  
Old 06-27-2007, 07:16 PM
Adrian Schneider's Avatar
Adrian Schneider Adrian Schneider is offline
 
Join Date: Jul 2004
Posts: 2,528
Благодарил(а): 0 раз(а)
Поблагодарили: 0 раз(а) в 0 сообщениях
Default

Relationship tables are the way to go.
Reply With Quote
  #7  
Old 06-27-2007, 09:35 PM
Eikinskjaldi's Avatar
Eikinskjaldi Eikinskjaldi is offline
 
Join Date: Feb 2006
Location: Hell, never looked better
Posts: 572
Благодарил(а): 0 раз(а)
Поблагодарили: 0 раз(а) в 0 сообщениях
Default

No AV, there isnt. You are scanning for a subset of the key, there is no way to index that.


I understand that you dont want to re structure your code, but my way is the high way (as opposed to the goat track you wandered down .

A bit of pain now versus a lot of pain in the future.
Reply With Quote
  #8  
Old 06-28-2007, 12:11 AM
Antivirus's Avatar
Antivirus Antivirus is offline
 
Join Date: Sep 2004
Location: Black Lagoon
Posts: 1,090
Благодарил(а): 0 раз(а)
Поблагодарили: 0 раз(а) в 0 сообщениях
Default

damn, but i guess you're right. Wondering then, for instance why jelsoft has coded membergroupids in this manner such as 11,13,22,35 etc...
Reply With Quote
  #9  
Old 06-28-2007, 01:52 AM
Eikinskjaldi's Avatar
Eikinskjaldi Eikinskjaldi is offline
 
Join Date: Feb 2006
Location: Hell, never looked better
Posts: 572
Благодарил(а): 0 раз(а)
Поблагодарили: 0 раз(а) в 0 сообщениях
Default

Quote:
Originally Posted by Antivirus View Post
damn, but i guess you're right. Wondering then, for instance why jelsoft has coded membergroupids in this manner such as 11,13,22,35 etc...
Swings and roundabouts, I guess. The only time VB needs to do a find in set is when it is showing all the users for a particular usergroup. In all other instances you already have a user and just want to know if they are a member of an extra user group. I guess the makers decided a bit of inefficiency was worth not having an extra table.

Personally, I dont agree with their decision.
Reply With Quote
Reply


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT. The time now is 03:14 AM.


Powered by vBulletin® Version 3.8.12 by vBS
Copyright ©2000 - 2024, vBulletin Solutions Inc.
X vBulletin 3.8.12 by vBS Debug Information
  • Page Generation 0.04494 seconds
  • Memory Usage 2,249KB
  • Queries Executed 11 (?)
More Information
Template Usage:
  • (1)SHOWTHREAD
  • (1)ad_footer_end
  • (1)ad_footer_start
  • (1)ad_header_end
  • (1)ad_header_logo
  • (1)ad_navbar_below
  • (1)ad_showthread_beforeqr
  • (1)ad_showthread_firstpost
  • (1)ad_showthread_firstpost_sig
  • (1)ad_showthread_firstpost_start
  • (1)bbcode_php
  • (1)bbcode_quote
  • (1)footer
  • (1)forumjump
  • (1)forumrules
  • (1)gobutton
  • (1)header
  • (1)headinclude
  • (1)navbar
  • (3)navbar_link
  • (120)option
  • (9)post_thanks_box
  • (9)post_thanks_button
  • (1)post_thanks_javascript
  • (1)post_thanks_navbar_search
  • (9)post_thanks_postbit_info
  • (9)postbit
  • (9)postbit_onlinestatus
  • (9)postbit_wrapper
  • (1)spacer_close
  • (1)spacer_open
  • (1)tagbit_wrapper 

Phrase Groups Available:
  • global
  • inlinemod
  • postbit
  • posting
  • reputationlevel
  • showthread
Included Files:
  • ./showthread.php
  • ./global.php
  • ./includes/init.php
  • ./includes/class_core.php
  • ./includes/config.php
  • ./includes/functions.php
  • ./includes/class_hook.php
  • ./includes/modsystem_functions.php
  • ./includes/functions_bigthree.php
  • ./includes/class_postbit.php
  • ./includes/class_bbcode.php
  • ./includes/functions_reputation.php
  • ./includes/functions_post_thanks.php 

Hooks Called:
  • init_startup
  • init_startup_session_setup_start
  • init_startup_session_setup_complete
  • cache_permissions
  • fetch_threadinfo_query
  • fetch_threadinfo
  • fetch_foruminfo
  • style_fetch
  • cache_templates
  • global_start
  • parse_templates
  • global_setup_complete
  • showthread_start
  • showthread_getinfo
  • forumjump
  • showthread_post_start
  • showthread_query_postids
  • showthread_query
  • bbcode_fetch_tags
  • bbcode_create
  • showthread_postbit_create
  • postbit_factory
  • postbit_display_start
  • post_thanks_function_post_thanks_off_start
  • post_thanks_function_post_thanks_off_end
  • post_thanks_function_fetch_thanks_start
  • post_thanks_function_fetch_thanks_end
  • post_thanks_function_thanked_already_start
  • post_thanks_function_thanked_already_end
  • fetch_musername
  • postbit_imicons
  • bbcode_parse_start
  • bbcode_parse_complete_precache
  • bbcode_parse_complete
  • postbit_display_complete
  • post_thanks_function_can_thank_this_post_start
  • tag_fetchbit_complete
  • forumrules
  • navbits
  • navbits_complete
  • showthread_complete