Get right table data on LEFT JOIN - sql

I have a problem with my sql join request.
I need to get lines of left table who are not referenced in right table for ME (User 1) or referenced in right table with status equal to 0 and user equal to 1.
I also need the field status of right table.
Here is my two tables :
Table left
ID | title
1 | Title 1
2 | Title 2
3 | Title 3
4 | Title 4
5 | Title 5
6 | Title 6
Table right
ID | status | user | left_id
1 | 0 | 1 | 1
2 | 0 | 50 | 1
3 | 1 | 1 | 2
4 | 0 | 50 | 2
5 | 0 | 1 | 3
6 | 1 | 50 | 3
7 | 0 | 50 | 4
8 | 1 | 50 | 5
My goal is to get this result :
left.ID | left.title | right.status | right.user
1 | Title 1 | 0 | 1
3 | Title 3 | 0 | 1
4 | Title 4 | NULL | NULL
5 | Title 5 | NULL | NULL
6 | Title 6 | NULL | NULL
Here is my request for the moment :
SELECT l.id, l.title, r.user, r.status
FROM left as l
LEFT JOIN right as r ON l.id = r.left_id
WHERE r.left_id IS NULL or (r.user = 1 AND r.status = 0)
With this request I get lines ID (left table) 1 / 3 / 6. But I also need the ID 4 / 5.
Those lines isn't displayed because another user (50) as a reference, but it's not me (1).
If someone can help me to add line 4 / 5 to my result I would be happy.
Thanks

Small improvement of the query should be sufficient:
SELECT l.id, l.title, r.user, r.status
FROM left as l
LEFT JOIN right as r ON l.id = r.left_id and r.user = 1
WHERE r.left_id IS NULL or r.status = 0

(Select t1.id, t1.title,t2.status,t2.user
from tableLeft t1
right outer join tableRight t2 on t2.left_id=t1.id
where t1.id not in
(select tt2.left_id from tableRight tt2)
)
union
(select t1.id,t1.title,t2.status,t2.user
from tableLeft t1
left join tableRight t2 on t1.id=t2.left_id
where t2.status=0 and t2.user=1
)

Related

LEFT Join and data in right table

I have a problem with my sql join request, I need to get lines of left table who are not referenced in right table or referenced in right table with status equal to 0 for my user 1.
I also need the field status of right table
Here is my two tables :
Table left
ID | title
1 | Title 1
2 | Title 2
3 | Title 3
4 | Title 4
5 | Title 5
Table right
ID | status | user | left_id
1 | 0 | 1 | 1
2 | 0 | 50 | 1
3 | 1 | 1 | 2
4 | 0 | 50 | 2
5 | 0 | 1 | 3
6 | 1 | 50 | 3
My goal is to get this result :
left.ID | left.title | right.status | right.user
1 | Title 1 | 0 | 1
3 | Title 3 | 0 | 1
4 | Title 4 | NULL | NULL
5 | Title 5 | NULL | NULL
I need right informations to do some verifications on status field if exist or not.
Here is my request for the moment :
SELECT l.title, r.status
FROM left as l
LEFT JOIN right as r ON l.id = r.left_id AND r.user = 1 AND r.status = 0
The problem is I got the line Title 2, I don't kwon how to remove this line.
If someone can help me.
Thanks
What about this
SELECT l.id, l.title, r.user, r.status
FROM left as l
LEFT JOIN right as r ON l.id = r.left_id
WHERE r.left_id IS NULL or (r.user = 1 AND r.status = 0)
The r.left_id IS NULL will keep the left records that are not in right table and or (r.user = 1 AND r.status = 0) will keep left records with requested values.
Since you use LEFT JOIN, you can't use the join condition to filter on status. Filter in the WHERE clause instead.
SELECT l.title, r.status
FROM left as l
LEFT JOIN right as r ON l.id = r.left_id
WHERE r.ID IS NULL OR (r.status = 0 and r.user = 1)
Try like this. First join with ids and then filter for your condition in where close
SELECT l.title, r.status
FROM left as l
LEFT JOIN right as r ON l.id = r.left_id
Where r.user = 1 AND r.status = 0

SQL Left Join with verification on each table

