Performing Searches over Many-to-Many Relationships - php

I have a database which (for the purposes of this example), has two tables that have a many to many association (with an intermediary table for holding the associations). Here is there structure:
Table A:
+-----+-------+-------+-------+
| aID | aCol1 | aCol2 | aCol3 |
+-----+-------+-------+-------+
| 1 | foo | aoo | doo |
+-----+-------+-------+-------+
| 2 | bar | aar | dar |
+-----+-------+-------+-------+
| 3 | baz | aaz | daz |
+-----+-------+-------+-------+
Table B:
+-----+-------+
| bID | bCol1 |
+-----+-------+
| 1 | alice |
+-----+-------+
| 2 | bob |
+-----+-------+
Association Table:
+-----+-----+
| aID | bID |
+-----+-----+
| 1 | 1 |
+-----+-----+
| 2 | 2 |
+-----+-----+
| 3 | 1 |
+-----+-----+
If I want to search for information by aCol2 LIKE 'aa%' AND the row has an association to bCol1 = 'bob' (i.e. resulting in only row aID = 2), how could I assemble a MySQL Query that could do something similar?
p.s. Sorry for the poor clarity, I am not exactly sure of the wording, but in a nut shell, it is about searching for data from one record that (for the purposes of this) has a 1-* relationship via a connecting table to a number of records, by information that exists in the entire set

SELECT
a.*
FROM
table_b b
INNER JOIN associations ab ON (b.b_id = ab.b_id)
INNER JOIN table_a a ON (ab.a_id = a.a_id)
WHERE
b.col_1 = 'bob'
AND a.col_2 LIKE 'aa%'

It's been awhile, but I believe this should work:
SELECT
*
FROM
A,
B,
associations
WHERE
A.aCol2 LIKE 'aa%' AND
A.aID = associations.aID AND
associations.bID = B.bID
You have to do 2 inner joins to combine the 3 tables.

Related

Relation among three tables: proper query and design suggestion

I have three tables (MySQL):
families where I define the products' families
products where I define the products
families_products where I relate families and products
------------------- -------------------- ------------------------
| familyID | code | | productID | code | | familyID | productID |
|----------|------| |-----------|------| |----------|-----------|
| 1 | p | | 1 | p3 | | 1 | 1 |
| 2 | a | | 2 | a5 | | 1 | 3 |
| 3 | e | | 3 | p1 | | 1 | 6 |
------------------- | 4 | e7 | | 2 | 2 |
| 5 | a2 | | 2 | 5 |
| 6 | p4 | | 3 | 4 |
-------------------- ------------------------
I have two questions:
Is this design convenient or is it better drop the families_products table putting the familyID relation directly into the table products?
With a design like this one, if I have the familyID how can I retrieve the products->code? I wrote this query but a query structure like this one would work if I drop the families_products table putting the familyID relation directly into the table products as said before, not in the case of a third relational table.
'SELECT productID, code, img
FROM products AS a
INNER JOIN families_products AS b
ON b.productID=a.productID
WHERE b.familyID=' . $families[$key]["familyID"]
Your data structure is fine.
If you have at most one familyID per product, then you should put the family in the products table. You should use the junction table (your structure) if a product can be part of multiple families.
As for your query, it is fine. I would use better table aliases:
SELECT p.productID, p.code, ??.img
FROM products p INNER JOIN
families_products fp
ON f.productID = fp.productID
WHERE fp.familyID = ' . $families[$key]["familyID"]
If your product only belongs to one product family you can skip the "familiy_product" table and add the familiy_id directly to the product. Only in case a product can be assigned to multipl families you need the "join" table.
With only two tables the SQL is quite easy:
select p.code from family f, product p where f.code ='xx' and p.family_id = f.id

query specific table based on search keyword in mysql

