I have a SQL query that I’m trying to write, but I’m not quite sure how to get it to work.
I have three tables: “s”, “t”, and “st” (which is a map between “s” and “t”.
table s
=======
primary key sID | val
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
a 0
b 1
c 5
d 6
e 7
table t
=======
primary key tID | val
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
nul -1
bbb 2
ccc 3
ddd 4
table st
========
foreign key sID | foreign key tID
(unique) | (multiple sID to one tID, meaning tID is not unique)
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
a ddd
b ccc
c nul
d ccc
e bbb
So, all ‘s’ have to be mapped to a ‘t’, but ones which are not at a real ‘t’ are instead mapped to the default/null ‘t’ (nul).
The val’s are unique across both ‘s’ and ‘t’, meaning that if table ‘s’ has a 1, then table ‘t’ cannot have a 1.
So my problem is the following:
Given a set of vals (which can be either ‘s’ or ‘t’), I need to get the sID and tID in the ‘st’ table of the corresponding IDs. The problem is that if a ‘s’ is in the set but it’s ‘t’ is NOT in the set, I need to get the values (sID, ‘nul’) rather than (sID, tID).
For example, given the values (3, 1, 6), it would return the pairs: (b,ccc); (d,ccc);
Given the values (0,4), it would return the pair: (a,ddd)
However, given the values (6), it would need to return (d, nul) since the val 3 (which corresponds to ccc which is what d is mapped to) is not in the set. I don’t need null ‘s’ though, just null ‘t’.
I was thinking of using the following statement, but that doesn’t help me with returning “id, nul” if only the ‘s’ is in the set but not ‘t’.
SELECT st.sID, st.tID FROM t, st WHERE t.tID=st.tID AND (t.val=%_VAL1_% OR t.val=%_VAL_2 OR ......);
That gives me anything that has both a ‘t’ and a ‘s’ in the set (really it gives me all ‘s’ associated with any ‘t’ that are in the set), but it doesn’t give me the ‘s’ that are by themselves.
Perhaps I could post-process anything that’s in ‘s’ but not in ‘st’, but I’d like to avoid that if possible.
Does anyone have any suggestions? I’m rather stuck.
Thanks!
(note: s, t, and st are not my real table names, don’t worry. Also, the primary key’s are actually text GUIDs, unfortunately, but I tried to make it simpler to distinguish)
Here is what you want:
Here is the SQLFiddle that proves it for all 3 scenarios. You have to have the mapping table as the main, since the resultset is from tables that can be null.
Although, this is very weird logic. Usually if a mapping is not hit in many-to-many relationship, you just return 0 rows, not a partial….
If you want to cancel out the duplicates that might occur from multiple mapping misses (null in one column output), then add a DISTINCT. Like this:
Here is the fiddle that shows the duplication
And, here is the one that fixes it
AND Finally, based on latest update. If you want any NULL s columns to be excluded, just make s an INNER JOIN and you can then remove the NULL check since you will not get double NULL’s now…Feel free to remove the distinct if you do want multiple
sID|NULLresults.Here is the SQLFiddle