I have some issues with multiple joins in MysQL
I have 3 tables:
cms_data_company
cms_data_company_categories
cms_datasrc_category
Sample records from: cms_data_company:
+----+-----------+------------+
| id | name | address |
+----+-----------+------------+
| 1 | Name1 | Samplestr1 |
+----+-----------+------------+
| 2 | Name2 | Samplestr2 |
+----+-----------+------------+
| 3 | Name3 | Samplestr3 |
+----+-----------+------------+
Sample records from: cms_data_company_categories ( It contains Company_id field and category_id ) Point is that there is serveral records for one company_id )
+----+-----------+------------+
| id | company_id| category_id|
+----+-----------+------------+
| 1 | 2 | 14 |
+----+-----------+------------+
| 2 | 2 | 11 |
+----+-----------+------------+
| 3 | 1 | 15 |
+----+-----------+------------+
Sample records from: cms_datasrc_category ( Here is a issue that i need only that rows where:
datasrc = 1 AND parent = 0
+----+-----------+------------+-----------+
| id | datasrc | parent |name |
+----+-----------+------------+-----------+
| 1 | 1 | 0 |category1 |
+----+-----------+------------+-----------+
| 2 | 2 | 0 |category2 |
+----+-----------+------------+-----------+
| 3 | 3 | 5 |category3 |
+----+-----------+------------+-----------+
What i would like to recive is that:
All fields from cms_data_company and field name from cms_datasrc_company
I need to join it as follows:
id from cms_data_company match with company_id from cms_data_company_categories
Then matched category_id from
cms_data_company_categories with ID from cms_datasrc_category (only these records where datasrc=0 and parent=0)
Return name as new column with all field from cms_data_company
I think I could make it messy, but my MySQL statement is as follows:
select * ,cms_datasrc_category.name_en
from cms_data_company
LEFT JOIN cms_data_company_categories.company_id
ON cms_data_company.id = cms_data_company_categories.company_id
LEFT JOIN cms_datasrc_category
ON cms_data_company_categories.category_id = cms_datasrc_category.id
WHERE cms_datasrc_category.datasrc = 1 AND cms_datasrc_category.parent = 0
It seems It is working somehow but, there is only records from cms_data_company where query can find something. I would like to change my statemat to show NULLs when There is no matching fields.
It is because WHERE applies to all Query ?
When you use left joins, conditions on all but the first table should be in the on clauses:
SELECT *, cdc.name_en
FROM cms_data_company dc LEFT JOIN
cms_data_company_categories.company_id c
ON dc.id = c.company_id LEFT JOIN
cms_datasrc_category cdc
ON c.category_id = cdc.id AND
cdc.datasrc = 1 AND cdc.parent = 0;
Notes:
Table aliases make a query easier to write and to read.
You should use table aliases for all column references, when your query has more than one table.
The select * already selects all columns from all tables. There is no need to include another column. Or, better yet, list the columns you really need.
The filtering conditions are on the last table, so they are now in the on clause.
Related
I have 2 tables, custom_leads_fields and custom_leads_fields_option. The primary key of custom_leads_fields is saved in custom_leads_fields_option table as c_id.
I need to fetch all the records from custom_leads_fields table where status = 1 and then I also needs matching records from custom_leads_fields_option where status = 1
custom_leads_fields table
c_id | user_id | label | status |
1 | 591 | A | 1 |
2 | 591 | B | 1 |
3 | 591 | C | 0 |
custom_leads_fields_option table
id | c_id | option | status
1 | 2 | yes | 1
2 | 2 | no | 1
3 | 2 | may | 0
4 | 3 | yy | 1
5 | 3 | zz | 1
Output required:
c_id | label | option
1 | A |
2 | B | yes
2 | B | no
It should return records from first table if status = 1 even if records are not available in second table, but if records are available in second table then only those records should be fetched whose status = 1.
I have written a query but it does not return label 'A' because matching records are not available in other table.
SELECT
`custom_leads_fields`.`c_id` AS `field_id`,
`custom_leads_fields_option`.`id` AS `option_id`,
`custom_leads_fields`.`label`,
`custom_leads_fields_option`.`option`
FROM
`custom_leads_fields`
LEFT JOIN
`custom_leads_fields_option`
ON custom_leads_fields.id = custom_leads_fields_option.custom_leads_field_id
WHERE
(`custom_leads_fields`.`user_id`=591)
AND (`custom_leads_fields`.`status`=1)
AND (`custom_leads_fields_option`.`status`= 1)
I think is left join and the label A doesn't have any relationship with custom_leads_fields_option table. So you can't use custom_leads_fields_option.status = 1. You can try this
select clf.*, clfo.*
from custom_leads_fields clf
left join custom_leads_fields_option clfo
on clf.id = clfo.c_id
where clf.status = 1
and (clfo.status = 1 or clfo.status is null);
sqlfiddle
you need to move status condition to join condition , this will give your desired output. All the records from left table and matched record (with status =1 condition) from right table
SELECT
`custom_leads_fields`.`c_id` AS `field_id`,
`custom_leads_fields_option`.`id` AS `option_id`,
`custom_leads_fields`.`label`,
`custom_leads_fields_option`.`option`
FROM
`custom_leads_fields`
LEFT JOIN
`custom_leads_fields_option`
ON custom_leads_fields.id = custom_leads_fields_option.custom_leads_field_id
AND (`custom_leads_fields_option`.`status`= 1) // changed line
// ^^^^^^^^^^^^^^^^^^
WHERE
(`custom_leads_fields`.`user_id`=591)
AND (`custom_leads_fields`.`status`=1)
I have three tables
Table a
+-----+-------+
| aid | value |
+-----+-------+
| 1 | A |
| 2 | B |
| 3 | C |
| 4 | D |
+-----+-------+
Table b
+-----+------+
| bid | name |
+-----+------+
| 1 | A |
| 2 | B |
| 3 | C |
+-----+------+
Table ba (mapping of table a and table b)
+-----+-----+
| bid | aid |
+-----+-----+
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 3 | 2 |
| 1 | 3 |
| 2 | 3 |
| 2 | 4 |
+-----+-----+
From these tables I want a query like
SELECT aid, mapped('true'-if(aid exist in ba) 'false'-otherwise)
FROM a
JOIN b
JOIN ba
WHERE bid=1
to get a result from where I can generate a list
(when bid=1)
A-mapped
B-not mapped
C-mapped
D-not mapped
(when bid=2)
A-mapped
B-not mapped
C-mapped
D-mapped
(when bid=3)
A-mapped
B-mapped
C-not mapped
D-not mapped
Right now I am generating the list in a while loop for all the rows of table 'a' and inside the loop a query is executed for each iteration to check the existence in table 'ba'.
I think this is supposed to be table b independent:
SELECT CONCAT_WS('-', a.value, IF(ba.aid IS NULL, "-not mapped", "-mapped"))
FROM a LEFT JOIN ba ON a.aid = ba.aid AND ba.bid = 1
ORDER BY a.aid
Note: I took "a" table as the base table since your samples included all values from "a" table.
This is a tricky question, but the difficult part is in figuring out how to formulate the query. Once that is out of the way, it is downhill from there. One approach is to use a cross join between the A and B tables to obtain all possible mappings. Then LEFT JOIN to the mapping table to determine which pairs are being mapped and which are not. Try the following query:
SELECT tb.bid, ta.value,
CASE WHEN ba.bid IS NOT NULL THEN 'mapped' ELSE 'not mapped' END AS label
FROM tb INNER JOIN ta -- cross join to obtain all bid/aid pairs
LEFT JOIN ba -- to determine which pairs are mapped/not mapped
ON ta.aid = ba.aid AND tb.bid = ba.bid
ORDER BY tb.bid, ta.value
Demo here:
SQLFiddle
Tables
__________________ ________________________________
|______name________| |____________scores______________|
|___id___|__name___| |_id_|_user-id_|_name-id_|_score_|
| 1 | bob | | 1 | 3 | 1 | 5 |
| 2 | susan | | 2 | 1 | 3 | 4 |
| 3 | geoff | | 3 | 3 | 2 | 3 |
| 4 | larry | | 4 | 2 | 4 | 5 |
| 5 | peter | | 5 | 1 | 1 | 0 |
-------------------- ----------------------------------
Im looking to write a query that returns a RANDOM name from the 'name' table, that the user hasnt scored so far.
So given user '1' for example, it could return 'susan, larry or peter' as user '1' hasnt given them a score yet.
SELECT *
FROM names
LEFT JOIN
votes
ON names.id = votes.name_id
WHERE votes.user_id = 1
AND (votes.score IS NULL);
So far I have this, but it doesnt seem to be working as I would like
(atm it doesnt return a random, but all, but this is wrong)
Any help would be appreciated.
If you are filtering on some field of outer joined table type of join is automatically changed to inner. In your case it's condition
votes.user_id = 1
So you need to move that condition from WHERE to ON
SELECT *
FROM names
LEFT JOIN
votes
ON names.id = votes.name_id and votes.user_id = 1
WHERE (votes.score IS NULL);
Consider moving the condition from WHERE to JOIN ON clause since you are performing an OUTER JOIN else the effect would be same as INNER JOIN
LEFT JOIN votes
ON names.id = votes.name_id
AND votes.user_id = 1
WHERE votes.score IS NULL
ORDER BY RAND();
You could apply :
SELECT name FROM name join scores on name.id=scores.user_id WHERE scores.score=0
You can perform this as a sub-query
SELECT *
FROM names
WHERE id NOT IN (SELECT name_id FROM votes WHERE user_id=1)
ORDER BY RAND()
LIMIT 1
Here is the sqlFiddle
I want to filter the users who have selected entities ,So if I want to filter user with entity say entity having ids "1" and "3" I hope to get the users which have both of these entities.
No of entities selected can vary in number .
Query I am using is
SELECT user_id from user_entities where entity_id IN(1,3)
but for obvious reason it is returing me result as
+----+-----------+---------+--------+
| ID | ENTITY_ID | USER_ID | STATUS |
+----+-----------+---------+--------+
| 1 | 1 | 3 | 1 |
| 2 | 3 | 3 | 1 |
| 7 | 1 | 2 | 1 |
| 29 | 3 | 1 | 1 |
+----+-----------+---------+--------+
So I will apply distinct to it it will give me user id with ids 1,2,3 but I only want user 3 as this is the only user having both entities .
What can be modified to get the exact results
You could join the table to itself specifying both IDs as part of the join condition:
SELECT e1.user_id
FROM user_entities e1
INNER JOIN user_entities e2
ON e1.user_id = e2.user_id AND
e1.entity_id = 1 AND
e2.entity_id = 3;
I'm struggling to work out how to join a couple of tables to get a certain result in a query.
I've got 2 tables:
A [T_Prog] table that has all possible ID1 & ID2 records with the amount of
PRGCASH for each record against its respective MONTHNUMBER.
A [T_ALS] table that contains a proportion of all possible ID1 & ID2 records with the ALSCASH for each of
those records against its respective MONTHNUMBER.
What I want to do is bring the PRGCASH and ALSCASH fields into a single query, matched appropriately to their respective ID1, ID2 and MONTHNUMBER fields.
The uniqueness of a record in each table is a combination of ID1, ID2 and MONTHNUMBER fields.
The problem I have is that the [T_ALS] table contains more entries on MONTHNUMBER against each unique ID1 and ID2 combination than it does in the [T_Prog] table.
So if I do it this way...
SELECT [T_Prog].ID1, [T_Prog].ID2, [T_Prog].MONTHNUMBER, [T_Prog].PRGCASH, [T_ALS].ALSCASH
FROM [T_Prog]
LEFT JOIN [T_ALS] ON ([T_Prog].ID1 = [T_ALS].ID1) AND ([T_Prog].ID2 = [T_ALS].ID2) AND ([T_Prog].MONTHNUMBER = [T_ALS].MONTHNUMBER)
...I get all possible records, but any additional records from [T_ALS] on MONTHNUMBER will be lost as the [T_Prog] table does not have an equivalent record.
If I do it this way...
SELECT [T_ALS].ID1, [T_ALS].ID2, [T_ALS].MONTHNUMBER, [T_Prog].PRGCASH, [T_ALS].ALSCASH
FROM [T_ALS]
LEFT JOIN [T_Prog] ON ([T_ALS].ID1 = [T_Prog].ID1) AND ([T_ALS].ID2 = [T_Prog].ID2) AND ([T_ALS].MONTHNUMBER = [T_Prog].MONTHNUMBER)
...I won't get all possible records as the [T_ALS] table contains only a proportion of all possible records.
Here's a illustration of the 2 tables with example data and the final query table I'm trying to achieve:
Prog table:
|[ID1]|[ID2]|[MONTHNUMBER]|[PRGCASH]|
| 1 | A | 1 | 600 |
| 1 | B | 1 | 500 |
ALS table:
|[ID1]|[ID2]|[MONTHNUMBER]|[ALSCASH]|
| 1 | A | 1 | 100 |
| 1 | A | 2 | 100 |
| 1 | A | 3 | 100 |
Ideal Result:
|[ID1]|[ID2]|[MONTHNUMBER]|[PRGCASH]|[ALSCASH]|
| 1 | A | 1 | 600 | 100 |
| 1 | A | 2 | | 100 |
| 1 | A | 3 | | 100 |
| 1 | B | 1 | 500 | |
This query, tested with Access 2007, returns the result set you want.
SELECT
p1.ID1,
p1.ID2,
p1.MONTHNUMBER,
p1.PRGCASH,
a1.ALSCASH
FROM
T_Prog AS p1
LEFT JOIN T_ALS AS a1
ON
p1.MONTHNUMBER = a1.MONTHNUMBER
AND p1.ID2 = a1.ID2
AND p1.ID1 = a1.ID1
UNION
SELECT
a2.ID1,
a2.ID2,
a2.MONTHNUMBER,
p2.PRGCASH,
a2.ALSCASH
FROM
T_ALS AS a2
LEFT JOIN T_Prog AS p2
ON
a2.MONTHNUMBER = p2.MONTHNUMBER
AND a2.ID2 = p2.ID2
AND a2.ID1 = p2.ID1;