Mysql querying multiple options - mysql

I have a query such as:
SELECT bp.*, b.company
FROM `DBPREFIXwindows_brands_products` bp
LEFT JOIN `DBPREFIXwindows_brands` b ON bp.brand_id = b.id
JOIN Windows_last_submissions ls
WHERE bp.width = ROUND(ls.width)
AND bp.height = ROUND(ls.height)
AND bp.material = ls.chosenmaterial
AND bp.type = ls.type
AND IF
(ls.minimumbid != 'NULL',bp.cost BETWEEN (ls.minimumbid AND ls.maximumbid),bp.cost <= ls.maximumbid)
the field 'chosenmaterial' comes from a select box which can hold multiple options. My question is, within this query - how do I make the WHERE clause work so that if a person chooses more than 1 option, (which obviously separate into row with commas) how can I query anything which includes any and all of those options??

You can use the IN operator for that field. If you can build a list of chosen materials that matches a pattern like:
(material1, material2, material3)
You can make your where clause something like this:
WHERE bp.material IN (material1, material2, material3)
which will pull any rows that have one of those three materials. In a way, it's just a simplified version of having multiple OR statements:
WHERE material = material1 OR material = material2 OR material = material3

Related

Creating a nested join using SQLAlchemy in a database with 3 tables

I want to join three tables together in order to find a value of the third table's id. The SQL statement works correctly, and looks like this:
SELECT table_three.id from table three
JOIN (table_one JOIN table_two ON table_one.id = table_two.table_one_id)
ON table_three.table_two_id = table_two.id
WHERE table_one.id = x AND table_two.external_id = y AND table three.external_id = z
What would the SQL Alchemy code look like for something like this? I have looked at the documentation, but their query is different than mine, and I can't make sense of the example well enough to apply it to my own code.
Turns out that chaining join statements does exactly what we needed all along.
result = connection.execute(
select(Table_three.id)
.join(Table_two, Table_three.Table_two_id == Table_two.id)
.join(Table_one, Table_two.Table_one_id == Table_one.id)
.where(
and_(
Table_three.external_id == z,
Table_two.external_id == y,
Table_on.id = x
)
)
).one_or_none()

Mysql: join to include all rows (even where SUM=0)

I have DB with two tables:
rmonth and alternatives
The rmonth is an aggregated table of data for each alternative a complete month - if they have any - otherwise the row don't exist in the rmonth table.
Now I want to join them, and this is my code:
SELECT
COALESCE(rmAntal, 0) AS sumMonth, aID, aText, rmUnitID
FROM
alternatives
LEFT JOIN
rmonth ON aID = rmAltID
WHERE aToQuestID = 4418
AND rmMonth = 3
AND rmYear = 2018
AND rmUnitID IN (10603,10960,10496)
GROUP BY aID, rmUnitID
ORDER BY aID ASC
But it doesn't give me the rows not existing in rmonth.
So this scenario gives me the result as I want it - except that it can't handle where the alternative does not exist for that specific unitID in rmonth.
I want them listed with just 0 in sumMonth.
Unfortunately that's where my MySQL-knowledge is limited.
Thanks.
You could add an OR operator, for example
...
WHERE aToQuestID = 4418 AND rmMonth IS NULL OR (
AND rmMonth = 3
AND rmYear = 2018
AND rmUnitID IN (10603,10960,10496)
)
...
This way, you'll get all your alternatives data, even when it's counter part in rmonth is null.

Retrieving data from one table while comparing value from another table

