Mysql WHERE not working in table with multiple joins - mysql

I am developing a EAV system for multiple entities (Product, Company,...)
I will tell the problem at the end.
The database structure is the following:
EAV_ENTITY
This table will give me a list of all available Entities, like:
1 | Product
2 | Company
Structure:
+-------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+----------------+
| id | int(11) unsigned | NO | PRI | NULL | auto_increment |
| model | varchar(255) | NO | | | |
+-------+------------------+------+-----+---------+----------------+
EAV_ATTRIBUTE
This table have a list of attributes, the ref is a mnemonic for getting the attributes by query easier. I add here the entity_type_id that is related with the table eav_entity because I want to limit each attribute to only one entity.
+----------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------+------------------+------+-----+---------+----------------+
| id | int(11) unsigned | NO | PRI | NULL | auto_increment |
| entity_type_id | int(11) unsigned | NO | MUL | NULL | |
| ref | varchar(50) | NO | UNI | | |
| name | varchar(255) | NO | UNI | | |
+----------------+------------------+------+-----+---------+----------------+
EAV_VALUE
This table have the values related to the attribute, values would be: red, green, orange, for attribute "color"
+-----------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+------------------+------+-----+---------+----------------+
| id | int(11) unsigned | NO | PRI | NULL | auto_increment |
| attribute_id | int(11) unsigned | NO | MUL | NULL | |
| value | varchar(255) | NO | MUL | NULL | |
+-----------------+------------------+------+-----+---------+----------------+
EAV_ATTRIBUTE_VALUE
+----------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------+------------------+------+-----+---------+----------------+
| id | int(11) unsigned | NO | PRI | NULL | auto_increment |
| entity_id | int(11) unsigned | YES | | NULL | |
| entity_type_id | int(11) unsigned | YES | MUL | NULL | |
| value_id | int(11) | YES | | NULL | |
+----------------+------------------+------+-----+---------+----------------+
Here I make all the "magic", I make a query making a relation between an entity(type, id) and all the values related and the attribute that the value belongs to.
My query is this one
SELECT
e.model,
av.entity_id,
a.id as category_id,
a.ref as category_ref,
v.id as value_id
FROM eav_entity as e
RIGHT JOIN eav_attribute_value as av
ON e.id = av.entity_type_id
LEFT JOIN eav_value as v
ON v.id = av.value_id
LEFT JOIN eav_attribute as a
ON v.attribute_id = a.id
WHERE e.model = 'App\Product'
PROBLEM & QUESTION
When I add the statement WHERE e.model ='Whatever' I dont get any result.
And it is supposed to be filter. But without the WHERE statement I get the results as expected.
I think that it might be a problem related to the way I am doing the joins.
A real example without WHERE e.model
+-------------+-----------+-------------+---------------------------+----------+
| model | entity_id | category_id | category_ref | value_id |
+-------------+-----------+-------------+---------------------------+----------+
| App\Product | 13 | 2 | product_development_phase | 2 |
| App\Product | 13 | 2 | product_development_phase | 3 |
| App\Product | 13 | 4 | product_therapeutics | 58 |
| App\Company | 13 | 4 | product_therapeutics | 58 |
+-------------+-----------+-------------+---------------------------+----------+

AS #Uuerdo said, I need to add a second backslash as escape character to interpret the second one as a real backslash.
The query will result in the next below:
SELECT
e.model,
av.entity_id,
a.id as category_id,
a.ref as category_ref,
v.id as value_id
FROM eav_entity as e
RIGHT JOIN eav_attribute_value as av
ON e.id = av.entity_type_id
LEFT JOIN eav_value as v
ON v.id = av.value_id
LEFT JOIN eav_attribute as a
ON v.attribute_id = a.id
WHERE e.model = "App\\Product"

Related

INSERT into Mysql table from table2, comparing variables in both tables

Ok, I have two tables, Region and Cities and I need to link them together using the id from regions. At present a common code is used which does not work for my use case.
Region Table:
+--------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| country_code | varchar(255) | NO | MUL | NULL | |
| code | varchar(255) | NO | | NULL | |
| name | varchar(255) | NO | | NULL | |
+--------------+--------------+------+-----+---------+----------------+
City Table
+--------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| country_code | varchar(255) | NO | MUL | NULL | |
| name | varchar(255) | NO | | NULL | |
| state | varchar(255) | NO | | NULL | |
| ascii_name | varchar(255) | NO | | NULL | |
| latitude | double | NO | | 0 | |
| longitude | double | NO | | 0 | |
| timezoneid | varchar(255) | NO | | NULL | |
| region_id | int(11) | YES | | NULL | |
+--------------+------------------+------+-----+---------+----------------+
In the City table, I have added the int region_id and I would like to populate it from the region table based on some city.country_code = region.country_code AND region.code = city.state.
Something along these lines:
INSERT INTO city (region_id) SELECT id FROM region WHERE city.country_code = region.country_code AND city.state = region.code;
That's the essence of what I am trying to do, MySql work is not a strong point.
Any help, appreciated!
I think you want an update statement (that modifies data on existing rows) rather than an insert (which creates new rows).
If so, you can use MySQL's update ... join syntax:
update city c
inner join region r
on c.country_code = r.country_code
and c.state = r.code
set c.region_id = r.id

