MySQL dynamic JOIN - mysql

Let's say that I have these tables on my db:
items
categories
weapons
shields
swords
And I need to create a join like this:
SELECT items.*, {swords}.*
FROM items
INNER JOIN categories
ON categories.id = items.category_id # <-- here I know that the item is a sword
INNER JOIN {swords}
ON {swords}.item_id = item.id
WHERE items.id = 12
But the {swords} part is dynamic since I found that an item is a sword checkgin the categories.name field.
The query will change if the categories.name is "shield" to this:
SELECT items.*, shields.*
FROM items
INNER JOIN categories
ON categories.id = items.category_id
INNER JOIN shields
ON shields.item_id = item.id
WHERE items.id = 13
I used { and } around the swords to show it like a variable
Thank you for your answer and sorry about my english! :)

Technically, you can only do this with dynamic SQL - which means MySQL's Prepared Statement syntax, or string concatenation to create the query prior to submitting it to the database. Prepared Statements are the preferable choice, due to better SQL injection defense.
You could use LEFT JOINs to the various tables, but it would mean including numerous columns from each of the tables (weapons, shields, swords...) that would be null if the category didn't match. It'd be horrible to try to pull out data from a single query...
PS: Why is there a SWORD table? Wouldn't that be covered by the WEAPON table?

Related

how to select exact values from 5 different tables

Hello guys this my first Q in stackoverflow so i'll be clear with you i'm very new to php so take it easy on me .
right so what am trying to do is i have 5 tables where's the relation have already been set
and i'm trying to show the related categorys and platforms using the game id note that the category has a table on it own and so as the platform then there's two other tables which have the game id and the cat id together and same as for the platform and the game and the field i have in the games table are:
id-->for the game id
name-->for the name of the game
details and image.
and in the game_cat:
g_id and cat_id
then thers the table for the category which has the name and id
and the same for the platform . these are my tables which i'm trying to select from
enter image description here
and my sql is:
SELECT games.*,
game_cat.*,
category.*
FROM games,
game_cat,
category
WHERE games.id='game_cat.g_id'
AND game_cat.g_id='game_cat.cat_id'
AND game_cat.cat_id='category.id'
but it doesn't work on phpmyadmin sql so I've done some research and there's something called join in sql which i'm not familiar with.
any help is appreciated.
Don't use single quotes for column name (when need use eventually backtics)
Use inner join if you have alway columns match (otherwise you left join ) and you can use alias for a compact query
(i have added also the last two tables ...hope the related columns name are right)
SELECT g.*,gc.*,c.* , gp.*, p.*
FROM games g
INNER JOIN game_cat gc on g.id = gc.g_id
INNER JOIN category c on gc.cat_id=c.id
INNER JOIN game_platform gp on g.id = gp.g_id
INNER JOIN platform p on gp.paltform_id=p.id
You need to JOIN between the tables based on the foreign-key relationship between them (if you don't know what this is, go read up on it!). Something like this (I don't know what columns represent the foreign keys, so making this up):
SELECT games.*,
game_cat.*,
category.*
FROM games g
INNER JOIN game_cat gc on (g.game_id = gc.g_id)
INNER JOIN category c on (gc.cat_id = c.cat_id)
WHERE games.id='game_cat.g_id'
AND game_cat.g_id='game_cat.cat_id'
AND game_cat.cat_id='category.id';
This looks like a standard implementation of a many-to-many relationship between games and category - would that be correct?

mysql query with dynamic return column name

I have 3 tables,Products, Languages and Products_translation.
How can I retrieve one Product and all translation at same time in one query ?
I have this
SELECT p.*, pt.description FROM Products p
LEFT JOIN Products_translation pt ON p.id=pt.product_id
LEFT JOIN Languages l ON pt.language =l.code
I have 3 languages, but it only retrieves one field name 'description' and I wanted it to return 3 (the number of languages), with something like description_en, description_es, description_fr
It's possible to make something like pt.description AS 'description'+'l.code' ?
This is a very common question and I'm fairly sure it's been answered many times (for example here: Mysql: joining tables for translation records). Anyway, if you have only 3 languages, just do this:
SELECT p.*, pt_en.description as description_en, pt_es.description as description_es, pt_fr.description as description_fr FROM Products p
LEFT JOIN Products_translation pt_en ON (p.id=pt.product_id and pt.language = 'en')
LEFT JOIN Products_translation pt_es ON (p.id=pt.product_id and pt.language = 'es')
LEFT JOIN Products_translation pt_fr ON (p.id=pt.product_id and pt.language = 'fr')
If you have more than 3, or a varying number, search pivoting or pivot table for more info. It's not easy to do in SQL so usually it's faster to just select your products, select all the translations of those products in a separate query, and construct the result you want outside of the database.

Join on multiple ids

