How to get results using join ON LIKE operator in sql - mysql

I am trying multiple joins in a single query to pull data from multiple tables.
Tables - Places_main, User_interests, travel_list
User_interests table data:
ID USERID INTERESTID
84 27 |18|
85 27 |18|
Places_main table data
ID TAGS
1 |5|18|35|34|33
2 |5|18|35|33|34
What I am trying to get here :
Get list of places from Places_main table which is not in travel_list, and for "tags" column of places_main there is an entry in User_interests table in interestID column.
This is query 1
select * from places_main pm
LEFT JOIN travel_list tl ON pm.ID = tl.PLACEID
LEFT JOIN user_interests ui ON pm.TAGS NOT LIKE '%' || ui.interestid || '%'
where tl.ID is null and ui.ID is null
This is same query 2 which is same as above but with hard-coded data
select * from places_main pm
LEFT JOIN travel_list tl ON pm.ID = tl.PLACEID
LEFT JOIN user_interests ui ON pm.TAGS NOT LIKE '%18%'
where tl.ID is null and ui.ID is null
When I execute query with hardcoded value, it returns expected results, but when I run without hard-coded(1st query), it returns nothing.
How do I get get expected result without using hardcoded value.
Thanks for help in advance.
Edit:
If I remove pipe form table data and compare it as single value, it works fine. But with pipe in row it returns empty. Any suggestion for this.

Firstly, you shouldn't be storing tags like that. You should normalize your table to store one tag per row. Then all there is left to do will be a simple join:
create table user_interests (
id int,
userid int,
interestid int
);
insert into user_interests values
(84 , 27 ,18),
(85 , 27 ,18);
create table places_main (
id int,
tag int
);
insert into places_main values
(1,5), (1,18), (1,35), (1,34), (1,33),
(2,5), (2,18), (2,35), (2,33), (2,34);
select *
from places_main p
join user_interests u on p.tag = u.interestid;
Demo normalized
For your current design, here's an ugly solution:
create table places_main (
id int,
tags varchar(100)
);
insert into places_main values
(1,'|5|18|35|34|33'),
(2,'|5|18|35|33|34');
select *
from places_main p
left join user_interests u
on concat('|', p.tags, '|') like concat('%|', u.interestid, '|%');
Demo

You are missing the quotes from round the like value
select * from places_main pm
LEFT JOIN travel_list tl ON pm.ID = tl.PLACEID
LEFT JOIN user_interests ui ON pm.TAGS NOT LIKE '"%' || ui.interestid || '%"'
where tl.ID is null and ui.ID is null

Maybe your mysql does not allow the pipe for concat. The || works in MySQL as well but you need to set sql_mode to PIPES_AS_CONCAT.
Or you use "concat()":
select * from places_main pm
LEFT JOIN travel_list tl ON pm.ID = tl.PLACEID
LEFT JOIN user_interests ui ON pm.TAGS NOT LIKE CONCAT('"%|', ui.interestid, '|%"')
where tl.ID is null and ui.ID is null

Related

SQL Join for retrieving record for a single user

I have user related info split into multiple tables . I am trying to write a join to retrieve data for a single user , a lot of the info is optional , so the entry for many columns may be null , which is okay . I have written the following query , it is working except that it returns all users when I want the user with id '69'
SELECT cur_doctor_names.First_Name, cur_doctor_Names.Last_Name, w.Website
FROM cur_doctor_names
LEFT JOIN (
SELECT *
FROM cur_website
WHERE Userid =69
) AS w ON cur_doctor_names.UserId = w.Userid
I want the following result :
First_Name | Last Name | Website
ABC XYZ Null
where ABC is the name for user with id 69 .
You are only filtering the websites because you are using a left join. You should apply your filter to the doctors table
SELECT
cur_doctor_names.First_Name,
cur_doctor_Names.Last_Name,
w.Website
FROM
cur_doctor_names
LEFT JOIN cur_website AS w
ON cur_doctor_names.UserId = w.Userid
WHERE
cur_doctor_names.UserId = 69
Try writing it like this - your where clause was in the wrong place (also your left join does not need to be written like that):
SELECT cur_doctor_names.First_Name, cur_doctor_Names.Last_Name, w.Website
FROM cur_doctor_names
LEFT JOIN cur_website as w
ON cur_doctor_names.UserId = w.Userid
WHERE cur_doctor_names.userId = 69
I think you can just write
SELECT cur_doctor_names.First_Name, cur_doctor_Names.Last_Name, w.Website
FROM cur_doctor_names
LEFT JOIN cur_website w ON cur_doctor_names.UserId = w.Userid
WHERE Userid =69

How to left join or inner join a table itself