Write a mysql not in query as join

I have two tables vtiger_crmentity and vtiger_crmentityrel (from open source project vtiger).
vtiger_crmentity
+--------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------+--------------+------+-----+---------+-------+
| crmid | int(19) | NO | PRI | NULL | |
| smcreatorid | int(19) | NO | MUL | 0 | |
| smownerid | int(19) | NO | MUL | 0 | |
| modifiedby | int(19) | NO | MUL | 0 | |
| setype | varchar(30) | NO | | NULL | |
| description | text | YES | | NULL | |
| createdtime | datetime | NO | | NULL | |
| modifiedtime | datetime | NO | | NULL | |
| viewedtime | datetime | YES | | NULL | |
| status | varchar(50) | YES | | NULL | |
| version | int(19) | NO | | 0 | |
| presence | int(1) | YES | | 1 | |
| deleted | int(1) | NO | MUL | 0 | |
| label | varchar(255) | YES | MUL | NULL | |
+--------------+--------------+------+-----+---------+-------+
vtiger_crmentityrel
+-----------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------+--------------+------+-----+---------+-------+
| crmid | int(11) | NO | | NULL | |
| module | varchar(100) | NO | | NULL | |
| relcrmid | int(11) | NO | | NULL | |
| relmodule | varchar(100) | NO | | NULL | |
+-----------+--------------+------+-----+---------+-------+
I am trying to get a list of contacts which are not present in the crmentityrel table (in the relcrmid column to be specific). I can do this via a subquery but it is taking about 2 minutes to complete (for about 20k records in each table).
I tried to convert the query to a join but i am surely doing something wrong as i keep getting wrong values (compared to the subquery which i know is right).
Any help is greatly appreciated. Please tell me if you need any details from my side
Edit -
My working query (with subquery) is -
SELECT crmid, label from vtiger_crmentity
WHERE deleted = 0 and setype="Contacts"
and crmid not in (select relcrmid from vtiger_crmentityrel
where relmodule="Contacts")
To convert a not in to a join, the idea is to use left join and where:
SELECT c.crmid, c.label
FROM vtiger_crmentity c left join
vtiger_crmentityrel cr
on c.crmid = cr.relcrmid and relmodule = 'Contacts'
WHERE c.deleted = 0 and c.setype = 'Contacts' and cr.relcrmid is null;
I should point out that the above is not exactly equivalent. NOT IN returns no rows if the subquery returns even a single NULL value. The above behaves more intuitively.
Because of the behavior of NOT IN with NULL values, NOT EXISTS is a better choice. Plus, it often has better performance as well:
SELECT crmid, label
FROM vtiger_crmentity c
WHERE deleted = 0 and setype = 'Contacts' AND
NOT EXISTS (SELECT relcrmid
FROM vtiger_crmentityrel cr
WHERE cr.relmodule = 'Contacts' and cr.relcrmid = c.crmid
);

MySQL right join with count not working properly

I have the following tables:
MOVIES
+-------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| user_id | int(11) | YES | MUL | NULL | |
| title | varchar(40) | NO | | NULL | |
| description | text | NO | | NULL | |
| created_at | datetime | YES | | NULL | |
| updated_at | datetime | YES | | NULL | |
+-------------+-------------+------+-----+---------+----------------+
MOVIE_VOTES
+------------+------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| user_id | int(11) | YES | MUL | NULL | |
| movie_id | int(11) | YES | MUL | NULL | |
| like | tinyint(1) | YES | | NULL | |
| created_at | datetime | YES | | NULL | |
| updated_at | datetime | YES | | NULL | |
+------------+------------+------+-----+---------+----------------+
And I want to query all the movies sorted by the number of likes they have. I have this query:
SELECT *, COUNT(*) AS count_likes
FROM movie_votes
RIGHT JOIN movies
ON movies.id=movie_votes.movie_id
WHERE movie_votes.like = 1
GROUP BY movie_id
ORDER BY count_likes;
And this returning the movies sorted by the number of likes BUT not the movies that haven't be voted(liked) yet. For some reason the RIGHT join works as simple join.
I have searched for some relative answers but cant find anything helpful.
You should specify a column name when doing outer joins so that it will count only the non-null values
SELECT movies.id,
movies.user_id,
movies.title,
movies.description,
movies.created_at,
movies.updated_at,
COUNT(movie_votes.movie_id) AS count_likes
FROM movies
LEFT JOIN movie_votes
ON movies.id = movie_votes.movie_id
AND movie_votes.like = 1
GROUP BY movies.id,
movies.user_id,
movies.title,
movies.description,
movies.created_at,
movies.updated_at
ORDER BY count_likes
The condition movie_votes.like = 1 should be put in the ON clause so it will filter the rows in table movie_votes first before joining it to table movies.