First, my SQL skils are really bad.
Here is my tables :
Message :
id | title | arrayusers
1 |Title1 | a:2:{i:1;i:1;i:5;i:5;}
2 |Title2 | a:2:{i:1;i:1;i:5;i:5;}
3 |Title3 | a:2:{i:1;i:1;i:5;i:5;}
4 |Title4 | a:2:{i:1;i:1;i:5;i:5;}
5 |Title5 | a:2:{i:1;i:1;i:5;i:5;}
6 |Title6 | a:2:{i:1;i:1;i:5;i:5;}
Read :
id | status | userid | message_id
1 | 0 | 5 | 1
2 | 0 | 1 | 2
3 | 0 | 5 | 2
4 | 0 | 1 | 3
5 | 0 | 5 | 4
6 | 1 | 1 | 5
7 | 1 | 5 | 5
7 | 1 | 5 | 6
I use the userid 1 for my test :
My goal, is to get all lines from Message, where my user 1 is in arrayusers with a LIKE(i:1;i:1;)
And user 1 not in table Read (userid), with the status equal to 0. If another user (5) but not me (user 1) is in Read table, I want to see my Message line
With the data above, I want to return the id 1 / 4 from Message table
I started a request with Left join, but my request hide line id 1 and 4 because there is another user in this table with this id.
SELECT * FROM message as m
LEFT JOIN read as r ON m.id = r.message_id
WHERE m.arrayusers LIKE '%i:1;i:1;%'
AND r.id IS NULL
Hope you understand my request.
Someone can help me to debug my request ?
Thanks
I'd use NOT EXISTSor NOT IN to look up the status in the read table:
select *
from message
where arrayusers like '%i:1;i:1;%'
and id not in
(
select message_id
from read
where userid = 1
and status = 0
);
As to your own query: You are merely missing the criteria on the read table:
SELECT m.*
FROM message as m
LEFT JOIN read as r ON m.id = r.message_id and r.userid = 1 and r.status = 0
WHERE m.arrayusers LIKE '%i:1;i:1;%'
AND r.id IS NULL;
What is the use of AND r.id IS NULL? Please remove this condition and check:
SELECT * FROM message as m
LEFT JOIN read as r ON m.id = r.message_id
WHERE m.arrayusers LIKE '%i:1;i:1;%'
AND r.id IS NULL

How to do it by simple sql or procedure

object_tbl:
objId(primary key) | name
1 | A
2 | B
3 | C
document_tbl:
documentId | sourceId
1 | 2
2 | 2
3 | 1
4 | 3
5 | 3
6 | 3
objToDoc_tbl:
id | objectId | documentId
1 | 1 | 2
2 | 2 | 4
3 | 2 | 6
4 | 1 | 5
5 | 3 | 1
6 | 1 | 2
Inner join of all table
A 2 2
B 4 3
B 6 3
A 5 3
C 1 2
A 2 2
A 2
B 1
C 1
so Answer is 1(As A is only 2)
Question: - How many object are related to documents from multiple sources.
How we can write sql query for this or it can only we solved by procedure
You can join all the tables and then use having to get objects with count > 1.
with t as (
select t.name, count(distinct d.sourceid) as count
from objtodoc_tbl o
join document_tbl d on o.documentid = d.documentid
join object_tbl t on o.objectid = t.name
group by t.name
having count(distinct d.sourceid) > 1
)
select count(t.name) from t;

Find matching set of records

I have the following tables on SQL Server 2008R2
MessageTable
ContrlNo| LineNo | Msg
1 | 1 | Tiger1 Text
1 | 2 | Tiger1 Text
1 | 3 | Tiger1 Text
1 | 4 | Tiger1 Text
2 | 1 | Tiger1 Text1
2 | 2 | Tiger1 Text2
2 | 3 | Tiger1 Text3
2 | 4 | Tiger1 Text4
3 | 1 | Horse 1
3 | 2 | Horse 2
3 | 3 | Horse 3
3 | 4 | Horse 4
RuleTable
RuleNo| MsgLineNo | RuleStartingPos | RuleMsg
1 | 1 | 1 | Tiger1 Text
2 | 1 | 1 | Tiger1 Text
2 | 3 | 1 | Tiger1 Text3
For each set of ControlNo records in the MESSAGETABLE I would like to apply the rule from the RULETABLE and list the RULENo if any mataches.
If you see the RuleTable, the Rule 2 overlaps rule 1. And the requirement is to get the most matched RuleNo for each Control number. the expected result is,
ContrlNo | RuleNo
1 | 1
2 | 2
3 | NULL
Thanks,
Jay
I believe the following will retrieve the listed results: it will show a control number with the associated rule that has the most matching lines (if, as in your first case, two rules have an equal number of matches, it will check the MatchPercent).
SELECT MT.ContrlNo, r.RuleNo, r.MatchPercent
FROM
MessageTable MT
LEFT JOIN
(
SELECT
ContrlNo,
RuleNo,
MatchedRules / AvailableRules AS MatchPercent,
ROW_NUMBER() OVER (PARTITION BY ContrlNo ORDER BY MatchedRules DESC, MatchedRules / AvailableRules DESC) AS rn
FROM
(
SELECT
ContrlNo,
R.RuleNo,
COUNT(*) as MatchedRules,
(SELECT COUNT(*) FROM RuleTable WHERE RuleTable.RuleNo = R.RuleNo) + 0.0 AS AvailableRules
FROM
MessageTable M
INNER JOIN
RuleTable R ON
M.[LineNo] = R.MsgLineNo AND
SUBSTRING(M.Msg,R.RuleStartingPos,LEN(R.RuleMsg)) LIKE '%' + R.RuleMsg + '%'
GROUP BY M.ContrlNo, R.RuleNo
) q
) r ON
MT.ContrlNo = r.ContrlNo AND
r.rn = 1
GROUP BY MT.ContrlNo, r.RuleNo, r.MatchPercent
SQL Fiddle
First subquery is getting total Matched rules and second sub query is getting total rules, when these two conditions are matched then we show the RuleNo other wise NULL as we are using LEFT JOIN
Select A.ContrlNo, ISNULL(T.RuleNo,0) as RuleNo FROM
( select ContrlNo, COUNT(R.RuleNo) as MatchedRules
FROM Messages M
LEFT JOIN Rules R
on M.[LineNo] = R.MsgLineNo
and SUBSTRING(M.Msg,R.RuleStartingPos,LEN(R.RuleMsg)) = R.RuleMsg
AND M.ContrlNo = R.RuleNo
GROUP BY M.ContrlNo) A
LEFT JOIN (
select COUNT(MsgLineNo) as TotalRules, RuleNo
from Rules R1
group by RuleNo) T
ON A.MatchedRules = T.TotalRules