Overview
I have two tables as can be seen below:
user_planes
----------------------------------
|id |user_id|plane_id|fuel|status|
----------------------------------
| 2 1 1 1 Ready |
----------------------------------
shop_planes
------------------------
|id |name|fuel_capacity|
------------------------
| 1 bob 3 |
------------------------
Foreign Key Primary Key
user_planes.plane_id <-> shop_planes.id
I want to be able to get every field (SELECT *) in user_planes and name and fuel_capacity based on the following criteria:
WHERE user_planes.user_id = ? - Parameter which will be added to the query through PHP.
WHERE user_planes.status = 'Ready'
WHERE user_planes.fuel < shop_planes.fuel_capacity
The Issue and My Attempts
I've tried JOIN however it retrieves data which doesn't fit that criteria, meaning it gets extra data which is from shop_planes and not user_planes.
SELECT * FROM `user_planes` WHERE fuel IN (SELECT shop_planes.fuel_capacity FROM shop_planes WHERE fuel < shop_planes.fuel_capacity) AND user_planes.user_id = 1 AND status = 'Ready'
and
SELECT * FROM `user_planes` INNER JOIN `shop_planes` ON user_planes.fuel < shop_planes.fuel_capacity AND user_planes.user_id = 1 AND user_planes.status = 'Ready'
I've searched Stackoverflow and looked through many questions but I've not been able to figure it.
I've looked up many tutorials but still can't get the desired result.
The desired result is that the query should use the data stored in user_planes to retrieve data from shop_planes while at the same time not getting any excess data from shop_planes.
Disclaimer
I really struggle using JOIN queries, I could use multiple separate queries however I wish to optimise my queries hence I'm trying to bring it in to one query.
If their isn't clarity in the question, please do say, I'll update it to the best of my ability.
Note - Is there an easy query builder option available either through phpmyadmin or an alternative software?
Thanks in advance.
Your last attempt was not a bad one, the only thing you missed there was the join criteria you described at the beginning of your post. I also moved the other filters to the where clause to better distinguish between join condition and the filters.
SELECT `user_planes`.*
FROM `user_planes`
INNER JOIN `shop_planes` ON user_planes.plane_id = shop_planes.id
WHERE user_planes.fuel < shop_planes.fuel_capacity AND user_planes.user_id = 1 AND user_planes.status = 'Ready'
First you need the base JOIN
SELECT up.* -- only user_plane fields
FROM shop_planes sp -- CREATE alias for table or field
JOIN user_planes up
ON sp.id = up.plane_id
Case 1: apply a filter in where condition with php parameter.
SELECT up.*
FROM shop_planes sp
JOIN user_planes up
ON sp.id = up.plane_id
WHERE up.user_id = ?
Case 2: apply a filter in where condition with string constant
SELECT up.*
FROM shop_planes sp
JOIN user_planes up
ON sp.id = up.plane_id
WHERE user_planes.status = 'Ready'
Case 3: aply filter comparing fields from both tables
SELECT up.*
FROM shop_planes sp
JOIN user_planes up
ON sp.id = up.plane_id
WHERE up.fuel < sp.fuel_capacity
Try something like:
SELECT
up.id AS User_Plane_ID
, up.[user_id]
, up.plane_id
, up.fuel
, up.[status]
, sp.name AS shop_Plane_Name
, sp.fuel_capacity AS shop_Plane_Fuel_Capacity
FROM User_Planes up
INNER JOIN Shop_Planes sp ON up.plane_id = sp.id
AND up.fuel < sp.Fuel_Capacity
WHERE up.[status] = 'Ready'
AND up.[user_id] = ?
Definitely find a tutorial for JOINs, and don't use SELECT *. With SELECT *, you may end up querying much more than you actually need and it can cause problems if the table changes. You'll enjoy your day much more if you explicitly name the columns you want in your query.
I've aliased some of the columns (with AS) since some of those column names may be reserved words. I've also moved the JOIN criteria to include a filter on fuel

sqlalchemy using generators in and_ filters

I'm trying to get a search going, where I pass in several different syllables into the 'and_' function via a generator. My search should then return all and only those words that have all given syllables
matches = db.session.query(Word).join(Word.syllables).filter(db.and_(Syllable.syllable==(syl for syl in combo))).all()
This doesn't return anything currently. Does this approach even make sense?
I don't think this query will do what you want. The query you'd generate would be something like this for combo = (1, 2):
SELECT words.* FROM words INNER JOIN syllables ON words.id = syllables.word_id WHERE syllables.syllable = 1 AND syllables.syllable = 2
What I think you want is this for combo = (1, 2):
SELECT words.* FROM words INNER JOIN syllables AS s1 ON words.id = s1.word_id AND s1.syllable = 1 INNER JOIN syllables AS s2 ON words.id = s2.word_id AND s2.syllable = 2
Repeated joining might get slow but here is how you could do this in sqlalchemy:
query = db.session.query(Word)
for syl in combo:
syl_cls = aliased(Syllable)
query = query.join(syl_cls, Word.syllables).filter(syl_cls.syllable == syl)
matches = query.all()
If you were generating OR clauses then this query would be a lot simpler.

