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

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

Related

How to get results using join ON LIKE operator in sql

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

How do I perform this join query?

I have a table leave_form which looks like:
type id reporting_id leave_bal from_date_id leave_from to_date_id leave_to number leave_for status applied_dates_id pendays
personal 99 6 10 1023 full day 1313 full day 10 personal yes 1026 null
I have separate table for dates, so that I can refer these dates into leave_form. My leave_date table looks like:
date_id(AI) dates(UK)
1025 2016-02-18
1301 2016-02-20
1218 2016-02-16
This date_id I have inserted into from_date_id, to_date_id, applied_dates_id columns in leave_form table i.e. all dates are inserted into leave_date table and from this table I am only referring the date_id into leave_form table.
There is also a table that keeps the emp_code and emp_name. My personal table is:
id(AI) emp_code(PK) emp_name
99 K0209 Nijo
When I am trying to fetch the date for from_date_id, to_date_id, applied_dates_id column from leave_form table I don't get any values.
My query for fetching the dates is:
select g.type, a.emp_code, h.rm_id, h.rm_name, g.leave_bal, i1.dates as from_date,
g.leave_from, i2.dates as to_date, g.leave_to, g.number, g.leave_for, g.status,
i3.dates as applied_date, g.pendays
from personal a
inner join leave_form g
on a.id = g.id
inner join inform_to_rm h
on h.reporting_id = g.reporting_id
inner join leave_dates i1
on i1.dates = g.from_date_id
inner join leave_dates i2
on i2.dates = g.to_date_id
inner join leave_dates i3
on i3.dates = g.applied_dates_id
where a.emp_code = 'K0209';
It shows me result like:
type, emp_code, rm_id, rm_name, leave_bal, from_date, leave_from, to_date, leave_to, number, leave_for, status, applied_date, pendays
i.e no data gets returned when I am executing this query.
I would agree with one of the comments to the question. I would recommend referencing the date directly in the leave_form table instead of a FK to a table with dates. But back to the question. You haven't described all of your tables completely, so it is possible that there are multiple problems that I can't see, however, there is definitely one problem.
Your query joins on
inner join leave_dates i1
on i1.dates = g.from_date_id
inner join leave_dates i2
on i2.dates = g.to_date_id
inner join leave_dates i3
on i3.dates = g.applied_dates_id
This is incorrect. leave_dates.dates is the actual DATE, while the columns that you are joining on (leave_form.from_date_id, leave_form.to_date_id, leave_form.applied_dates_id) are foreign key references.
For example, 1023 does not equal 2016-02-18 so you get no match. Replacing the above query-snippet with the following would correct this particular problem.
inner join leave_dates i1
on i1.date_id = g.from_date_id
inner join leave_dates i2
on i2.date_id = g.to_date_id
inner join leave_dates i3
on i3.date_id = g.applied_dates_id

Multiple table join query

I have one master table as "master_tbl" which has following fields :
m_id(PK)
m_name
Two slave tables which can be :
Slave-1 :
---------
sl1_id PK
sl1_name
sl_m_id FK
Slave-2 :
---------
sl2_id PK
sl2_name
sl2_m_id FK
I need output as in one query like the matching records details should be displayed like :
m_id m_name sl1_name(or sl2_name)
last displaying field should be take name of matching records from slave1 or Slave2 table.
Inner Join query Use
SELECT mt.name, s1.sl1_name, s2.sl2_name FROM master_tbl as mt
INNER JOIN Slave-1 as s1 ON s1.sl_m_id = mt.m_id
INNER JOIN Slave-2 as s2 ON s2.sl2_m_id = mt.m_id
SELECT m_id, m_name, sl1_name as `sl1_name(or sl2_name)` FROM slave_1 S1
INNER JOIN master_tbl M ON S1.sl1_m_id = M.m_id
UNION
SELECT m_id, m_name, sl2_name as `sl1_name(or sl2_name)` FROM slave_2 S2
INNER JOIN master_tbl M ON S2.sl2_m_id = M.m_id

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 do I do 2 unique LEFT JOINs on the same table cell?

In mysql I'd like to do 2 unique LEFT JOINs on the same table cell.
I have two tables.
One table lists individual clients and has a clientNoteID and staffNoteID entry for each client. clientNoteID and staffNoteID are both integer references of a unique noteID for the note store in the notesTable.
clientsTable:
clientID | clientName | clientNoteID | staffNoteID
notesTable:
noteID | note
I'd like to be able to select out of the notesTable both the note referenced by the clientNoteID and the note referenced by the staffNoteID.
I don't see any way to alias a left join like:
SELECT FROM clientsTable clientsTable.clientID, clientsTable.clientName, clientsTable.clientNoteID, clientsTable.stylistNoteID
LEFT JOIN notes on clientTable.clientNotesID = notes.noteID
LEFT JOIN notes on clientTable.staffNoteID = notes.noteID as staffNote
(not that i think that really makes too much sense)
So, how could I query so that I can print out at the end:
clientName | clientNote | staffNote
When you join a table the alas must be immediately after the table name, not after the join condition. Try this instead:
SELECT clientsTable.clientName, n1.note AS clientNote, n2.note AS staffNote
FROM clientsTable
LEFT JOIN notes AS n1 ON clientTable.clientNotesID = n1.noteID
LEFT JOIN notes AS n2 ON clientTable.staffNoteID = n2.noteID
you need to alias the tables themselves
SELECT FROM clientsTable clientsTable.clientID, clientsTable.clientName, clientsTable.clientNoteID, clientsTable.stylistNoteID
LEFT JOIN notes a on clientTable.clientNotesID = a.noteID
LEFT JOIN notes b on clientTable.staffNoteID = b.noteID
SELECT CT.clientName, N1.note AS clientNote, N2.note AS staffNote
FROM clientsTable CT
LEFT JOIN notes N1 on CT.clientNotesID = N1.noteID
LEFT JOIN notes N2 on CT.staffNoteID = N2.noteID