I have two tables: users and tabletop_questions. The users table has a column called institution_primary_function and tabletop_questions has a column called target_institutions. An example value for users.institution_primary_function = C and an example value for tabletop_questions.target_institutions = A,B,C,D,E,F.
I am trying to return only those rows where the value for users.institution_primary_function is contained in tabletop_questions.target_institutions (comma delimited list) using the below query.
SELECT * FROM tabletop_questions
LEFT JOIN users
ON users.institution_primary_function
LIKE CONCAT( '%,', tabletop_questions.target_institutions, ',%' )
However, with this query, every row from the tabletop_questions table is returned with all the values from the joined users table as NULL. Could you please advise me as to where I am going wrong?
You should normalize your data because searching through a comma-delimited string is not efficient. Yet, MySQL includes a function for this called FIND_IN_SET(). Use an INNER JOIN instead of a LEFT OUTER JOIN to only return matching records.
SELECT * FROM tabletop_questions
INNER JOIN users
ON FIND_IN_SET(users.institution_primary_function,
tabletop_questions.target_institutions)
Related
I am trying to join 3 tables in one output, and each table has a unique identifier that should join them together. However, in one of my tables, I need to CONCAT 3 columns into a string so it matches the format in another table (Table 1). When I run my sql command, I return null for all columns in the daily weather table which shouldn't be the case.
I get data populating for my first 2 table joins, however dailyweather table returns only null cells.
my sql command is:
SELECT results.*,users.cityid,dailyweather.*
FROM results
LEFT JOIN users on results.id = users.id
LEFT JOIN dailyweather ON results.day = CONCAT(dailyweather.day,"-",dailyweather.month,"-",dailyweather.year) WHERE users.cityid = dailyweather.cityid
The columns that should match between tables:
Results.id = users.id
Results.day = CONCAT(dailyweather columns)
users.cityid = dailyweather.cityid
EDIT: as requested in the comments by #Antique-Rahman and #Claus-Bönnhoff, the format for results.day is tinytext/string and NOT DateTime/Timestamp format
Solved.
Solution for those interested:
Normalize your data. I had two tables with dates in a string, and the other table where date items (day/month/year) were separated into unique columns. The column separated dates did not have a zero pad on the front for single digit days whereas the dates did. My solution was to my left join was:
results.day =CONCAT_WS("-",LPAD(dailyweather.day, 2, '0'),LPAD(dailyweather.month,2,'0'),dailyweather.year)
I have two tables: 'tasknotes' and 'relatedtasks'.
I want to return all the rows from 'tasknotes' in which the values in its'task_id' column corresponds to the values held in one of two columns in the 'relatedtasks' table. The columns from the 'relatedtasks' table which hold these values are called 'primarytaskid' and 'relatedtaskid'
I want to return values from the 'tasknotes' if the 'tasknotes.task_id' matches the value stored in either relatedtasks.primarytaskid or relatedtasks.relatedtaskid
I tried to do it several ways. I've been looking at the example here as I thought it might help:
Selecting rows from one table using values gotten from another table MYSQL
But I can't get it quite right. I've also tried the following but I can't seem to get it to work.
"Select * from tasknotes WHERE tasknotes.task_id = ? AND relatedtasks.primarytaskid = ? OR relatedtasks.relatedtaskid= ?";
How should I be dong this? I recognise an option would be to create a version of this code:
SELECT t1.* FROM film t1 WHERE EXISTS (SELECT filmid
FROM film_rating_report t2
WHERE t2.rating = 'GE'
AND t2.filmid = t1.id);
which is from the other stack answer I cited and then run it twice targeting each column distinctly, but there must be a better solution.
********** RESOLVED CODE *****************
Thanks to the answer and comments below the final code is:
String sql = "SELECT t.* "
+ "FROM tasknotes t "
+ "INNER JOIN relatedtasks r "
+ "ON (t.task_id = r.primarytaskid OR t.task_id = r.relatedtaskid) "
+ "WHERE r.primarytaskid=? OR r.relatedtaskid=?";
the values for the '?' as passed in from statements in the java code.
This is a job for a JOIN with a nontrivial ON clause.
Try something like this:
SELECT t.*
FROM tasknotes t
JOIN relatedtasks r
ON (t.task_id = r.primarytask OR t.task_id = r.relatedtaskid)
Using JOIN rather than LEFT JOIN will suppress the rows from tasknotes that don't meet the ON clause.
If you need to filter, append a WHERE clause to the query. For example:
SELECT t.*
FROM tasknotes t
JOIN relatedtasks r
ON (t.task_id = r.primarytask OR t.task_id = r.relatedtaskid)
WHERE t.task_id = ?
The trick here:
All the FROM / JOIN ON stuff is to be considered a chunk of code. It specifies the table (physical or virtual) in your query. In your query your virtual table is
FROM tasknotes t
JOIN relatedtasks r
ON (t.task_id = r.primarytask OR t.task_id = r.relatedtaskid)
This virtual table has both tasknotes and relatedtasks columns in it. It has all possible combinations of rows from the two tables that match the ON clause.
(If you did FROM a JOIN b without an ON clause you would get all combinations of rows in a and b. That could be a great many rows.)
You put a SELECT clause before your virtual table to choose the columns you want to retrieve from that virtual table.
You put a WHERE clause after it to choose the rows you want from your virtual table.
In your case you may need SELECT DISTINCT t.* because your virtual table will have a row for each row in tasknotes times each matching row in relatedtasks.
Finally you let the query planner in MySQL figure out how to satisfy your query efficiently.
I'm using 3 tables to collect data from. The proces looks like:
User write VIN to form
Script search in table 1 for case_id and country base on that vin
number
After that he use case_id and country for search in table number 2
and get calculation id from there
Base on that calculation id and case id it search in 3th table
.
My script looks like this:
SELECT
cases.case_id,
cases.lastcalc_model_options,
cases.country,
calculations.calculation_id,
calculations.license,
positions.text
FROM cases
INNER JOIN calculations ON(cases.case_id =calculations.case_id
AND cases.country = calculations.country)
INNER JOIN positions ON(calculations.case_id = positions.case_id
AND calculations.calculation_id = positions.calculation_id)
WHERE vin ='ABCDEFGH'
This select work correctly, problem start when for example there is for example no result in table positions with that case_id and calculation_id. Instead of give back atleast everything it found in other tables it return NOTHING.
Is there a way to change this kind of komplex SELECT to return everything it found not return something only when every condition is TRUE?
Your problem is the INNER JOIN. Using INNER JOIN your result only contains entries present in all tables. Try using LEFT JOIN instead.
SELECT
cases.case_id,
cases.lastcalc_model_options,
cases.country,
calculations.calculation_id,
calculations.license,
positions.text
FROM cases
LEFT JOIN calculations ON(cases.case_id =calculations.case_id
AND cases.country = calculations.country)
LEFT JOIN positions ON(calculations.case_id = positions.case_id
AND calculations.calculation_id = positions.calculation_id)
WHERE vin ='ABCDEFGH'
See this stackoverlow answer for some more indepth information.
INNER JOIN returns rows from both tables only if there is a match between the columns in both tables.
You may try LEFT JOIN or FULL OUTER JOIN instead.
I have a query:
SELECT GROUP_CONCAT(stores.store_name)
FROM stores
WHERE stores.id IN
(
SELECT
GROUP_CONCAT(users_x_stores.store_id) as stores_list
FROM users_x_stores
WHERE users_x_stores.user_id = 4
);
The subquery, when run alone, returns a group_concat of 3 results - 14,4,8.
There are corresponding rows for the IDs 14,4,8 - but the overall query only returns one store name.
If I change the subquery to simply 14,4,8 the overall query works and a concatenation of 3 store names is returned.
Can anyone tell me what I am doing incorrectly here?
Thanks.
Avoiding doing an IN on a sub query, you can probably use a JOIN.
Assuming that users_x_stores.store_id contains a single store id for that user (with another row on users_x_stores for a different store for the same user):-
SELECT GROUP_CONCAT(stores.store_name)
FROM stores
INNER JOIN users_x_stores
ON stores.id = users_x_stores.store_id
WHERE users_x_stores.user_id = 4
If sers_x_stores.store_id is a comma separated list of stores (not a good table design, and probably not what you have done, but not clear from your original post) then you could do this
SELECT GROUP_CONCAT(stores.store_name)
FROM stores
INNER JOIN users_x_stores
ON FIND_IN_SET(stores.id, users_x_stores.store_id)
WHERE users_x_stores.user_id = 4
Try this
SELECT GROUP_CONCAT(stores.store_name)
FROM stores
WHERE stores.id IN
(
SELECT
users_x_stores.store_id as stores_list
FROM users_x_stores
WHERE users_x_stores.user_id = 4
);
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