I've looked at a bunch of questions and solutions regarding many to many queries. I just can't seem to wrap my head around it. Maybe I'm not completely understanding the keywords in MySQL. But...
I have 3 tables. The first table is a list of peoples contact information. The second table is a list of mailing list categories. The third table is an associative table that holds the id's from the first and second table. How would I write a MySQL query to get all the contacts from the contact table that match the VIP list id (which I already have)?
Table 1 (contacts)
id | name | email
-----------------------------
1 | John | john#gmail.com
-----------------------------
2 | Jane | jane#gmail.com
-----------------------------
Table 2 (list_type)
id | list_name |
-----------------
1 | VIP's |
-----------------
2 | Generic |
-----------------
Table 3 (list_contact_joiner)
contact_id | list_type_id |
----------------------------
1 | 2 |
----------------------------
2 | 1 |
----------------------------
This is what I tried but get a syntax error
$listID = 1;
SELECT list_contact_joiner.contact_id
FROM list_contact_joiner
WHERE list_id = $listID AS lcj
INNER JOIN contact_lists AS cl
ON cl.id = lcj.contact_id
SELECT c.*
FROM contacts c
JOIN list_contact_joiner j on j.contact_id = c.id
JOIN list_type t on j.list_type_id = t.id
WHERE t.list_name = 'VIP''s'
If you already have the id of VIP's then you need to join only 2 tables
SELECT c.*
FROM contacts c
JOIN list_contact_joiner j on j.contact_id = c.id
WHERE j.list_type_id = 1
Yes the join statement is not correct. It should be something as
select
c.name,
c.email,
lt.list_type
from list_contact_joiner lcj
join contacts c on c.id = lcj.contact_id
join list_type lt on lt.id = lcj.list_type_id
where
lt.id = ?
If you are looking for data with $listID = 1; then the place holder is
lt.id = ?
Your syntax error is because all the table specification (FROM and JOIN) has to occur before the WHERE and you got your alias syntax a little messed up - this should work better:
$listID = 1;
SELECT lcj.contact_id
FROM list_contact_joiner AS lcj
INNER JOIN contact_lists AS cl
ON cl.id = lcj.contact_id
WHERE lcj.list_id = $listID
But if all you are trying to do is get the contact_id then you don't need to do any join at all...
SELECT contact_id
FROM list_contact_joiner
WHERE list_id = $listID
If you need the rest of the contact information then you might try this:
SELECT contact.*
FROM list_contact_joiner
JOIN contacts ON contacts.id = list_contact_joiner.contact_id
WHERE list_id = $listID
Note that you still don't need to get the list_type table at all.
Related
I'm trying to write a query to calculate the total charged on a per client basis, where a client has a registered property in one table, where they have not been invoiced in another, but I am not sure how to write the 'Not In' portion of the query so that it does not have to reference a specific ID.
The query listed below is part of a larger query to calculate overall totals, but I am struggling with this particular piece.
I have tried to modify the 'Not In' portion of the query to remove the reference to a specific ID and do a Group By the client_id, but this did not return any results. I also tried a GROUP_CONCAT, but I'm not sure I implemented that properly.
I'm not sure if a) what I'm trying to do is possible, or b) if there's a much better way to go about doing what I'm trying to accomplish, but I feel like if I could write this in another subquery, I'd be in much better shape, but I can't wrap my head around how to write it or even another way to approach the problem.
SELECT
clients.client_id,
clients.first_name,
clients.last_name,
SUM(total_charged) AS total_charged
FROM
clients
LEFT JOIN
(SELECT
clients.client_id,
route_property_reg.route_property_reg_id,
route_property_reg.rate_charged AS total_charged
FROM
clients
LEFT JOIN properties ON clients.client_id = properties.client_id
LEFT JOIN route_property_reg ON properties.property_id = route_property_reg.property_id
WHERE
route_property_reg.route_property_reg_id NOT IN (
SELECT DISTINCT
invoice_lines.route_property_reg_id
FROM
clients
LEFT JOIN invoices ON clients.client_id = invoices.client_id
LEFT JOIN invoice_lines ON invoices.invoice_id = invoice_lines.invoice_id
WHERE
clients.client_id = 1)
GROUP BY clients.client_id)
AS charged ON clients.client_id = charged.client_id
GROUP BY clients.client_id
SQL Fiddle
An alternative Fiddle with another attempt but similar results: SQL Fiddle
Expected/Anticipated Output would be:
| client_id | first_name | last_name | total_charged |
|-----------|------------|-----------|---------------|
| 1 | John | Doe | 200 | - (route-properties # 1 and 4)
| 2 | Jane | Doe | 200 | - (route-property #5)
| 3 | John | Smith | (null) |
| 4 | Jane | Smith | (null) |
After a lot of guess and check, the following works for me:
SELECT
clients.client_id,
clients.first_name,
COALESCE(SUM(total_charged), 0) AS total_charged
FROM
clients
LEFT JOIN (SELECT
c.client_id,
a.route_property_reg_id,
COALESCE(SUM(ROUND((a.rate_charged * (1 + (tax_types.rate / 100))), 2)), 0) AS total_charged
FROM
route_property_reg a
LEFT JOIN properties ON a.property_id = properties.property_id
LEFT JOIN clients c ON properties.client_id = c.client_id
LEFT JOIN tax_types ON a.tax_rate_charged = tax_types.tax_type_id
WHERE
NOT EXISTS( SELECT
NULL
FROM
invoice_lines b
LEFT JOIN invoices ON b.invoice_id = invoices.invoice_id
LEFT JOIN clients d ON invoices.client_id = d.client_id
WHERE
b.route_property_reg_id = a.route_property_reg_id
AND d.client_id = c.client_id)
GROUP BY client_id) AS charged ON clients.client_id = charged.client_id
GROUP BY clients.client_id
I have these three tables movies, category and relationship as shown below.
movies--
-----------------------
id|name|duration|
1 |x |5 mins |
2 |y |10 mins |
----------------------
category--
-----------------------
id|type |value |
1 |genre |action |
2 |language|english |
3 |genre |thriller |
4 |language|spanish |
------------------------
relationship--
id| movie_id|category_id|
1 |1 | 2 |
2 |1 | 3 |
------------------------------
i want a query that will fetch both genre and language for the movie in a single query.
below is the expected output.
name|duration|language|genre |
x |5 mins |english |thriller|
--------------------------------
in short i want to use the type column twice.
Please help
You need mysql pivot table for that. That is turn some columns into row data. The following query will produce what you want:
SELECT
m.name,
m.duration,
MAX(IF(c.type = 'language', c.value, NULL)) AS language,
MAX(IF(c.type = 'genre', c.value, NULL)) AS genre
FROM movies AS m
INNER JOIN relationship AS r ON m.id = r.movie_id
INNER JOIN category AS c ON r.category_id = c.id
WHERE m.name = 'x'
GROUP BY m.name;
That will produce:
| name | duration | language | genre |
| x | 5 mins | english | thriller |
See DEMO
Step 1: Join all the three table together. Now you get all the category infos for each movie.
Step 2: Select what you want from the big combined table.
Step 3: Use two subquery to satisfy your special needs for language and genre.
Step 4: Add a LIMIT 1 to avoid redundant records.
The final query might be something like this:
SELECT name, duration, (SELECT value FROM t WHERE type = 'language' AND name = 'x') AS language, (SELECT value FROM t WHERE type = 'genre' AND name = 'x') AS genre
FROM
(
SELECT m.name, m.duration, c.type FROM movies AS m
JOIN relationship AS r ON m.id = r.movie_id
JOIN category AS c ON r.category_id = c.id
) AS t LIMIT 1;
Note:
Replace your own query condition for WHERE clause.
This query might not be strictly syntax correct. Please fix it by yourself.
One method uses two joins, one for each type:
select m.*, cl.value as language, cg.language as genre
from movies m join
relationships r
on m.id = r.movie_id left join
categories cl
on cl.id = r.category_id and type = 'language' left join
categories cg
on cg.id = r.category_id and type = 'genre';
Note that movies typically have only one language, but they can have multiple genres. If this is the case you will get a separate row for each genre.
Im trying to join 5 tables that look somewhat like this
post table
ID | product | user-us | make-id | dealer-id | pending | .... 30 other columns ... |
make table
ID | make |
state table
prefix | state | city | zip
members table
ID | name | email | password | zip | dealer-id
dealer table
ID | dealer name | city | state | zip | address | phone
MySql query looks like this
SELECT *
FROM `post` AS p
JOIN (`make` AS m, `state` AS s, `members` AS mb, `dealer` AS d)
ON (p.Make = m.id AND p.state = s.id AND p.id = mb.id AND mb.dealer-id = d.id)
WHERE p.pending != '1'
The problem is this query only returns rows that member.dealer-id = dealer.id, And if i use a LEFT JOIN, it returns all the correct rows, BUT all columns in tables make, state, members and dealer will be NULL. which it shouldn't be because i need the info in those tables.
Is there away i can only join the dealer table if member.dealer-id is > 0? i could add a row in the dealer table with id 0, but there has to be a better way.
Once you code your joins in the normal way, use LEFT JOIN only on the dealer table:
SELECT *
FROM post AS p
JOIN make AS m ON p.Make = m.id
JOIN state AS s ON p.state = s.id
JOIN`members AS mb ON p.id = mb.id
LEFT JOIN dealer AS d ON mb.dealer_id = d.id
WHERE p.pending != '1'
This will automatically only join to dealer if the member.dealer-id is greater than zero.
btw, I have never seen a query join coded like yours before. If I had, I would have assumed it would not execute due to a syntax error - it looks that strange.
Hope you can help me with correct syntax of a SQL query (using MySQL 5.5.25).
I have 3 tables:
data
data_tmp
users
data table is empty - has it's own structure but no rows
data:
id | name | who
----------------
data_tmp:
id | cars | who
---------------
1 | lambo| 2
users
who | name |
------------
2 | john
My query is:
SELECT DISTINCT
users.name,
(SELECT count(id) FROM data WHERE who = 1) as number,
data_tmp.cars
FROM
users, data, data_tmp
WHERE
users.who = 2
AND data_tmp.who = 2
AND data.who = 2
This of course returns an empty result (there is no row that suits to all parameters because data is empty).
What I would like to achieve is:
users.name | number | data_tmp.cars |
-------------------------------------
john | 0 | lambo |
I am sure I have to - in some way - use LEFT JOIN but can't find correct syntax. Hope you can help me.
Kalreg
give this a try (without using subquery)
SELECT a.name, b.cars, count(c.id) as number
FROM users a
INNER JOIN data_tmp b
on a.who = b.who
LEFT JOIN data c
on a.who = c.who AND
a.name = c.name
WHERE a.who = 2
GROUP BY a.name, b.cars
this works on different servers:
MSSQL SERVER # SQLFIDDLE
MYSQL # SQLFIDDLE
Your assumption is right: you have to use left JOIN, in this way :
SELECT DISTINCT users.name, (SELECT count(id) FROM data WHERE who = 1) as number, data_tmp.cars
FROM users
JOIN data_tmp USING (who)
LEFT JOIN data USING(who)
WHERE users.who = 2
I have following two tables 'USERS' and 'GROUPS':
USERS
-id
-name
-groupid
GROUP
-id
-name
I'd like to return all users along with their group's name and group id. It should be an outer join on group id field correct?
A simple INNER JOIN should be enough:
SELECT `USERS`.*, `GROUP`.name AS group_name
FROM `USERS`, `GROUP`
WHERE `USERS`.groupid = `GROUP`.id
You're going to want to look at the JOIN statement
Doing this from my phone, so pardon any moderately incorrect syntax, but something a long the lines of
Edit: other guy's syntax is better. It's too early here
You can use a LEFT JOIN between users and groups so that users who are not in a group still show up in the result set, but with group name and id NULL:
SELECT
a.*,
b.name AS group_name
FROM
users a
LEFT JOIN
`group` b ON a.group_id = b.id
Side note: Ensure that you're encasing the table name group in backticks because it is a reserved keyword.
The result-set should look something like:
id | name | group_id | group_name
-----------------------------------------------------------------------------
1 | John | 5 | ThisIsGroup5
3 | Tim | 3 | ThisIsGroup3
6 | NotInGroup | NULL | NULL
Changing LEFT to INNER in the above query would INNER JOIN the two tables and exclude the user "NotInGroup" from the result-set.