Join tables with comma values

前端 未结 3 570
日久生厌
日久生厌 2020-12-12 05:20

I have a hard nut to crack with joing 3 tables. I have a newsletter_items, newsletter_fields and newsletter_mailgroups which I want to be joined to get a list of newsletters

相关标签:
3条回答
  • 2020-12-12 06:04

    Try to use

    SELECT A.*, B.*, group_concat(C.mailgroup_name SEPARATOR ',') 
    FROM newsletter_items A,  newsletter_fields B, newsletter_mailgroups C  
    WHERE B.field_letter_uid = A.letter_id 
          AND field_name = 'letter_headline' 
          AND A.template = '". $template ."' 
          and find_in_set(c.mailgroup_id, A.receivers) 
    group by A.letter_id;
    
    0 讨论(0)
  • 2020-12-12 06:06

    If it's allowed, why don't you create a new table called newsletter_item_receivers where you could store letter_id, receiver_id fields? Having comma separated values in a field like this usually means you're missing a table :)

    Edit:

    By using CSV, you are making your life miserable when you want to retrieve an answer to "give me all newsletters that receiver_id=5 receives" :)

    Here's a good answer to a similar question on SO: Comma separated values in a database field

    Edit2:

    If I understand your table relationships correctly then it would be something like this:

    SELECT
      a.letter_date,
      b.receiver_id,
      a.status
    FROM newsletter_items_receivers b
      LEFT OUTER JOIN newsletter_items a ON (a.letter_id = b.letter_id)
      LEFT OUTER JOIN newsletter_mailgroups m ON (m.mailgroup_id = b.receiver_id)
    

    NOTE! This query WILL NOT return a newsletter when there are no receivers of that newsletter. If you need that functionality you can try something like this:

    SELECT
      x.letter_date,
      y.mailgroup_name,
      x.status
    FROM (
    SELECT
      a.letter_date,
      b.receiver_id,
      a.status
    FROM newsletter_items a
      LEFT OUTER JOIN newsletter_items_rec b ON (b.letter_id = a.letter_id)) x
      LEFT OUTER JOIN newsletter_mailgroups y ON (y.mailgroup_id = x.receiver_id)
    

    I don't have access to SQL right now so I might have made some syntax errors (hopefully not logical ones :)).

    As for why we are doing it like this, as @Konerak pointed out, you'd be well advised to read up on database normalization and why it's important.

    You can start with this article from about.com, just glanced over it seems an OK read http://databases.about.com/od/specificproducts/a/normalization.htm

    Also, it would be good if you'd keep fields names the same across multiple tables. For example you have letter_id in newsletter_items, but you have field_letter_uid in newsletter_fields. Just a thought :)

    0 讨论(0)
  • 2020-12-12 06:07

    I recommend that you make your joins explicit.
    It makes it easier to debug your query and to change inner with left joins.
    There is absolutely never a good reason to use SQL '89 implicit join syntax.

    SELECT ni.*
           , nf.*
           , group_concat(nm.mailgroup_name) as mailgroups
    FROM newsletter_items ni
    INNER JOIN newsletter_fields nf 
      ON (nf.field_letter_uid = ni.letter_id)
    INNER JOIN newsletter_mailgroups nm  
      ON (find_in_set(nm.mailgroup_id, ni.receivers))
    WHERE  
      nf.field_name = 'letter_headline' 
      ni.template = '". $template ."' 
    GROUP BY ni.letter_id;
    

    Regarding your database design.
    I recommend you normalize your database, that means that you move the comma separated fields into a different table.

    So you make a table receivers

    Receivers
    ----------
    id integer auto_increment primary key
    letter_id integer not null foreign key references newsletter_items(letter_id)
    value integer not null
    

    You then remove the field receiver from the table newsletter_items

    Your query then changes into:

    SELECT ni.*
           , group_concat(r.value) as receivers
           , nf.*
           , group_concat(nm.mailgroup_name) as mailgroups
    
    FROM newsletter_items ni
    INNER JOIN newsletter_fields nf 
      ON (nf.field_letter_uid = ni.letter_id)
    INNER JOIN newsletter_mailgroups nm  
      ON (find_in_set(nm.mailgroup_id, ni.receivers))
    LEFT JOIN receiver r ON (r.letter_id = ni.letter_id)
    WHERE  
      nf.field_name = 'letter_headline' 
      ni.template = '". $template ."' 
    GROUP BY ni.letter_id;
    

    This change should also speed up your query significantly.

    0 讨论(0)
提交回复
热议问题