I am creating a search portal in PHP from which user can search for a specific cuisine. In MySQL I have multiple tables for each cuisine and the respective hotel names that offer the cuisine. For example, in table
How can I query a specific cuisine table based on the cuisine search keyword?
So if a user enters 'mexican' as the search query, how can it connect to the 'Table2 - Mexican' and return the hotel names from this table?
Table1 - Chinese
_______________________
| id | hotelname |
|______|______________|
| 1 | hotel1 |
| 2 | hotel2 |
| 3 | hotel3 |
| 4 | hotel4 |
| 5 | hotel5 |
|______|______________|
Table2 - Mexican
_______________________
| id | hotelname |
|______|______________|
| 1 | hotel1 |
| 2 | hotel2 |
| 3 | hotel3 |
| 4 | hotel4 |
| 5 | hotel5 |
|______|______________|
Table3 - Pizza
_______________________
| id | hotelname |
|______|______________|
| 1 | hotel1 |
| 2 | hotel2 |
| 3 | hotel3 |
| 4 | hotel4 |
| 5 | hotel5 |
|______|______________|
Your database concept is very unflexible. I think you should put the cuisines into your database as information (i.e. table content) instead of metadata describing single tables. Tables should generally considered to be static just like the code you write to access the database and its tables. If you implement the cuisines as different tables you would have to hardwire every cuisine into your code.
Here is a suggestion for a better approach:
Create a hotels table to store all the hotels,
Create a cuisines table to store all the different types of cuisines,
Make an additional table to establish the n:m relationship between the hotel and the cuisine.
Example:
hotels: id, name, address, city, telno, email
cuisine: id, name, description
rel: cuisine, hotel (where both are the foreign keys to the
id columns of the respective tables above)
See also:
How to handle a Many-to-Many relationship with PHP and MySQL.
MySQL: Many To Many Relationships ยป Return True
You might want to check this question to create a many-to-many relationship:
many-to-many and many-to-many intersections
I guess what you would like to achieve is something like this:
Table1 - Hotel
_______________________
| id | hotelname |
|______|______________|
| 1 | hotel1 |
| 2 | hotel2 |
| 3 | hotel3 |
| 4 | hotel4 |
| 5 | hotel5 |
|______|______________|
Table2 - Cuisine
____________________________________________
| id | cuisine_name | keywords |
|______|______________|____________________|
| 1 | Chinese | Shandong,Noodles,. |
| 2 | Mexican | Tacos,Beans,... |
| 3 | Itarian | Pizza,Pasta,.. |
|______|______________|____________________|
Table3 - HotelCuisine
___________________________________
| id | hotel_id | cuisine_id |
|______|____________|______________
| 1 | 1 | 2 |
| 2 | 1 | 3 |
| 3 | 2 | 1 |
| 4 | 2 | 2 |
| 5 | 3 | 3 |
|______|____________|_____________|
SQL:
SELECT hotelname, cuisine_name FROM Hotel
INNER JOIN HotelCuisine ON Hotel.id = HotelCuisine.hotel_id
INNER JOIN Cuisine ON Cuisine.id = HotelCuisine.cuisine_id
WHERE keywords like '%pizza%'
Result:
________________________________________
| hotelname | cuisine_name |
|_______________|______________________|
| hotel1 | Itarian |
| hotel3 | Itarian |
|_______________|______________________|
DEMO: http://sqlfiddle.com/#!2/961de/1
Hope this helps
you can check SQL UNION. But instead of having multiple tables with the same fields, you can try normalization to minimize the redundancy and to make queries easier.
Something like:
Hotel Table
-----------------------------
id | hotelname | categoryID
------------------------------
1 | hotel name 1 | 1
2 | hotel name 2 | 2
-----------------------------
Category Table
-------------------
id | categoryname
-------------------
1 | chinese
2 | mexican
------------------
And query as simple as:
SELECT a.hotelname, b,categoryname
FROM hotel_table a
LEFT JOIN category_table b
ON a.categoryID = b.id AND b.categoryname LIKE '%mexican%';

SQL duplicate row

