Left join with condition - mysql

Suppose I have these tables
create table bug (
id int primary key,
name varchar(20)
)
create table blocking (
pk int primary key,
id int,
name varchar(20)
)
insert into bug values (1, 'bad name')
insert into bug values (2, 'bad condition')
insert into bug values (3, 'about box')
insert into blocking values (0, 1, 'qa bug')
insert into blocking values (1, 1, 'doc bug')
insert into blocking values (2, 2, 'doc bug')
and I'd like to join the tables on id columns and the result should be like this:
id name blockingName
----------- -------------------- --------------------
1 bad name qa bug
2 bad condition NULL
3 about box NULL
This means:
I'd like to return all rows from #bug
there should be only 'qa bug' value in column 'blockingName' or NULL (if no matching row in #blocking was found)
My naive select was like this:
select * from #bug t1
left join #blocking t2 on t1.id = t2.id
where t2.name is null or t2.name = 'qa bug'
but this does not work, because it seems that the condition is first applied to #blocking table and then it is joined.
What is the simplest/typical solution for this problem? (I have a solution with nested select, but I hope there is something better)

Simply put the "qa bug" criteria in the join:
select t1.*, t2.name from #bug t1
left join #blocking t2 on t1.id = t2.id AND t2.name = 'qa bug'

correct select is:
create table bug (
id int primary key,
name varchar(20)
)
insert into bug values (1, 'bad name')
insert into bug values (2, 'bad condition')
insert into bug values (3, 'about box')
CREATE TABLE blocking
(
pk int IDENTITY(1,1)PRIMARY KEY ,
id int,
name varchar(20)
)
insert into blocking values (1, 'qa bug')
insert into blocking values (1, 'doc bug')
insert into blocking values (2, 'doc bug')
select
t1.id, t1.name,
(select b.name from blocking b where b.id=t1.id and b.name='qa bug')
from bug t1

It looks like you want to select only one row from #blocking and join that to #bug. I would do:
select t1.id, t1.name, t2.name as `blockingName`
from `#bug` t1
left join (select * from `#blocking` where name = "qa bug") t2
on t1.id = t2.id

select *
from #bug t1
left join #blocking t2 on t1.id = t2.id and t2.name = 'qa bug'

make sure the inner query only returns one row.
You may have to add a top 1 on it if it returns more than one.
select
t1.id, t1.name,
(select b.name from #blocking b where b.id=t1.id and b.name='qa bug')
from #bug t1

Here's a demo: http://sqlfiddle.com/#!2/414e6/1
select
bug.id,
bug.name,
blocking.name as blockingType
from
bug
left outer join blocking on
bug.id = blocking.id AND
blocking.name = 'qa bug'
order by
bug.id
By adding the "blocking.name" clause under the left outer join, rather than to the where, you indicate that it should also be consider "outer", or optional. When part of the where clause, it is considered required (which is why the null values were being filtered out).
BTW - sqlfiddle.com is my site.

Related

Insert two Records in new mysql table for each record in another table

I need to Insert two Records in a new mysql table for each record in another table
example:
table1
id, name
1, Patrick
2, John
I want to insert favorite site for each records in the second table and each record should have facebook and google as default
the second table should looks like:
table2
table1_id, site
1, facebook
1, google
2, facebook
2, google
We can multiply the original table with a fixed list of rows with a cross join:
insert into table2 (table1_id, site)
select t1.id, s.site
from table1 t1
cross join (select 'google' site union all select 'facebook') s
In recent MySQL versions (>= 8.0.19), the VALUES statement makes the syntax neater:
insert into table2 (table1_id, site)
select t1.id, s.site
from table1 t1
cross join ( values row('google'), row('facebook') ) s(site)
This is an other way to do it using inner join
insert into table2
select t1.id, s.site
from table1 t1
inner join (
select 'facebook' site union select 'google' site
) as s on s.site <> ''
order by t1.id;
Demo here

How to make a join only on selected values of a column on another table in sql

Hello I have a main table table1 that has n columns with a column name called R_Id this column is a primary key (Id) in another table table2. I want to make a join such that I want to retain all the values and columns of table1 but filter the table1 where the R_Id is 13, 3 and 4.
Simply, I can try this i.e.
select * from table1
where table1.R_Id in (13, 3, 4)
but this will filter the whole table1 based on these three values. I want to retain the table1 and all its value and filter only this particular column. I tried something like this but it doesn't work
select * from table1 t1
left join table2 t2 on t1.R_Id = t2.Id
where t1.R_Id in (13, 3, 4)
But this unfortunately doesn't work.
You must set the condition in the ON clause, so that all rows of table1 are returned but only the rows with t1.R_Id IN (13, 3, 4) are joined to table2:
SELECT *
FROM table1 t1 LEFT JOIN table2 t2
ON t1.R_Id = t2.Id AND t1.R_Id IN (13, 3, 4)

Why does LEFT JOINing leave the second table's id NULL?

Please refer to the following answer first: this
So in that answer, it provided a way to take a data based on one distinct column with its corresponding columns. How it picks which one of that distinct column can be sorted by ascending or descending on the condition WHERE t1.lastname > t2.lastname or WHERE t1.lastname < t2.lastname respectively, which I understand.
I'm still practicing SQL and I have questions in regard to the method provided in the above link.
When I tried to select t2.id, it is all null. I can't comprehend this, isn't t2 basically the same table as t1? If so, how is it possible that its id became NULL, but not t1s ids?
Why is it necessary to check WHERE t2.id IS NULL when all t2.id is going to return NULL anyway?
This is a part about which I think I have a slight idea. However, please correct me if I'm wrong. The above method worked (let's talk about the descending order here) because: firstly, the I LEFT JOINed my t1 and t2 together based on their ids. Secondly, I also check that the t1.lastname has to be bigger (>) than t2.lastname which I assume is using ASCII or UNICODE values, which returns me voila! Only one result; the one that has a higher value. Okay now more question: does it check the t1.lastname with t2.lastname one by one but to all t2.lastname and then returns nothing if just one of the t2.lastname renders that condition invalid?
I think that I'm missing something about something here. Could someone please help me? Thank you in advance.
LEFT JOIN will show left part of the join(values from left table) and will show:
values from right table in right part of the join if join condition are
fulfilled or
null values if join condition are not fulfilled
For example:
INSERT INTO #test (id, firstname, lastname)
VALUES
(1, 'A', 'A'),
(2, 'B', 'B'),
(3, 'A', 'B'),
(4, 'B', 'C')
SELECT t1.*, t2.*
FROM #test AS t1
LEFT JOIN #test AS t2
ON t1.firstname = t2.firstname
AND t1.lastname < t2.lastname
it will show
1 A A 3 A B
2 B B 4 B C
3 A B NULL NULL NULL
4 B C NULL NULL NULL
It shows all rows from t1 but last two rows will have nulls for t2 becaue join condition t1.lastname < t2.lastname is not fulfilled. For AB we don't have rows with greater lastname value than B, and for BC we don't rows with greater lastname value than C.
If you now add WHERE condition:
SELECT t1.*, t2.*
FROM #test AS t1
LEFT JOIN #test AS t2
ON t1.firstname = t2.firstname
AND t1.lastname < t2.lastname
WHERE t2.id IS NULL;
you limit you result to rows which didn't fulfilled join conditions.

Search for values in table1 that match values in table2 without joins (Sql Server 2008)

I ran into a situation where I have two tables that store employee information, Table1 are the employees and table2 are 3rd party temps. These tables use a different convention for the IDs (not something I have control over).
The problem is that oftentimes these 3rd party temps become employed and there is no link between these tables. When this happens, I need to make sure they don't exists in Table2 before I create them. Right now the I just want to identify matches on DOB & Last 4, although I'm probably going to add at least first name to the criteria but right now I'd like to start somewhere.
The columns although name differently are the same (DOB = Birth Date, Code = Last 4)
CREATE TABLE Table1
([Emp_ID] int, [DOB] date, [code] varchar(10))
;
INSERT INTO Table1
([Emp_ID], [DOB], [code])
VALUES
(55556, '1966-01-15', '5454'),
(55557, '1980-03-21', '6868'),
(55558, '1985-04-26', '7979'),
(55559, '1990-10-17', '1212'),
(55560, '1992-12-30', '6767')
;
CREATE TABLE Table2
([USer_ID] int, [Birth_Date] date, [last4] varchar(10))
;
INSERT INTO Table2
([User_ID], [Birth_Date], [last4])
VALUES
(22223, '1966-01-15', '5454'),
(22224, '1980-03-21', '6868'),
(22225, '1975-07-19', '4545'),
(22226, '1988-05-24', '3434')
;
Here is what I came up with, It seems to work but I need to return the user_id from table2 that is producing this match?
SELECT *
FROM table1 t1
WHERE EXISTS (SELECT 1 FROM table2 t2 WHERE t1.DOB = t2.Birth_date)
AND EXISTS (SELECT 1 FROM table2 t2 WHERE t1.code = t2.last4)
Thanks!
Try this
Without JOINS:
SELECT t1.*,
(SELECT user_id FROM table2 t2
WHERE t1.DOB = t2.Birth_date and t1.code = t2.last4) user_id
FROM table1 t1
WHERE EXISTS (SELECT 1 FROM table2 t2
WHERE t1.DOB = t2.Birth_date and t1.code = t2.last4)
With JOINS
SELECT t1.*, t2.user_id
FROM table1 t1
inner join table2 t2 on t1.DOB = t2.Birth_date and t1.code = t2.last4
SQL DEMO

Selecting record from one table and insert it into different table with different structure avoiding duplicates

I have two tables with different structure, say property_bid and sc_property_queries.
sc_property_queries holds value from property_bid as well as another table. And there is a field called query_method in a destination table which tells from which table the rows came from. The field raw_id holds the ID from the source tables. What I want to do is , selecting from the property_bid table and insert it into sc_property_queries, but with new items only, i.e. avoiding the duplicates based on raw_id and query_method. Below is my MySQL code which doesn't seem to work
INSERT INTO sc_property_queries (
`property_id`,
`raw_id`, `query_method`,
`contact_fullname`,
`contact_address`,
`contact_email`,
`contact_phone`,
`contact_date`,
`entry_date`,
`title`,
`query_status`,
`remarks`,
`description`
)
SELECT
t1.property_id,
t1.id,
'web-bids',
t1.fullname,
'n/a',
t1.email,
t1.phone,
t1.on_date,
NOW(),
'n/a',
'1',
'n/a',
t1.comment
FROM
property_bid t1
LEFT JOIN sc_property_queries t2
ON (t1.id = t2.raw_id)
WHERE t2.query_method='web-bids' AND t2.raw_id IS NULL;
This query should return the all the rows from property_bid that doesnot exist in sc_property_queries. But it is not doing anything. Can anybody shed light on this?
WHERE t2.raw_id IS NULL restricts your resultset to only those records that do not exist in t2; therefore t2.* are all NULL. Hence this criterion cannot be true simultaneously with the other criterion WHERE t2.query_method='web-bids'.
Perhaps you meant to include that criterion in the join:
FROM
property_bid t1
LEFT JOIN sc_property_queries t2
ON (t1.id = t2.raw_id AND t2.query_method='web-bids')
WHERE t2.raw_id IS NULL
You don't need JOIN just use NOT IN:
FROM
property_bid t1
where
t1.id not in (select t2.raw_id from sc_property_queries t2 where t2.query_method='web-bids')