I have this data in a table, for instance,
id name parent parent_id
1 add self 100
2 manage null 100
3 add 10 200
4 manage null 200
5 add 20 300
6 manage null 300
How can I left join or inner join this table itself so I get this result below?
id name parent
2 manage self
4 manage 10
6 manage 20
As you can I that I just want to query the row with the keyword of 'manage' but I want the column parent's data in add's row as the as in manage's row in the result.
Is it possible?
EDIT:
the simplified version of my actual table - system,
system_id parent_id type function_name name main_parent make_accessible sort
31 30 left main Main NULL 0 1
32 31 left page_main_add Add self 0 1
33 31 left page_main_manage Manage NULL 0 2
my actual query and it is quite messy already...
SELECT
a.system_id,
a.main_parent,
b.name,
b.make_accessible,
b.sort
FROM system AS a
INNER JOIN -- self --
(
SELECT system_id, name, make_accessible, sort
FROM system AS s2
LEFT JOIN -- search --
(
SELECT system_id AS parent_id
FROM system AS s1
WHERE s1.function_name = 'page'
) AS s1
ON s1.parent_id = s2.parent_id
WHERE s2.parent_id = s1.parent_id
AND s2.system_id != s1.parent_id
ORDER BY s2.sort ASC
) b
ON b.system_id = a.parent_id
WHERE a.function_name LIKE '%manage%'
ORDER BY b.sort ASC
result I get currently,
system_id main_parent name make_accessible sort
33 NULL Main 0 1
but I am after this,
system_id main_parent name make_accessible sort
33 self Main 0 1
You just need to reference the table twice:
select t1.id, t1.name, t2.id, t2.name
from TableA t1
inner join TableA t2
on t1.parent_id = t2.Id
Replace inner with left join if you want to see roots in the list.
UPDATE:
I misread your question. It seems to me that you always have two rows, manage one and add one. To get to "Add" from manage:
select system.*, (select parent
from system s2
where s2.parent_id = system.parent_id
and s2.name = 'add')
AS parent
from system
where name = 'manage'
Or, you might split the table into two derived tables and join them by parent_id:
select *
from system
inner join
(
select * from system where name = 'add'
) s2
on system.parent_id = s2.parent_id
where system.name = 'manage'
This will allow you to use all the columns from s2.
Your data does not abide to a child-parent hierarchical structure. For example, your column parent holds the value 10, which is not the value of any id, so a child-parent association is not possible.
In other words, there's nothing that relates the record 2,manage,null to the record 1,add,self, or the record 4,manage,null to 3,add,10, as you intend to do in your query.
To represent hierarchical data, you usually need a table that has a foreign key referencing it's own primary key. So your column parent must reference the column id, then you can express a child-parent relationship between manage and add. Currently, that's not possible.
UPDATED: Joining by parent_id, try:
select m.id, m.name, a.parent
from myTable m
join myTable a on m.parent_id = a.parent_id and a.name = 'add'
where m.name = 'manage'
Change the inner join to a left join if there may not be a corresponding add row.

How to Join 3 Tables in MySQL?

I am creating a view for my Database , I am joing 3 tables, Users,personal_info and contact_info, if you notice I have a lot of column names in my Select statement , since i don't want to include primary keys but it seems I have an error here, take a look
CREATE VIEW `payroll`.`new_view` AS
Select employee_id,employee_password,First_Name,Middle_Initial,
Last_Name,Date_Of_Birth,Beneficiaries,Home_Number,Address,Mobile_Number,Email_Address
From USER
LEFT JOIN personal_info on idUser = idPersonal_Info,
FULL JOIN contact_info on idUser = idContact_Info
The error is
ERROR 1146: Table 'payroll.full' doesn't exist
SQL Statement:
CREATE OR REPLACE VIEW `payroll`.`new_view` AS
Select employee_id,employee_password,First_Name,Middle_Initial,
Last_Name,Date_Of_Birth,Beneficiaries,Home_Number,Address,Mobile_Number,Email_Address
From USER
LEFT JOIN personal_info on idUser = idPersonal_Info,
FULL JOIN contact_info on idUser = idContact_Info
quote it with backtics: payroll.new_view
CREATE VIEW `payroll.new_view`
Error on:
LEFT JOIN personal_info on idUser = idPersonal_Info
you need to specify which column on which table equals which one on the other table, like
SELECT a,b,c from table1
LEFT JOIN table2
on table1.a= table2.columnY
in your case:
on USER.idUser = Personal_Info.idPersonalInfo
and the same for the 3rd Join
Another thing is the Comma at the end of the line:
LEFT JOIN personal_info on idUser = idPersonal_Info ,
it doesnt belong there.

selecting where in multiple join tables