I have a big filter with many options and want to generate the query for sql automaticle and without many code.
GET:
searchvalue=abc
&title=abc
&description=abc
&category=1
&subcategory=2
&zip=7
&city=ke
&country=DE
SQL:
SELECT activity.* FROM activity,subcategory,city,country
WHERE activity.title LIKE '%abc%' OR activity.description LIKE '%abc%'
AND subcategory.SubID = 2
AND city.zip LIKE '%7%'
AND city.City LIKE '%ke%'
AND country.CShort= 'DE'
With this options, I have 1 row in my database.
The answer is this row many times, many many times.
I know that the sql duplicate a row, when a table is not used in a WHERE clausel - but why he do it now and how can I solve that?
Edit: I have a ER, but the database is in german (school project), maybe it help you to understand:
Thanks!
You are doing a cross product by selecting multiple tables. SQL will return every row from the one table combined with every row in the other table.
For example in a database with table a
|------|----------|
| idA | textA |
|------|----------|
| 1 | fooA |
| 2 | barA |
|------|----------|
and table b
|------|----------|
| idB | textB |
|------|----------|
| 1 | fooB |
| 2 | barB |
|------|----------|
when you do
SELECT * FROM a, b
you would get
|------|----------|------|----------|
| idA | textA | idB | textB |
|------|----------|------|----------|
| 1 | fooA | 1 | fooA |
| 1 | fooA | 2 | barA |
| 2 | barA | 1 | fooB |
| 2 | barA | 2 | barB |
|------|----------|------|----------|
To combine these rows logically you do a JOIN. That means you tell in your query which rows belong together. You can do so by JOIN clause or without JOIN clause directly in the WHERE clause.
Back to the example you would do
SELECT * FROM a, b
WHERE a.idA = b.idB
-- or
SELECT * FROM a
JOIN b ON a.idA = b.idB
you would get only 2 rows.
|------|----------|------|----------|
| idA | textA | idB | textB |
|------|----------|------|----------|
| 1 | fooA | 1 | fooA |
| 2 | barA | 2 | barB |
|------|----------|------|----------|
To answer your question:
You have to support JOIN/WHERE clauses to connect your tables activity, subcategory, city and country according to your database schema.
I don't know your table structures but for example clauses like this:
WHERE
...
AND city.country_id = country.id
AND activity.subcategory_id = subcategory.id
AND ...

mysql group by table b, inner join table a for a random

