Grouping MySQL data - mysql

I have this table, lets call it table one.
+----+---------+-----------------+
| id | link_id | url |
+----+---------+-----------------+
| 1 | 1 | www.example.com |
| 2 | 1 | www.abc.com |
| 3 | 1 | www.test.com |
| 4 | 1 | www.t1.com |
| 5 | 1 | www.newtest.com |
| 6 | 1 | www.testing.com |
| 7 | 1 | www.abc.com |
| 8 | 1 | www.example.com |
| 9 | 1 | www.web1.com |
| 10 | 1 | www.web2.com |
| 11 | 2 | www.dear.com |
| 12 | 2 | www.google.com |
| 13 | 2 | www.flowers.com |
| 14 | 2 | www.yahoo.com |
| 15 | 2 | www.abc.com |
| 16 | 2 | www.dell.com |
| 17 | 2 | www.web.com |
| 18 | 2 | www.example.com |
| 19 | 2 | www.test.com |
| 20 | 2 | www.abc.com |
+----+---------+-----------------+
20 rows in set (0.00 sec)
The link_id is sort the primary identifier in the table. It tells me which urls appear in link 1, link 2 , etc.
What I want to acomplish is:
1. Get all the unique URLs,
2. Show which links the URL belongs to
So an example output would be:
+-----------------+---------+
| url | link_id |
+-----------------+---------+
| www.example.com | 1 |
| www.example.com | 2 |
| www.abc.com | 1 |
| www.abc.com | 2 |
| www.test.com | 1 |
| www.test.com | 2 |
| www.t1.com | 1 |
| www.newtest.com | 1 |
| www.testing.com | 1 |
| www.web1.com | 1 |
...and so on.
So you can see that www.example.com appears twice since it is associated with both links 1 and 2, but web1.com appears only once since it belongs only to link 1.
I have tried several different group by but I only end up scratching my head even more.
Any help is appreciated. Here is the table dump if anyone needs:
CREATE TABLE IF NOT EXISTS `table1` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`link_id` tinyint(3) unsigned DEFAULT NULL,
`url` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=21 ;
INSERT INTO `table1` (`id`, `link_id`, `url`) VALUES
(1, 1, 'www.example.com'),
(2, 1, 'www.abc.com'),
(3, 1, 'www.test.com'),
(4, 1, 'www.t1.com'),
(5, 1, 'www.newtest.com'),
(6, 1, 'www.testing.com'),
(7, 1, 'www.abc.com'),
(8, 1, 'www.example.com'),
(9, 1, 'www.web1.com'),
(10, 1, 'www.web2.com'),
(11, 2, 'www.dear.com'),
(12, 2, 'www.google.com'),
(13, 2, 'www.flowers.com'),
(14, 2, 'www.yahoo.com'),
(15, 2, 'www.abc.com'),
(16, 2, 'www.dell.com'),
(17, 2, 'www.web.com'),
(18, 2, 'www.example.com'),
(19, 2, 'www.test.com'),
(20, 2, 'www.abc.com');

Wouldn't a DISTINCT list work? Does order matter?
SELECT DISTINCT url, link_id
FROM `table1`
ORDER BY 1, 2

Unless I'm misunderstanding the question, it sounds like all you need is a DISTINCT clause:
select distinct url, link_id from table1;

SELECT url, GROUP_CONCAT(link_id)
FROM table1
GROUP
BY url;
That'll give you all the distinct URLs, each with a list of link ids

Select url, link_id
From Table1
Group By url, link_id

select * from table group by link_id,url

Well imho you should group by both link_id and url, and than maybe sort by url so the same urls are together.
SELECT url, link_id FROM table1
ORDER BY url
GROUP BY url, link_id

Unless I'm missing something:
SELECT DISTINCT url, link_id FROM table1;

Related

MySQL conditional row update based on other tables