I have the logic worked out, just not sure how to best write this query.
the logic is
we have a deal ID of 1
a deal is linked to multiple regions
a deal is linked to multiple interests
a user is linked to multiple regions
a user is linked to multiple interests
we want all users where....
the user is linked to the same region as a deal
userRegionLink url, dealRegionLink drl
url.regionId is in drl.regionId where drl.dealId = 1
the user is linked to the same interest as a deal
userInterestLink uil, dealInterestLink dil
uil.interestId is in dil.interestId where dil.dealId = 1
this would give us a list of the users
now we need to select distinct from the list so we only end up sending each user a single email
But I have no idea what the best way to write this query would be.
We are dealing with a few tables here
We have
users which has all the user Information in it userId and other columns not important
userInterestLink which has userId and interestId
dealInterestLink which has dealId and interestId
userRegionLink which has userId and regionId
dealRegionLink which has dealId and regionId
so what we are wanting in the end is all the user info which matches.
I take RC's answer and modify it
SELECT u.userId, uil.interestId, url.regionId FROM users u
JOIN userInterestLink uil ON (uil.userId = u.userId)
JOIN userRegionLink url ON (url.userId = u.userId)
WHERE interestId IN (
SELECT DISTINCT interestId FROM dealInterestLink WHERE dealId = 1
) AND regionId IN (
SELECT DISTINCT regionId FROM dealRegionLink WHERE dealId = 1
)
as there is no need for LEFT JOIN if I exclude the NULL rows afterwards.
A more "symmetric" version without subqueries and with USING would be
SELECT u.userId, uil.interestId, url.regionId FROM users u
JOIN userInterestLink uil USING (userId)
JOIN userRegionLink url USING (userId)
JOIN dealInterestLink dil USING (interestId)
JOIN dealRegionLink drl USING (regionId, dealId)
WHERE dealId = 1
Untested as well.
Something like:
SELECT u.userId, uil.interestId, url.regionId FROM users u
LEFT JOIN userInterestLink uil ON (uil.userId = u.userId)
LEFT JOIN userRegionLink url ON (url.userId = u.userId)
WHERE uil.interestId IS NOT NULL AND uil.interestId IN (
SELECT DISTINCT interestId FROM dealInterestLink WHERE dealId = 1
) AND url.regionId IS NOT NULL AND url.regionId IN (
SELECT DISTINCT regionId FROM dealRegionLink WHERE dealId = 1
)
? If result is OK, you can then SELECT DISTINCT u.userId FROM users u -- ...
(not tested)
SELECT `u`.*
FROM `users` AS `u`
JOIN `userRegionLink` `userReg` USING ( `userId` )
JOIN `userInterestLink` `userInt` USING ( `userId` )
JOIN `dealInterestLink` `dealInt` USING ( `interestId` )
JOIN `dealRegionLink` `dealReg` USING ( `regionId` )
JOIN `deal` `d` ON ( `dealInt`.`dealId` && `dealReg`.`dealId` && `d`.`dealId` = 1 )
GROUP BY `u`.`userId`
Tested locally using dummy data and presumed schema. Worked OK.

How can I conditionally join two MySQL tables on multiple fields?

In my MySQL DB, I have 2 tables: pos_tables and pos_user_login. In
pos_tables, I have four staff fields: staff1, staff2, staff3,
staff4. These 4 fields hold the IDs of staffmembers stored in
pos_user_login. In pos_tables, these staff IDs may repeat, but staff_id
is the primary key in pos_user_login.
What I'm trying to do is to join these two tables, using a condition of
if pos_user_login.staff_id=(pos_tables.staff1 OR
pos_tables.staff2 OR
pos_tables.staff3 OR
pos_tables.staff4)
... and if any of the 4 fields from pos_tables matches the primary key from
pos_user_login, then fetch that record from pos_tables.
What query do I need to run to do this?
---- EDIT ----
Should I use something like this?
SELECT *
FROM pos_user_login pu
WHERE pos_user_login_id IN (SELECT *
FROM pos_tables
WHERE staff1 = pu.pos_user_login_id
OR staff2 = pu.pos_user_login_id
...);
---- EDIT 2 ----
SAMPLE RECORD
pos_tables
----------
table_number (1 )
staff1 (10)
staff2 (11)
staff3 (12)
pos_user_login
--------------
staff_id (10),
type (drinks_person)
staff_id(11), type (order_taker)
staff_id(12), type(cleaner)
After comparing using the WHERE condition (type="drinks_person"), the output
should be:
table_number(1), staff1(10), staff2("null"), staff3(null)
You can use the IN() operator:
SELECT *
FROM pos_tables JOIN pos_user_login
ON pos_user_login.staff_id IN (
pos_tables.staff1,
pos_tables.staff2,
pos_tables.staff3,
pos_tables.staff4
)
There it´s
select a.*
from pos_tables a left join
pos_user_login b1 on a.staff1=b1.staff_id left join
pos_user_login b2 on a.staff2=b2.staff_id left join
pos_user_login b3 on a.staff3=b3.staff_id left join
pos_user_login b4 on a.staff4=b4.staff_id
where (b1.staff_id is not null or
b2.staff_id is not null or
b3.staff_id is not null or
b4.staff_id is not null)
Sort of sounds like the data hasn't been stored very well. Can you post a schema?
Here's my suggestion: using ifnull and doing multiple joins you can work out if one of the id's has a join. I've returned "name" assuming that the pos_user_login has that field, but you would return any field you need.
SELECT
ifnull(p1.id,
ifnull(p2.id,
ifnull(p3.id,
ifnull(p4.id,
'no matching record',
p4.name,
p3.name,
p2.name,
p1.name) as staff_name
FROM
pos_tables t
LEFT JOIN pos_user_login p1 on staff1=t.id
LEFT JOIN pos_user_login p2 on staff2=t.id
LEFT JOIN pos_user_login p3 on staff3=t.id
LEFT JOIN pos_user_login p4 on staff4=t.id