sql joining three tables using inner joins

in my database I have 3 tables named items, manufacturers and items_manufacturers. manufacturers has a HAS:MANY relation with items_manufacturers
My items table
+---------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------+--------------+------+-----+---------+----------------+
| id | bigint(20) | NO | PRI | NULL | auto_increment |
| code | varchar(25) | NO | MUL | NULL | |
| item_category | varchar(100) | NO | | NULL | |
| item_desc | varchar(500) | NO | | NULL | |
| reorder_point | int(11) | NO | | NULL | |
| unit | varchar(45) | NO | | NULL | |
+---------------+--------------+------+-----+---------+----------------+
My manufacturers table
+------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+----------------+
| id | bigint(20) | NO | PRI | NULL | auto_increment |
| code | varchar(25) | NO | | NULL | |
| name | varchar(250) | NO | | NULL | |
| address | varchar(750) | NO | | NULL | |
| contact_no | varchar(50) | NO | | NULL | |
+------------+--------------+------+-----+---------+----------------+
My items_manufacturers table
+-----------------+---------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+---------------+------+-----+---------+----------------+
| id | bigint(20) | NO | PRI | NULL | auto_increment |
| item_id | bigint(20) | NO | MUL | NULL | |
| manufacturer_id | bigint(20) | NO | MUL | NULL | |
| unit_cost | decimal(20,2) | NO | | NULL | |
| vendor_id | bigint(20) | NO | | NULL | |
+-----------------+---------------+------+-----+---------+----------------+
In my result table I want items_id, items_desc, name of manufacturer from manufacturers table and manufacturer_id. The relation I have is
items.id=items_manufacturers.item_id and
manufacturers.id=items_manufacturers.manufacturer_id.
I tried using inner joins for three tables but not working.
The query I tried
select
items_manufacturers.id,
items.item_desc,
item_manufacturers.manufacturer_id,
manufacturer.name
from items_manufacturers
INNER JOIN items ON items_manufacturers.item_id=items.id
INNER JOIN manufacturers ON items_manufacturers.manufacturer_id=manufacturers.id
Anybody kindly help me with this, I am stuck up from a long time
I used this following code and got the result you were trying to get. This code may solve your problem:
select a.name,b.manufacturer_id,c.id,c.item_desc
from manufacturers as a
inner join
item_manufacturers as b
on b.manufacturer_id=a.id
inner join item as c
on c.id=b.item_id

Why isn't this JOIN working?

Database Tables
ss_merchant
+----------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------+--------------+------+-----+---------+----------------+
| pk_merchant_id | bigint(20) | NO | PRI | NULL | auto_increment |
| name | varchar(45) | YES | | NULL | |
| website | varchar(100) | YES | | NULL | |
+----------------+--------------+------+-----+---------+----------------+
ss_merchant_store
+----------------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------------+-------------+------+-----+---------+----------------+
| pk_merchant_store_id | bigint(20) | NO | PRI | NULL | auto_increment |
| fk_pk_merchant_id | bigint(20) | YES | | NULL | |
| street | varchar(20) | YES | | NULL | |
| city | varchar(20) | YES | | NULL | |
| postcode | varchar(8) | YES | | NULL | |
| telephone | varchar(15) | YES | | NULL | |
| email | varchar(45) | YES | | NULL | |
+----------------------+-------------+------+-----+---------+----------------+
ss_merchant_store_rating
+-----------------------------+------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------------------+------------+------+-----+---------+----------------+
| pk_merchant_store_rating_id | bigint(20) | NO | PRI | NULL | auto_increment |
| fk_pk_merchant_store_id | bigint(20) | NO | | NULL | |
| rating | int(1) | YES | | NULL | |
+-----------------------------+------------+------+-----+---------+----------------+
and my query:
SELECT *
FROM ss_merchant
JOIN ss_merchant_stores
ON ss_merchant.pk_merchant_id = ss_merchant_stores.fk_pk_merchant_id
JOIN ss_merchant_store_rating
ON ss_merchant_stores.pk_merchant_store_id = ss_merchant_store_rating.fk_pk_merchant_store_id
There isn't anything specifically wrong with your join but it does make the assumption that all three tables have at least one row for each merchant_id. If you want to allow for non-existant merchant_store_rating rows consider using a LEFT JOIN
If there is no matching row for the
right table in the ON or USING part in
a LEFT JOIN, a row with all columns
set to NULL is used for the right
table. You can use this fact to find
rows in a table that have no
counterpart in another table:
SELECT left_tbl.* FROM left_tbl LEFT JOIN right_tbl
ON left_tbl.id = right_tbl.id WHERE right_tbl.id IS NULL;
This example finds all rows in
left_tbl with an id value that is not
present in right_tbl (that is, all
rows in left_tbl with no corresponding
row in right_tbl). This assumes that
right_tbl.id is declared NOT NULL.