Question

Consider the database:

  • A Company has zero or more Branch companies
  • A Company has zero or more Emails
  • A Branch has zero or more Emails

And consider the following instance of that database:

  • 1 Company with 2 Branches
  • The Company has 1 Email
  • Each branch has 2 Emails

(5 Emails in total)

If you prefer, check the graphical representation of that instance.


Query

I'd like to make a query (MySQL) that retrieves all e-mails related to a given company (5, in the example). I couldn't find a solution, so after a bit of googling I found out that there's a thing called cursor.


Question

  • Is the use of cursor needed to achieve the query above? Would it be a good solution? What would be your solution to the query above?

(tables are defined below)


My idea was to retrieve all branches for a given company (that query I could make), but from there I don't know how to iterate through the branches (result of the query) and get all the e-mails.


Tables definitions in MySQL

-- Database tables
CREATE TABLE `company` (

        `c_id`          INT(11) NOT NULL AUTO_INCREMENT,
        `c_name`        VARCHAR(45) NOT NULL,

        PRIMARY KEY (`c_name`),
        UNIQUE KEY `c_id` (`c_id`)

) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8


CREATE TABLE `branch` (

        `b_id`          INT(11) NOT NULL AUTO_INCREMENT,
        `c_id`          INT(11) NOT NULL,
        `b_name` VARCHAR(45) NOT NULL,

        PRIMARY KEY (`b_name`),
        UNIQUE KEY `b_id` (`b_id`),
        KEY `c_id` (`c_id`),

        CONSTRAINT `branch_ibfk_1` FOREIGN KEY (`c_id`)
                REFERENCES `company` (`c_id`)
                ON DELETE CASCADE
                ON UPDATE CASCADE

) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8


CREATE TABLE `email` (

        `e_id`          INT(11) NOT NULL AUTO_INCREMENT,
        `e_addr`        VARCHAR(45) NOT NULL,

        PRIMARY KEY (`e_addr`),
        UNIQUE KEY `e_id` (`e_id`)

) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8


CREATE TABLE `c_email` (

        `c_id`          INT(11) NOT NULL,
        `e_id`          INT(11) NOT NULL,

        PRIMARY KEY (`c_id`,`e_id`),
        KEY `e_id` (`e_id`),

        CONSTRAINT `c_email_ibfk_1` FOREIGN KEY (`c_id`)
                REFERENCES `company` (`c_id`)
                ON DELETE CASCADE
                ON UPDATE CASCADE,

        CONSTRAINT `c_email_ibfk_2` FOREIGN KEY (`e_id`)
                REFERENCES `email` (`e_id`)
                ON DELETE CASCADE
                ON UPDATE CASCADE

) ENGINE=InnoDB DEFAULT CHARSET=utf8


CREATE TABLE `b_email` (

        `b_id`          INT(11) NOT NULL,
        `e_id`          INT(11) NOT NULL,

        PRIMARY KEY (`b_id`,`e_id`),
        KEY `e_id` (`e_id`),

        CONSTRAINT `b_email_ibfk_1` FOREIGN KEY (`b_id`)
                REFERENCES `branch` (`b_id`)
                ON DELETE CASCADE
                ON UPDATE CASCADE,

        CONSTRAINT `b_email_ibfk_2` FOREIGN KEY (`e_id`)
                REFERENCES `email` (`e_id`)    
                ON DELETE CASCADE
                ON UPDATE CASCADE

) ENGINE=InnoDB DEFAULT CHARSET=utf8


-- Example of query
-- Retrieving all e-mails of a given branch
SELECT e_addr
        FROM email      AS _em
        JOIN b_email    AS _be ON _be.e_id = _em.e_id
        JOIN branch     AS _br ON _br.b_id = _be.b_id
        WHERE b_name = @bra2;

-- How to retrieve all e-mails related to a given company
-- (e-mails from the company itself and also from all of its branches)?
-- ?
Was it helpful?

Solution

No, you don't need a cursor for this. You can do this with SQL -- much better than a cursor. It is something like:

select *
from ((select ce.c_id, e.email
       from c_email ce join
            email e
            on e.e_id = ce.e_id
      ) union all
      (select b.c_id, e.email
       from branch b join
            b_email be
            on b.b_id = be.b_id join
            email e
            on be.e_id = e.e_id
      )
     ) e
where ce.c_id = X;

EDIT:

You can add b_id into the second subquery but not the first. Perhaps you could do:

select *
from ((select ce.c_id, e.email, NULL as b_id
       from c_email ce join
            email e
            on e.e_id = ce.e_id
      ) union all
      (select b.c_id, e.email, b.b_id
       from branch b join
            b_email be
            on b.b_id = be.b_id join
            email e
            on be.e_id = e.e_id
      )
     ) e
where ce.c_id = X
order by c_id, b_id;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top