I've been helping a friend out with some of his MySQL queries, and came up with this query. While writing this I kind of wondered if there wasn't a better way to do this:
select offers.*, users.*, items.* from offers
join users on users.id = offers.sender_id
join items on
(items.id = offers.receiver_gets_1)
or
(items.id = offers.receiver_gets_2)
or
(items.id = offers.receiver_gets_3)
or
(items.id = offers.receiver_gets_4)
or
(items.id = offers.sender_gets_1)
or
(items.id = offers.sender_gets_2)
or
(items.id = offers.sender_gets_3)
or
(items.id = offers.sender_gets_4)
where receiver_id = 1;
It kind of made me feel bad, because I really have the feeling I gave him some messed up query (not that he minds). It has left me wondering if there isn't a nicer way to write this down?
I tried looking on google for stuff like these questions:
- Mysql Left Join on multiple conditions
- MySQL how to join tables on two fields
- https://dba.stackexchange.com/questions/33996/which-is-better-many-join-conditions-or-many-where-conditions
But these didn't really offer any other way. I did run in to another question where the answer was set-up the same as my own query.
I know the database could perhaps modeled better, but it's not my database to toy with. I don't really agree with how his tables are built up or anything, but the question remains interesting to me non the less.
You can use IN:
select offers.*, users.*, items.* from offers
join users on users.id = offers.sender_id
join items on
items.id IN (offers.receiver_gets_1, offers.receiver_gets_2, offers.receiver_gets_3, offers.receiver_gets_4,
offers.sender_gets_1, offers.sender_gets_2, offers.sender_gets_3, offers.sender_gets_4)
However, it's generally better to design your schema so you don't have repeated columns like receiver_gets_1, receiver_gets_2, .... Instead, you should have a relation table where each if these is in a different row, then you just need to join with it once to get all the matches.

MYSQL SELECT: check if rowdata exists

In my SQL query i'm checking on different parameters. Nothing strange happens when there is data in each of the tables for the inserted tripcode. But when one table has no data in it I don't get any data at all. Even if the other tables have data. So I need to be able to check if the table has data in it and if it has, I need to select.
SELECT roadtrip_tblgeneral.*,
GROUP_CONCAT(distinct roadtrip_tblhotels.hotel) as hotels,
GROUP_CONCAT(distinct roadtrip_tbllocations.location) as locations,
GROUP_CONCAT(distinct roadtrip_tbltransports.transport) as transports
FROM roadtrip_tblgeneral
INNER JOIN roadtrip_tblhotels
ON roadtrip_tblgeneral.id = roadtrip_tblhotels.tripid
INNER JOIN roadtrip_tbllocations
ON roadtrip_tblgeneral.id = roadtrip_tbllocations.tripid
INNER JOIN roadtrip_tbltransports
ON roadtrip_tblgeneral.id = roadtrip_tbltransports.tripid
WHERE roadtrip_tblgeneral.tripcode = :tripcode
GROUP BY roadtrip_tblgeneral.id
Only the tables with the GROUP_CONCAT in front need the check. I already tried with the keyword EXISTS in front of it.
Thanks in advance.
The INNER JOIN keyword returns rows when there is at least one match in both tables. You can't have a match if there is no data, perhaps you want to use a LEFT JOIN or a FULL JOIN.
Left join will be use as it returns all the data from the table at left, even if there is no matching rows in right table

Avoiding a MySql Loop With Query

I've got three tables.
Table 1 is packages.
Table 2 is package_to_keyword.
Table 3 is keywords.
Packages can be connected to multiple keywords. So if I query package_to_keyword Joining keywords and packages I can search for all packages that relate to a certain keyword. That's the part I understand.
NOW... my question is, how do I retrieve packages that match a LIST of keywords? Right now, in php, I loop a sql statement and then loop through all the results for each keyword and do an array_intersect() to filter down to the packages that show up in all the result sets. However, I'm sure this is bad, because I'm running a query for each keyword when I'm certain SQL is built to handle this type of relationship, I'm just not sure what type of query to perform.
The key is the list of keywords can be any number of words. If I use something like IN ('keyword','array','returns','all','results') I just get a list for all the packages that have a relationship with ANY of the keywords when I just want packages that have a relationship with ALL of the keywords.
Thoughts?
select title
from packages p
inner join pack_to_tag pt on p.index = pt.pIndex
inner join keyworks w on w.index = pt.kindex
where word in ('keyword','array','returns','all','results')
group by title
having count(*) = 5
First, the "PreQuery" (qualified products result) looks only the products joined to keywords that have ANY of the keywords you are looking for, and will ultimately return 1 or more entries. The GROUP BY then confirms however many you ARE EXPECTING... Then join to products for final results.
select
p.*
from
( select ptt.pIndex
from pack_to_tag ptt
join keywords k
on ptt.kindex = k.index
and k.word in ( 'word1', 'word2', 'word3' )
group by
ptt.pIndex
having
count(*) = 3 ) QualifiedProducts
join Products p
on QualifiedProducts.pIndex = p.index