Tricky SQL including outer join and case

I use data from http://geonames.org. The table structure is as follows:
GN_Name 1 - 0:N GN_AlternateName
They are linked on:
(PK)GN_Name.GeoNameId == (FK)GN_AlternateName.GeoNameId
GN_Name is the main table containing all place names.
GN_AlternateName contains names in other languages if any.
EX:
GN_Name.Name - Stockholm
GN_AlternateName.AlternateName - Estocolmo (if IsoLanguage=="es")
Rules:
I want to use GN_AlternateName.AlternateName if it exists for the specified language and if it starts with the search string.
If not, i want to use GN_Name.Name if it starts with the search string.
I want GeoNameId to be unique.
Basically I could outer join in first record only, but that seemed to decrease performance.
I've got the following SQL (basically modified SQL from a LINQ query). The problem is that it only finds 'Estocolmo' if search string starts with "stock". "estoc" yields nothing.
select
distinct(n.GeoNameId) as Id,
an.IsoLanguage,
CASE WHEN (an.AlternateName like N'estoc%')
THEN an.AlternateName
ELSE n.Name
END AS [The name we are going to use]
from GN_Name as n
LEFT OUTER JOIN GN_AlternateName as an
ON n.GeoNameId = an.GeoNameId
AND 'es' = an.IsoLanguage
WHERE n.Name like N'estoc%'
UPDATE
Thanks Rahul and Lee D.
I now have the following:
select
distinct(n.GeoNameId) as Id,
an.IsoLanguage,
CASE WHEN (an.AlternateName like N'estoc%')
THEN an.AlternateName
ELSE n.Name
END AS [The final name]
from GN_Name as n
LEFT OUTER JOIN GN_AlternateName as an
ON n.GeoNameId = an.GeoNameId
AND 'es' = an.IsoLanguage
WHERE (n.Name LIKE N'estoc%' OR an.AlternateName LIKE N'estoc%')
This performs LIKE twice on an.AlternateName. Is there any way i could get rid of on LIKE clause?
UPDATE 2
Andriy M made a nice alternative query using COALESCE. I changed it a little bit and ended up with the following:
SELECT Id, LocalisedName
FROM (
SELECT
n.GeoNameId AS Id,
an.IsoLanguage,
COALESCE(an.AlternateName, n.Name) AS LocalisedName
FROM n
LEFT JOIN GN_AlternateName AS an ON n.GeoNameId = an.GeoNameId
AND IsoLanguage = 'es'
) x
WHERE LocalisedName LIKE 'estoc%'
This query does exactly what i am looking for. Thanks!
Here's a probable solution of the problem, which uses a slightly different apporach:
SELECT Id, LocalisedName
FROM (
SELECT
n.GeoNameId AS Id,
an.IsoLanguage,
COALESCE(an.AlternateName, n.Name) AS LocalisedName
FROM GN_Name AS n
LEFT JOIN GN_AlternateName AS an ON n.GeoNameId = an.GeoNameId
AND IsoLanguage = 'es'
) x
WHERE LocalisedName LIKE 'estoc%'
(Changed it based on your update.)
If I understand correctly, in your example the value 'Estocolmo' is in the GN_AlternateName.AlternateName column, so would be filtered out by the where clause which only looks at GN_Name.Name. What if you change the last line of SQL to:
WHERE n.Name LIKE N'estoc%' OR an.AlternateName LIKE N'estoc%'
I'm assuming 'estoc%' is your search string.
I guess you need to modify the WHERE clause to check in GN_AlternateName table as well
WHERE n.Name like N'estoc%' OR an.AlternateName like 'N'estoc%'