here is my 2 tables, id for a inner join event. i want to do this thing:
in table b, there has 10 albums, i want random get out 4 albums. then each album select one record, the record is random position in the album.
so that i will get 4 records back (these 4 records with no duplicate id), then take these 4 records for a inner join query, to get the title from table a.
here just little records just for test. in the fact, i have 300,000 records in table a and 2,000,000 records in table b.
table a
+-----+-------+
| id | title |
+-----+-------+
| 1 | a1 |
+-----+-------+
| 2 | a2 |
+-----+-------+
| 3 | a3 |
+-----+-------+
| 4 | a4 |
+-----+-------+
| 5 | a5 |
+-----+-------+
| 6 | a6 |
+-----+-------+
table b
+-----+--------+
| id | album |
+-----+--------+
| 1 | album1 |
+-----+--------+
| 2 | album1 |
+-----+--------+
| 3 | album1 |
+-----+--------+
| 6 | album1 |
+-----+--------+
| 2 | album2 |
+-----+--------+
| 3 | album2 |
+-----+--------+
| 5 | album3 |
+-----+--------+
| 6 | album3 |
+-----+--------+
| 3 | album4 |
+-----+--------+
| 2 | album5 |
+-----+--------+
| 4 | album5 |
+-----+--------+
| 5 | album5 |
+-----+--------+
| 1 | album6 |
+-----+--------+
| 3 | album6 |
+-----+--------+
| 2 | album7 |
+-----+--------+
| 4 | album7 |
+-----+--------+
| 1 | album8 |
+-----+--------+
| 5 | album8 |
+-----+--------+
| 3 | album9 |
+-----+--------+
| 2 | album10|
+-----+--------+
| 5 | album10|
+-----+--------+
I am not good at mysql query. In my mind I would do
select * from b group by album order by random() limit 0,4
get back 4 album, then do a inner join query (this query not correct, how to check the b.id no duplicate?)
select * from b inner join a on b.id = a.id where (select id from b where b.album = '".$row['album']."' order by random() limit 1)
I need an easy and quicker method, the best is just use one query. many thanks.
AFAIR, "ORDER BY RAND()" is extremely slow solutions, especially on tables like you have (2 million+ records), so I'd recommend looking at something similar to these kind of articles first: http://www.greggdev.com/web/articles.php?id=6
So, you should know the number of records in your table before running the query and then do something like:
"SELECT * FROM `album` LIMIT 1 OFFSET " . rand(0,$count)
This will return you 1 random row a bit more efficiently, I believe.
Also, I think it's not a good idea to store album references as string in tracks table, you'd rather use a proper integer foreign key album_id referenced to albums.id. Then you can join both tables much fatser. If I were you, I'd do first:
ALTER TABLE `tracks` add column `album_id` int;
UPDATE `tracks` SET `album_id` = SUBSTRING(`album`,5);
Then, after doing this and combining with the solution above, launch something like:
"SELECT * FROM `album` INNER JOIN `tracks`ON `tracks`.`album_id` = `albums`.`id` LIMIT 1 OFFSET " . rand(0,$count)
Since I'm neither an expert on MySQL nor on PHP, I'll try with pseudocode and generic SQL. I have renamed your tables to albums and tracks for sake of readability.
First fetch the four random records to your PHP application:
select id from albums order by random() limit 4
Second, iterate over the resulting result set of four IDs and fetch the corresponding tracks (pseudo-php):
foreach($album_ids as $id):
execute_query("select id from tracks where album_id = ? order by random(), limit 1", $id)
It is not obvious to me how you match your tracks to their albums. You should have something like tracks.album_id as a foreign key to albums.id, that's how I designed my queries. You should adapt as appropriate, the underlying logic behind my solution should remain the same.

MYSQL Joins to retrieve result

I will try to be as explanatory as possible regarding my question. I am using MYSQL/PHP to fetch data from two tables with the structure looking like the following:
table A
+---------+------------+
| userid | username |
+---------+------------+
| 1 | john |
| 2 | doe |
| 3 | lewis |
+---------+------------+
table B
+---------+------------+-----------+
| id |from_userid | to_userid |
+---------+------------+-----------+
| 1 | 1 | 3 |
| 2 | 3 | 2 |
| 3 | 1 | 2 |
| 4 | 2 | 1 |
+---------+------------+-----------+
Am trying to achieve the following:
+---------+------------+----------------------+
| id |sender username| receiver username |
+---------+------------+----------------------+
| 1 | john | lewis |
| 2 | lewis | doe |
| 3 | john | doe |
| 4 | doe | john |
+---------+------------+----------------------+
As you can see, instead of returning the sender or receiver user id, I am returning their username according to Table A.
can I use left or right joins in this scenario? Thanks in advance
Try this
SELECT b.id, sender.username AS sender_username, receiver.username AS receiver_username
FROM tableB AS b
JOIN tableA AS sender ON b.from_userid = sender.userid
JOIN tableA AS receiver ON b.to_userid = receiver.userid
Inner joins would work fine, you just need to do two of them...
Left and right joins are only needed when you want to get all records from one table and some from another table. In this case you have two distinct relationships thus the need for two joins. My MySQL skills are a bit rusty so I don't know if ' or [ are used as separators on the table/field names with spaces.
Select t1.ID, T1.userName as 'Sender userName', T2.username as 'Receiver username'
FROM [Table A] A
INNER JOIN [Table B] T1
on T1.from_userid = A.userID
INNER JOIN [Table B] T2
on T2.to_userid = A.userID

Categories