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.
Related
I have the following tables:
jobs:
-------------------------------------------------------
| id | title | slug |
-------------------------------------------------------
employments:
-------------------------------------------------------
| id | job_type|
-------------------------------------------------------
applications:
-------------------------------------------------------
| id | job_opening_id| application_state_id|
-------------------------------------------------------
application_states
-------------------------------------------------------
| id | name|
-------------------------------------------------------
I want to create a query that counts the different application_state_id's
----------------------------------------------------------------------------
| j.title| j.slug| e.job_type | candidates | hired
----------------------------------------------------------------------------
This is the query that i have at the moment:
SELECT
j.title,
j.slug,
e.job_type,
count(a1.application_state_id) as candidates,
count(a2.application_state_id) as hired
FROM
jobs AS j
INNER JOIN employments AS e ON j.employment_id = e.id
LEFT JOIN applications AS a1 ON a1.job_opening_id = job_openings.id
LEFT JOIN application_states AS as ON as.id = a1.application_state_id
LEFT JOIN applications AS a2 ON a2.job_opening_id = j.id AND a2.application_state_id = 1
GROUP BY
a1.application_state_id,
a2.application_state_id,
j.id,
j.title,
j.slug
I thought i could create 2 joins and set the application_state_id, but all that does is count records double.
What do i need to change in this query? I hope someone can help me.
You did not provide sample data, but as I see from your code
you are joining the table applications twice,
so by the 1st to get the total number of candidates
and by the 2nd to get the total number of hired candidates.
I think you can drop the 2nd join and do conditional counting to get the total number of hired candidates.
Also:
the select statement must include the columns that you group by and any aggregated columns
and I don't see why you need to join to the application_states table.
Try this:
SELECT
j.title,
j.slug,
e.job_type,
count(a.application_state_id) as candidates,
sum(case when a.application_state_id = 1 then 1 else 0 end) as hired
FROM
jobs AS j INNER JOIN employments AS e ON j.employment_id = e.id
LEFT JOIN applications AS a ON a.job_opening_id = job_openings.id
GROUP BY
j.title,
j.slug,
e.job_type
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.
Note: I see similar SQL questions but nothing specific to MySQL on how to solve this issue.
I have the following query which sums a product value by day for a period based on the sale date from the sales table, products can be filtered based on categories which is why I need to have the left join, categories also need to be displayed along with the rest of the information. Due to project requirements I can not do any processing outside of this MySQL query.
select `sales`.`sell_date` as `date`, SUM(product_value.value) as value from
`sales` left join `products` on `sales`.`product_id` = `products`.`id` left join
`product_value` on `product_value`.`product_id` = `products`.`id` and
`sales`.`sell_date` BETWEEN product_value.date_from AND
IFNULL(product_value.date_to, '2999-01-01')
left join `product_product_category` on `product_product_category`.`product_id`
= `products`.`id` left join `product_categories` on
`product_product_category`.`product_category_id` = `product_categories`.`id`
left join `users` on `sales`.`seller_id` = `users`.`id`
where `sales`.`sell_date` between "2016-02-01" and "2016-02-29" and `product_value`.`deleted_at` is null
and `products`.`id` in ("178") and `sales`.`deleted_at` is null group by
`sales`.`sell_date` order by `sales`.`sell_date` asc
The above query will get a sum which is doubled or trippled when there is two or three categories for a product. Categories can be things such as color, size, etc.
The sum works fine when I remove the following from the query which has lead me to believe that the many to many relationship here is causing the issue.
left join `product_product_category` on `product_product_category`.`product_id` =
`products`.`id` left join `product_categories` on
`product_product_category`.`product_category_id` = `product_categories`.`id`
How can I prevent this left join from causing my SUM() to give me the wrong total value?
Using Distinct on product_value.value will not work as product values can be the same for many products.
My tables
sales
ID | sell_date | product_id
----------------------------
2 | 2016-02-15 | 178
product_value
ID | value | date_from | date_to | product_id
-------------------------------------------------
1 | 500 | 2016-01-01 | NULL | 178
2 | 500 | 2015-01-01 | 2015-12-01 | 392
products
ID | name
----------
178 | ProductName
product_product_category
product_id | product_category_id
--------------------------------
178 | 1
178 | 2
product_categories
ID | name
---------
1 | Red
2 | Large
So to make this clear, if I run the above query on these tables I would get value = 1000 but value should be 500. How can I make sure SUM() shows the correct value when joining many to many relationships?
You can remove left join and add filters in where as subquery
...
where
...
and exists (
select 1
from `product_product_category`
inner join `product_categories` on `product_product_category`.`product_category_id` = `product_categories`.`id`
where `product_product_category`.`product_id` = `products`.`id`
and ....
and ....
)
...
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.
I have three tables I'm trying to select data from, each table has a pID which is what I want the join to be based on. When I run the following query I still end up with three pID fields.
What is wrong with my select join statement?
SELECT * FROM Player p
LEFT JOIN AvgStats a ON a.pID = p.pID
LEFT JOIN MisTotal m ON m.pID = p.pID;
Player Table
pID | Name | Age
AvgStats Table
pID | 3pt% | gamePoints
MisTotal Table
pID | Fouls | rebounds
I want to creat a table that returns
pID | Name | Age | 3pt% | gamePoints | Fouls | rebounds
If I'm understanding your question correctly, just remove * from your query and specify the field(s) you want -- in this case, p.pID:
SELECT p.pId FROM Player p
JOIN AvgStats a ON a.pID = p.pID
JOIN MisTotal m ON m.pID = p.pID;
Given your edits, this should work:
SELECT p.pID, p.Name, p.Age, a.`3pt%`, a.gamePoints, m.fouls, m.rebounds
...
Just make sure you include the backticks around the column with the special character.