Left Join on Associative Table

I have three tables
Prospect -- holds prospect information
id
name
projectID
Sample data for Prospect
id | name | projectID
1 | p1 | 1
2 | p2 | 1
3 | p3 | 1
4 | p4 | 2
5 | p5 | 2
6 | p6 | 2
Conjoint -- holds conjoint information
id
title
projectID
Sample data
id | title | projectID
1 | color | 1
2 | size | 1
3 | qual | 1
4 | color | 2
5 | price | 2
6 | weight | 2
There is an associative table that holds the conjoint values for the prospects:
ConjointProspect
id
prospectID
conjointID
value
Sample Data
id | prospectID | conjointID | value
1 | 1 | 1 | 20
2 | 1 | 2 | 30
3 | 1 | 3 | 50
4 | 2 | 1 | 10
5 | 2 | 3 | 40
There are one or more prospects and one or more conjoints in their respective tables. A prospect may or may not have a value for each conjoint.
I'd like to have an SQL statement that will extract all conjoint values for each prospect of a given project, displaying NULL where there is no value for a value that is not present in the ConjointProspect table for a given conjoint and prospect.
Something along the lines of this for projectID = 1
prospectID | conjoint ID | value
1 | 1 | 20
1 | 2 | 30
1 | 3 | 50
2 | 1 | 10
2 | 2 | NULL
2 | 3 | 40
3 | 1 | NULL
3 | 2 | NULL
3 | 3 | NULL
I've tried using an inner join on the prospect and conjoint tables and then a left join on the ConjointProspect, but somewhere I'm getting a cartesian products for prospect/conjoint pairs that don't make any sense (to me)
SELECT p.id, p.name, c.id, c.title, cp.value
FROM prospect p
INNER JOIN conjoint c ON p.projectID = c.projectid
LEFT JOIN conjointProspect cp ON cp.prospectID = p.id
WHERE p.projectID = 2
ORDER BY p.id, c.id
prospectID | conjoint ID | value
1 | 1 | 20
1 | 2 | 30
1 | 3 | 50
1 | 1 | 20
1 | 2 | 30
1 | 3 | 50
1 | 1 | 20
1 | 2 | 30
1 | 3 | 50
2 | 1 | 10
2 | 2 | 40
2 | 1 | 10
2 | 2 | 40
2 | 1 | 10
2 | 2 | 40
3 | 1 | NULL
3 | 2 | NULL
3 | 3 | NULL
Guidance is very much appreciated!!
Then this will work for you... Prejoin a Cartesian against all prospects and elements within that project via a select as your first FROM table. Then, left join to the conjoinprospect. You can obviously change / eliminate certain columns from result, but at least all is there, in the join you want with exact results you are expecting...
SELECT
PJ.*,
CJP.Value
FROM
( SELECT
P.ID ProspectID,
P.Name,
P.ProjectID,
CJ.Title,
CJ.ID ConJointID
FROM
Prospect P,
ConJoint CJ
where
P.ProjectID = 1
AND P.ProjectID = CJ.ProjectID
ORDER BY
1, 4
) PJ
LEFT JOIN conjointProspect cjp
ON PJ.ProspectID = cjp.prospectID
AND PJ.ConjointID = cjp.conjointid
ORDER BY
PJ.ProspectID,
PJ.ConJointID
Your cartesian product is a result of joining by project Id - in your sample data there are 3 prospects with a project id of 1 and 3 conjoints with a project id of 1. Joining based on project id should then result in 9 rows of data, which is what you're getting. It looks like you really need to join via the conjointprospects table as that it what holds the mapping between prospects and conjoint.
What if you try something like:
SELECT p.id, p.name, c.id, c.title, cp.value
FROM prospect p
LEFT JOIN conjointProspect cp ON cp.prospectID = p.id
RIGHT JOIN conjoint c ON cp.conjointID = c.id
WHERE p.projectID = 2
ORDER BY p.id, c.id
Not sure if that will work, but it seems like conjointprospects needs to be at the center of your join in order to correctly map prospects to conjoints.