I have the following MySQL tables:
CREATE TABLE notification
(`id` int, `person_id` int, `rule_id` int, `account_id` int, `account_display_name` varchar(16))
;
INSERT INTO notification
(`id`, `person_id`, `rule_id`, `account_id`, `account_display_name`)
VALUES
(1, 1, 1, 1, 'Muad''Dib'),
(2, 1, 1, 2, 'Kwisatz Haderach'),
(3, 1, 2, 2, 'Kwisatz Haderach'),
(4, 2, 1, 3, 'Duncan'),
(5, 2, 2, 4, 'Duncan Idaho')
;
CREATE TABLE person
(`id` int, `name` varchar(6), `organization_id` int)
;
INSERT INTO person
(`id`, `name`, `organization_id`)
VALUES
(1, 'paul', 1),
(2, 'duncan', 1),
(3, 'paul', 2),
(4, 'duncan', 2),
(5, 'paul', 3),
(6, 'duncan', 3)
;
CREATE TABLE account
(`id` int, `display_name` varchar(16), `person_id` int)
;
INSERT INTO account
(`id`, `display_name`, `person_id`)
VALUES
(1, 'Muad''Dib', 1),
(2, 'Kwisatz Haderach', 1),
(3, 'Duncan', 2),
(4, 'Duncan Idaho', 2),
(5, 'Muad''Dib', 3),
(6, 'Kwisatz Haderach', 3),
(7, 'Duncan', 4),
(8, 'Duncan Idaho', 4),
(9, 'Muad''Dib', 5),
(10, 'Kwisatz Haderach', 5),
(11, 'Duncan', 6),
(12, 'Duncan Idaho', 6)
;
CREATE TABLE organization
(`id` int, `name` varchar(17))
;
INSERT INTO organization
(`id`, `name`)
VALUES
(1, 'atreides'),
(2, 'atreides_dev'),
(3, 'atreides_research')
;
CREATE TABLE rule
(`id` int, `name` varchar(14))
;
INSERT INTO rule
(`id`, `name`)
VALUES
(1, 'bug'),
(2, 'false_positive')
;
Conceptually, the system in question generates a notification when an event occurs that is considered relevant to person. Whether or not a notification gets generated is determined by rule (the relation between person and rule is defined elsewhere, but that's outside the scope of this question). Every notification that gets generated for a person is specifically related to an account owned by that person, and it also contains the (denormalized) account_display_name of the account.
Notice that a person is also related to exactly one organization.
Currently, I have a set of notifications (with related accounts) for multiple persons in a particular organization. But I need to move these notifications to different replica organizations (with replica persons and accounts) based on the rule that caused the notification.
Below is an example of the type of migration I'm trying to perform.
State of related tables
person
+----+--------+-----------------+
| id | name | organization_id |
+----+--------+-----------------+
| 1 | paul | 1 |
| 2 | duncan | 1 |
| 3 | paul | 2 |
| 4 | duncan | 2 |
| 5 | paul | 3 |
| 6 | duncan | 3 |
+----+--------+-----------------+
organization
+----+-------------------+
| id | name |
+----+-------------------+
| 1 | atreides |
| 2 | atreides_dev |
| 3 | atreides_research |
+----+-------------------+
account
+----+------------------+-----------+
| id | display_name | person_id |
+----+------------------+-----------+
| 1 | Muad'Dib | 1 |
| 2 | Kwisatz Haderach | 1 |
| 3 | Duncan | 2 |
| 4 | Duncan Idaho | 2 |
| 5 | Muad'Dib | 3 |
| 6 | Kwisatz Haderach | 3 |
| 7 | Duncan | 4 |
| 8 | Duncan Idaho | 4 |
| 9 | Muad'Dib | 5 |
| 10 | Kwisatz Haderach | 5 |
| 11 | Duncan | 6 |
| 12 | Duncan Idaho | 6 |
+----+------------------+-----------+
rule
+----+----------------+
| id | name |
+----+----------------+
| 1 | bug |
| 2 | false_positive |
+----+----------------+
Initial state of notifications
+----+-----------+---------+------------+----------------------+
| id | person_id | rule_id | account_id | account_display_name |
+----+-----------+---------+------------+----------------------+
| 1 | 1 | 1 | 1 | Muad'Dib |
| 2 | 1 | 1 | 2 | Kwisatz Haderach |
| 3 | 1 | 2 | 2 | Kwisatz Haderach |
| 4 | 2 | 1 | 3 | Duncan |
| 5 | 2 | 2 | 4 | Duncan Idaho |
+----+-----------+---------+------------+----------------------+
End state of notifications
+----+-----------+---------+------------+----------------------+
| id | person_id | rule_id | account_id | account_display_name |
+----+-----------+---------+------------+----------------------+
| 1 | 3 | 1 | 5 | Muad'Dib |
| 2 | 3 | 1 | 6 | Kwisatz Haderach |
| 3 | 5 | 2 | 10 | Kwisatz Haderach |
| 4 | 4 | 1 | 7 | Duncan |
| 5 | 6 | 2 | 12 | Duncan Idaho |
+----+-----------+---------+------------+----------------------+
As you can see, the person_id and account_id of the notifications have been updated based on the notification's rule_id. Specifically:
Every notification generated by the bug rule (ID 1) was moved to the corresponding person and account replicas in the atreides_dev organization (ID 2).
Every notification generated by the false_positive rule (ID 2) was moved to the corresponding person and account replicas in the atreides_research organization (ID 3).
I've written a SQL query that (I believe) selects the correct notification.person_id and notification.account_id based on notification.rule_id, but I'm unsure of the best way to use this in an UPDATE statement, such that every notification gets updated correctly.
Here is the SELECT:
select p_replica.id, acc_replica.id as account_id
from (select p.name, person_id, rule_id, account_id, account_display_name from notification n
inner join person p
on n.person_id = p.id
where p.organization_id = 1
and n.rule_id in (1)) as notifications
inner join person p_replica
on p_replica.name = notifications.name
and p_replica.organization_id = 2
inner join account acc_replica
on acc_replica.person_id = p_replica.id
and acc_replica.display_name = notifications.account_display_name;
Notice that the SELECT specifies an origin organization (ID 1), a destination organization (ID 2), and a rule whose notifications need to be migrated. Recall that this is based on a mapping of rule to destination organization. In other words, selecting all updated notifications would require one execution of this query per mapping of rule -> organization.
What would an UPDATE query for performing this migration look like?
Here is a SQL Fiddle to play around with.

How to sum the values of column on duplicate key?

I have a table like this:
// mytable
+----+--------+-------+-------+
| id | name | key | value |
+----+--------+-------+-------+
| 1 | jack | 1 | 10 |
| 2 | peter | 1 | 5 |
| 3 | jack | 2 | 5 |
| 4 | ali | 1 | 2 |
| 5 | jack | 1 | 5 |
| 6 | jack | 1 | 10 |
| 7 | bert | 4 | 2 |
| 8 | peter | 2 | 10 |
| 9 | bert | 4 | 5 |
+----+--------+-------+-------+
Now I want to sum the numbers of value where both name and key are identical. So, I want this output:
// mynewtable
+----+--------+-------+-------+
| id | name | key | value |
+----+--------+-------+-------+
| 1 | jack | 1 | 25 |
| 2 | peter | 1 | 5 |
| 3 | jack | 2 | 5 |
| 4 | ali | 1 | 2 |
| 7 | bert | 4 | 7 |
| 8 | peter | 2 | 10 |
+----+--------+-------+-------+
Is it possible to I do that?
Edit: How can I do that for insert?
// mytable
+----+--------+-------+-------+
| id | name | key | value |
+----+--------+-------+-------+
| 1 | jack | 1 | 25 |
| 2 | peter | 1 | 5 |
| 3 | jack | 2 | 5 |
| 4 | ali | 1 | 2 |
| 7 | bert | 4 | 7 |
| 8 | peter | 2 | 10 |
+----+--------+-------+-------+
Inserting these rows:
+----+--------+-------+-------+
| 10 | jack | 1 | 5 |
+----+--------+-------+-------+
+----+--------+-------+-------+
| 11 | bert | 1 | 2 |
+----+--------+-------+-------+
What I want: (output)
// mynewtable
+----+--------+-------+-------+
| id | name | key | value |
+----+--------+-------+-------+
| 1 | jack | 1 | 30 |
| 2 | peter | 1 | 5 |
| 3 | jack | 2 | 5 |
| 4 | ali | 1 | 2 |
| 7 | bert | 4 | 7 |
| 8 | peter | 2 | 10 |
| 11 | bert | 1 | 2 |
+----+--------+-------+-------+
You have to group by more columns.
select name, key, sum(value) from mytable group by name, key;
Group by name, key
select name, key, sum(value) as value
from mytable group by name,key
check this
CREATE TABLE #testing_123
([id] int, [name] varchar(5), [key] int, [value] int)
;
INSERT INTO #testing_123
([id], [name], [key], [value])
VALUES
(1, 'jack', 1, 10),
(2, 'peter', 1, 5),
(3, 'jack', 2, 5),
(4, 'ali', 1, 2),
(5, 'jack', 1, 5),
(6, 'jack', 1, 10),
(7, 'bert', 4, 2),
(8, 'peter', 2, 10),
(9, 'bert', 4, 5)
;
query used was
select min(id) id ,name,[key],sum(value) value from #testing_123 group by name,[key] order by 1
output after insert
For the first part (to get the id column in the way requested), you could work along:
INSERT INTO mynewtable
(id, name, `key`, `value`)
SELECT
MIN(id), name, `key`, SUM(`value`)
FROM mytable
GROUP BY name, `key`
;
Now, provided mynewtable is defined with a unique index on name and key like
CREATE TABLE mynewtable
(id INT, name VARCHAR(5), `key` INT, `value` INT, UNIQUE (name, `key`));
you'd get the requested result with
INSERT INTO mynewtable
(id, name, `key`, `value`)
VALUES
(10, 'jack', 1, 5),
(11, 'bert', 1, 2)
ON DUPLICATE KEY UPDATE `value` = `value` + VALUES(`value`)
;
Beware:
It requires the unique index on name and key to work.
It might not work correctly, if there are other unique indexes and/or a primary key on the same table as well.
NB:
Please try to avoid the use of reserved words such as value and key for, e.g., column names.

What is happening when using DISTINCT?

Here is my table and the data contained in it:
Table: first
+----------+------+
| first_id | data |
+----------+------+
| 1 | 5 |
| 2 | 6 |
| 3 | 7 |
| 4 | 6 |
| 5 | 7 |
| 6 | 5 |
| 7 | 7 |
| 8 | 6 |
| 9 | 5 |
| 10 | 7 |
+----------+------+
Table: second
+-----------+----------+----------+
| second_id | first_id | third_id |
+-----------+----------+----------+
| 1 | 1 | 2 |
| 2 | 2 | 3 |
| 3 | 3 | 4 |
| 4 | 4 | 2 |
| 5 | 5 | 3 |
| 6 | 6 | 4 |
| 7 | 7 | 2 |
| 8 | 8 | 2 |
| 9 | 9 | 4 |
| 10 | 10 | 4 |
+-----------+----------+----------+
My intention is to get the list of third_ids ordered by data field. Now, I ran the following query for that.
SELECT
third_id, data
FROM
first f JOIN second s ON ( s.first_id = f.first_id )
ORDER BY
data ASC;
And I get the following result as expected.
+----------+------+
| third_id | data |
+----------+------+
| 4 | 5 |
| 2 | 5 |
| 4 | 5 |
| 2 | 6 |
| 3 | 6 |
| 2 | 6 |
| 2 | 7 |
| 4 | 7 |
| 4 | 7 |
| 3 | 7 |
+----------+------+
The following query is also work as expected.
SELECT
third_id
FROM
first f JOIN second s ON ( s.first_id = f.first_id )
ORDER BY
data ASC;
with output
+----------+
| third_id |
+----------+
| 4 |
| 2 |
| 4 |
| 2 |
| 3 |
| 2 |
| 2 |
| 4 |
| 4 |
| 3 |
+----------+
Then I ran the following.
SELECT DISTINCT
third_id
FROM
first f JOIN second s ON ( s.first_id = f.first_id )
ORDER BY
data ASC;
But, here I get an unexpected result:
+----------+
| third_id |
+----------+
| 2 |
| 3 |
| 4 |
+----------+
Here, 3 must be after 2 and 4, since I am ordering on the data field. What am I doing wrong? Or do I have to go for a different strategy.
Note:
This scenario happens on my project. The tables provided here doesn't belong to original database. It is created by me to explain the problem. Original tables contain thousands of rows.
I am inserting database dump if you would like to experiment with the data:
--
-- Table structure for table `first`
--
CREATE TABLE IF NOT EXISTS `first` (
`first_id` int(11) NOT NULL AUTO_INCREMENT,
`data` int(11) NOT NULL,
PRIMARY KEY (`first_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=11 ;
--
-- Dumping data for table `first`
--
INSERT INTO `first` (`first_id`, `data`) VALUES
(1, 5),
(2, 6),
(3, 7),
(4, 6),
(5, 7),
(6, 5),
(7, 7),
(8, 6),
(9, 5),
(10, 7);
--
-- Table structure for table `second`
--
CREATE TABLE IF NOT EXISTS `second` (
`second_id` int(11) NOT NULL AUTO_INCREMENT,
`first_id` int(11) NOT NULL,
`third_id` int(11) NOT NULL,
PRIMARY KEY (`second_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=11 ;
--
-- Dumping data for table `second`
--
INSERT INTO `second` (`second_id`, `first_id`, `third_id`) VALUES
(1, 1, 2),
(2, 2, 3),
(3, 3, 4),
(4, 4, 2),
(5, 5, 3),
(6, 6, 4),
(7, 7, 2),
(8, 8, 2),
(9, 9, 4),
(10, 10, 4);
You probably want to do something like
SELECT third_id
FROM first JOIN second USING (first_id)
GROUP BY third_id
ORDER BY aggregatesomething(data)
that is min(data) or max(data) or whatever.
Doing a SELECT DISTINCT requires the database to order the values in the column(s) as that is the most efficient way to find the distinct values. As far as I'm aware ORDER BY clauses that do not contain columns that are outputted in the query do not get honoured (SQL SERVER won't accept the query) as it is not clear what it would mean to order by something that did not participate.
You may use a subquery -
SELECT DISTINCT third_id FROM (
SELECT
third_id
FROM
first f JOIN second s ON ( s.first_id = f.first_id )
ORDER BY
data ASC
) t;
It will help to select and sort all data firstly, then to select distinct values.
I had this exact problem before. I finally came up with a simple solution, almost seems too simple. You need to use a subquery as a column of the select query. In that subquery is where you will do the ordering by date. When you do it all in a single query with ORDER BY happens before the JOIN. You want to order first, so go with the subquery. http://nathansnoggin.blogspot.com/2009/04/select-distinct-with-order-by.html

MySQL subquery/complex query question, tracking state changes

I have a table that tracks contact class state changes by date. The question that I am trying to answer is what is the current state of all contacts on a certain date.
DROP TABLE IF EXISTS `contact_class_state`;
CREATE TABLE `contact_class_state` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`contact_id` int unsigned DEFAULT NULL, -- the contact
`contact_class` int unsigned,
`state_date` date,
PRIMARY KEY (`id`),
INDEX (`contact_id`)
) DEFAULT CHARSET=utf8;
INSERT INTO `contact_class_state` (`contact_id`, `contact_class`, `state_date`) VALUES
(1, 1, '2011-01-01'),
(2, 1, '2011-01-01'),
(3, 1, '2011-01-01'),
(4, 1, '2011-01-01'),
(5, 1, '2011-01-01'),
(1, 2, '2011-02-01'),
(3, 2, '2011-02-01'),
(5, 2, '2011-02-01'),
(1, 1, '2011-02-15'),
(5, 3, '2011-03-01');
For example, the following query:
SELECT contact_id, contact_class, state_date
FROM contact_class_state
WHERE state_date <= '2011-02-27'
ORDER BY contact_id, state_date DESC
returns
+------------+---------------+------------+
| contact_id | contact_class | state_date |
+------------+---------------+------------+
| 1 | 1 | 2011-02-15 |
| 1 | 2 | 2011-02-01 |
| 1 | 1 | 2011-01-01 |
| 2 | 1 | 2011-01-01 |
| 3 | 2 | 2011-02-01 |
| 3 | 1 | 2011-01-01 |
| 4 | 1 | 2011-01-01 |
| 5 | 2 | 2011-02-01 |
| 5 | 1 | 2011-01-01 |
+------------+---------------+------------+
While this is technically correct, I only need the first (or last if sorted ASC) row for each contact_id as the latest date will always give me current state of the contact, per the below:
+------------+---------------+------------+
| contact_id | contact_class | state_date |
+------------+---------------+------------+
| 1 | 1 | 2011-02-15 |
| 2 | 1 | 2011-01-01 |
| 3 | 2 | 2011-02-01 |
| 4 | 1 | 2011-01-01 |
| 5 | 2 | 2011-02-01 |
+------------+---------------+------------+
I am pretty sure a sub or a complex query would do the trick but I am having a mental block with the SQL. I am also open to other approaches to solve this issue.
Thanks!
If your query is in fact what you want (except then grouped by contact_id), then do exactly that.
SELECT * FROM
(SELECT contact_id, contact_class, state_date
FROM contact_class_state
WHERE state_date <= '2011-02-27'
ORDER BY contact_id, state_date DESC) table1
GROUP BY contact_id
This is tested and works perfect.

Need help with a complex MySQL query

I'm struggling to get a final result set for a 3 table hierarchical set of data. Hopefully, the diagrams will indicate what I have and what I'm trying to do. Briefly, my final result set (below) should easily allow me to define a dynamic number of checkboxes in my web site, while also allowing me to define whether the boxes are checked, all from within a single result set. I believe that since the data is normalized, I should be able to get a single result set, but I can't get my head wrapped around this on... Can anyone help??
TABLE A TABLE B TABLE C
MEMBER CONTACT ALERT
(pk)$member_id -> (pk)$contact_id -> (pk)$alert_id
(fk)$member_id (fk)$contact_id
$alert_type ->
-> 'local', 'state', 'nation'
Example of my filter criteria is member_id = 1 AND alert_type = 'local'
* = results of filter member_id = 1
TABLE MEMBERS A
+----------+----------+
|member_id | Name |
+----------+----------+
| 1 | Alan | *
| 2 | Brad |
| 3 | Doug |
| 4 | Flo |
+---------------------+
TABLE CONTACTS B
+--------------------------------------------------------------------+
| contact_id | member_id | email | phone | Name |
+------------+-------------+---------------+--------------+----------+
| 1 | 1 | a#gmail.com | | Alex | *
| 2 | 1 | b#gmail.com | 123-456-7890 | Bob | *
| 3 | 3 | c#gmail.com | | Cris |
| 4 | 1 | d#gmail.com | | Dan | *
| 5 | 2 | e#gmail.com | | Ed |
| 6 | 1 | f#gmail.com | | Fran | *
| 7 | 1 | g#gmail.com | 212-323-1111 | Greg | *
| 8 | 2 | h#gmail.com | | Hans |
| 9 | 3 | i#gmail.com | | Ida |
| 10 | 1 | j#gmail.com | 945-555-1212 | Jeff | *
| 11 | 2 | k#gmail.com | 945-555-1212 | Karl |
| 12 | 3 | l#gmail.com | | Leo |
+--------------------------------------------------------------------+
# = resutls of filter alert_type = 'local'
TABLE CONTACTS_SELECTED C
+-----------------------------------------+
| alert_id | contact_id | alert_type |
+------------+------------+---------------+
| 1 | 1 | local | * #
| 2 | 1 | state | *
| 3 | 3 | state |
| 4 | 5 | local |
| 5 | 5 | state |
| 6 | 6 | nation | *
| 7 | 7 | local | * #
| 8 | 8 | nation |
| 9 | 10 | local | *
| 10 | 12 | state |
+-------------------------+---------------+
REQUIRED OUTPUT
+------------------------------------------------------------------------------------+
|member_id | contract_id | email | phone | Name | alert_type |
+----------+--------------+---------------+--------------+----------+----------------+
| 1 | 1 | a#gmail.com | | Alex | local |
| 1 | 2 | b#gmail.com | 123-456-7890 | Bob | NULL |
| 1 | 4 | d#gmail.com | | Dan | NULL |
| 1 | 6 | f#gmail.com | | Fran | nation |
| 1 | 7 | g#gmail.com | 212-323-1111 | Greg | local |
| 1 | 10 | j#gmail.com | 945-555-1212 | Jeff | local |
+------------------------------------------------------------------------------------+
With this result set, I should be easily able to FOREACH my way through all 6 records and create a checkbox for each record, and flag those records with 'local' as checked. Can anyone help with setting up this complex query?
--
-- Table structure for table `contacts`
--
CREATE TABLE IF NOT EXISTS `contacts` (
`contact_id` int(12) NOT NULL AUTO_INCREMENT,
`member_id` int(12) NOT NULL,
`email` varchar(30) NOT NULL,
`phone` varchar(15) NOT NULL,
`name` varchar(30) NOT NULL,
PRIMARY KEY (`contact_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=13 ;
--
-- Dumping data for table `contacts`
--
INSERT INTO `contacts` (`contact_id`, `member_id`, `email`, `phone`, `name`) VALUES
(1, 1, 'a#gmail.com', '', 'Alex'),
(2, 1, 'b#gmail.com', '123-456-7890', 'Bob'),
(3, 3, 'c#gmail.com', '', 'Cris'),
(4, 1, 'd#gmail.com', '987-654-3210', 'Dan'),
(5, 2, 'e#gmail.com', '', 'Ed'),
(6, 1, 'f#gmail.com', '', 'Fran'),
(7, 2, 'h#gmail.com', '234-567-8901', 'Hans'),
(8, 3, 'i#gmail.com', '', 'Ida'),
(9, 1, 'g#gmail.com', '', 'Greg'),
(10, 1, 'j#gmail.com', '456-789-0123', 'Jeff'),
(11, 2, 'k#gmail.com', '945-555-1212 ', 'Karl'),
(12, 3, 'l#gmail.com', '', 'Leo');
CREATE TABLE IF NOT EXISTS `contacts_selected` (
`alert_id` int(12) NOT NULL AUTO_INCREMENT,
`contact_id` int(12) NOT NULL,
`alert_type` varchar(6) NOT NULL,
PRIMARY KEY (`alert_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=12 ;
--
-- Dumping data for table `contacts_selected`
--
INSERT INTO `contacts_selected` (`alert_id`, `contact_id`, `alert_type`) VALUES
(1, 1, 'local'),
(2, 1, 'state'),
(3, 3, 'state'),
(4, 5, 'local'),
(5, 5, 'state'),
(6, 6, 'nation'),
(7, 7, 'local'),
(8, 8, 'nation'),
(9, 10, 'local'),
(10, 12, 'state'),
(11, 1, 'nation');
CREATE TABLE IF NOT EXISTS `alert_types` (
`alert_type` varchar(6) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
--
-- Dumping data for table `alert_types`
--
INSERT INTO `alert_types` (`alert_type`) VALUES
('local'),
('state'),
('nation');
SOLUTION:
$alert_type = 'local';
// choices are local, state, nation
//
SELECT c.contact_id, c.member_id, c.email, c.phone, c.desc, s.alert_type
FROM contact c
LEFT JOIN contact_select s
ON c.contact_id = s.contact_id
WHERE c.member_id = 1 AND c.contact_id NOT IN
(SELECT cs.contact_id FROM contact_select cs WHERE cs.alert_type = '$alert_type')
GROUP BY c.contact_id
UNION
SELECT * FROM
(SELECT c.contact_id, c.member_id, c.email, c.phone, c.desc, s.alert_type
FROM contact c
LEFT JOIN contact_select s
ON c.contact_id = s.contact_id
WHERE c.member_id = 1
AND s.contact_id
IN (SELECT cs.contact_id FROM contact_select cs WHERE cs.alert_type = '$alert_type')) z
WHERE z.alert_type = '$alert_type'
This should give you your desired output.
SELECT C.member_id, C.contact_id, C.email, C.phone, C.name, S.alert_type
FROM CONTACTS C
LEFT OUTER JOIN CONTACTS_SELECTED S
ON C.contact_id = S.contact_id
WHERE member_id = 1
select member_id, cs.contract_id, c.email, c.phone, c.name, cs.alert_type
FROM contact c
LEFT JOIN contact_selected cs on cs.contact_id = c.contact_id
WHERE c.member_id = 1
Not sure i understand well what do you mean but maybe you're looking for thiS?
I would try this:
select `c`.`contact_id`, `member_id`, `email`, `phone`, `name`, `alert_type` from contacts `c`
left join contacts_selected `s` on `c`.`contact_id` = `s`.`contact_id`
where member_id=1
group by `c`.`contact_id`
However, two points: One, it's not clear to me how you want to narrow the result set to select only one of the alert types. Two, your sample data and your insert statments contain slightly different data. That's not a problem, but it is a little confusing at first.