Using a column from inside a not in query - sql

I have a sql query as below:
SELECT
A.COL1, A.COL2
FROM
SOMESCHEMA.TABLE1 A
WHERE
A.COL3 NOT IN (SELECT A1.COL3 FROM SOMESCHEMA.TABLE2 B, SOMESCHEMA.TABLE1 A1 WHERE A.COL4 = B.COL4 AND B.DATE >= '2014-01-17')
The result of above query is two columns COL1 and COL2.
Now I want the DATE column of the second table into my result.
That is, the result should be COL1, COL2 and DATE.
How to achieve this?
Thanks for reading!

This is exactly the situation you want to use a join:
SELECT
A.COL1, A.COL2, B.DATE
FROM
SOMESCHEMA.TABLE1 A INNER JOIN SOMESCHEMA.TABLE2 B ON A.COL3 = B.COL3
WHERE B.DATE >= '2014-01-17'
You can find more info on using JOINS in DB2 here: http://www-01.ibm.com/support/knowledgecenter/?lang=en#!/SSEPEK_10.0.0/com.ibm.db2z10.doc.intro/src/tpc/db2z_innerjoin.dita

Your question as stated makes no sense - you're asking for matched data where the data does not match. Sample data from each table and a sample output would really help here.
Here is my best guess as to what you're trying to do:
Return data from Table2 where a match on COL4 exists that is greater than January 17th and has with a different COL3
SELECT
A.COL1, A.COL2, B.DATE
FROM
SOMESCHEMA.TABLE1 A
INNER JOIN
SOMESCHEMA.TABLE2 B ON
A.COL4 = B.COL4 AND
B.DATE >= '2014-01-17' AND
A.COL3 <> B.COL3

Related

Can you use an AND statement in a JOIN in SQL

Suppose you have two tables A and B and you are trying to write a JOIN query, is the following possible:
SELECT A.col1, B.col1
FROM A JOIN B on (A.col2 = B.col2 AND B.col3 = 'hello')
Will this return a table of col1 from table A and col2 from table B where there is a match in the second column across the tables and the third column of table B is 'hello'?
I.e. it will only return rows that are matching in col2 and this is further reduced to the cases where col3 in table B is 'hello'?
Yes. You can use:
Below will Join the Records in B table (Col3='hello') with A:
SELECT A.col1, B.col1
FROM A JOIN B on (A.col2 = B.col2 AND B.col3 = 'hello')
Below will Join all Records in B table with A, And performing where at Result of A and B:
SELECT A.col1, B.col1
FROM A JOIN B on A.col2 = B.col2
WHERE B.col3 = 'hello'
Both will give the same result when no other tables joined.
Yes you can.
You can specify any kind of boolean condition in the ON clause.
It is not mandatory that any column is involved in the condition so all of the following are valid:
SELECT A.col1, B.col1 FROM A JOIN B on 1=1
SELECT A.col1, B.col1 FROM A JOIN B on B.col3 = 'hello'
SELECT A.col1, B.col1 FROM A JOIN B on (A.col2 = B.col2 AND B.col3 = 'hello')
SELECT A.col1, B.col1 FROM A JOIN B on (A.col2 = B.col2 AND B.col3 = C.col3)
SELECT A.col1, B.col1 FROM A LEFT JOIN B on (C.col3 = 'bye')
But pay attention, if you limit the condition to only key fields the optimizer engine will improve the performances very much.
For an inner join, these two statements are equivalent:
SELECT A.col1, B.col1
FROM A JOIN
B
ON A.col2 = B.col2 AND B.col3 = 'hello';
and:
SELECT A.col1, B.col1
FROM A JOIN
B
ON A.col2 = B.col2
WHERE B.col3 = 'hello';
Both should have the same execution plans as well.
Some people prefer putting filtering conditions in the WHERE clause, so the query is more clear about "conditions between tables" versus "filters on the result set". I tend to agree with this sentiment, although I'm not dogmatic about it.
OUTER JOINs are different. For an outer join, it makes a big different where the conditions go. In that case, you generally do not have a choice, so you use ON or WHERE to get the logic that you want.

How to avoid DISTINCT in a query that joins multiple tables?

I want to avoid using DISTINCT and produce the same result for queries that join multiple tables.
Without DISTINCT, it produces the same row multiple times.
I already tried looking up how to avoid DISTINCT, but nothing seems to work for me, seemingly because my table is more complicated and joining multiple tables at the same time.
SELECT DISTINCT C.COL3, B.COL1, A.COL2, A.COL4, B.COL5 FROM C
INNER JOIN B
ON B.COL1 = C.COL1
INNER JOIN A
ON B.COL2 = A.COL2
ORDER BY C.COL3 ASC;
I know I have to use GROUP BY somehow, but I just can't wrap my head around it...
You can just group by all the columns (without having ay aggregation):
SELECT
C.COL3, B.COL1, A.COL2, A.COL4, B.COL5
FROM C
JOIN B ON B.COL1 = C.COL1
JOIN A ON B.COL2 = A.COL2
GROUP BY C.COL3, B.COL1, A.COL2, A.COL4, B.COL5 -- group by all selected columns
ORDER BY C.COL3 ASC
If you then wanted to aggregate over the de-duped rows of the above query, use it as a subquery. For example, to SUM(B.COL5) of the de-duped rows:
SELECT
COL3, COL1, COL2, COL4, SUM(COL5)
FROM (
SELECT
C.COL3, B.COL1, A.COL2, A.COL4, B.COL5
FROM C
JOIN B ON B.COL1 = C.COL1
JOIN A ON B.COL2 = A.COL2
GROUP BY C.COL3, B.COL1, A.COL2, A.COL4, B.COL5
) deduped
GROUP BY COL3, COL1, COL2, COL4
ORDER BY COL3 ASC
Are you getting multiple duplicate rows of the same data if you do not use DISTINCT? If so, this query worked for me when I was joining multiple asp net tables in order to show the user info, plus the roles within the site they are assigned to. Hopefully this can help you.
SELECT AspNetUsers.Id, AspNetRoles.Name as SiteRole,
AspNetRoles.ID as RoleID, AspNetUsers.UserName,
AspNetUsers.Email FROM AspNetUserRoles INNER JOIN
AspNetUsers ON AspNetUserRoles.UserId = AspNetUsers.Id INNER JOIN
AspNetRoles ON AspNetUserRoles.RoleId = AspNetRoles.Id
You can use row_number() partition by [column you want to be distinct].
select *
from (select c.col3, b.col1, a.col2, a.col4, b.col5
, row_number() over (partition by c.col1 order by c.col3) as rn
from c
inner join b on b.col1 = c.col1
inner join a on a.col2 = b.col2) t1
where t1.rn = 1
order by t1.col3
SELECT COL3, COL1, SUM(COL5)
FROM
(
SELECT DISTINCT C.COL3, B.COL1, A.COL2, A.COL4, B.COL5 FROM C
INNER JOIN B
ON B.COL1 = C.COL1
INNER JOIN A
ON B.COL2 = A.COL2
) X
GROUP BY COL3, COL1
ORDER BY COL3, COL1

Left Join Table with Exclusive OR

Is there a way to join 2 tables together on one and only one of the possible conditions? Joining on condition "a" or "b" could duplicate rows, but I'm looking to only join once. I came up with a potential solution, but I'm wondering if there is a more slick way to do it.
For example:
SELECT *
FROM TableA a
LEFT JOIN TableB b
ON a.col1 = b.col1
OR (a.col1 != b.col1 AND a.col2 = b.col2)
This would join the tables on col1 OR col2 BUT NOT BOTH. Is there a cleaner way of doing this?
Not more efficient but I think more clear
SELECT *
FROM TableA a
LEFT JOIN TableB b
ON (a.col1 = b.col1 or a.col2 = b.col2)
AND NOT (a.col1 = b.col1 and a.col2 = b.col2)
Your method works. If you only want one (or a handful) of columns from b, I would suggest:
SELECT a.*, COALESCE(b.col3, b2.col3)
FROM TableA a LEFT JOIN
TableB b
ON a.col1 = b.col1 LEFT JOIN
TableB b2
ON a.col1 <> b2.col1 AND a.col2 = b2.col2;
Removing the OR from the JOIN conditions allows the optimizer to generate a better execution plan.

SQL: How can I add to a table without some duplicates?

So I am currently trying to take one table and add it into another table but for some reason it is not working the way I want it to.
There are three columns in both the tables and I only want to add each row of data from table 2 to table 1 if the first 2 columns of table 2 are not already in table 1 (I dont care about the 3rd column)
This is what I have so far:
INSERT INTO table1 (col1, col2, col3)
SELECT a.col1, a.col2, a.col3
FROM table2 as a
WHERE NOT EXISTS (SELECT b.col1, b.col2
FROM table1 as b
WHERE a.col1 = b.col1 AND a.col2 = b.col2);
I checked around and this seems that it should work but it isn't but can anyone see why?
I often have trouble when there are two fields to search for. One way is to combine them together:
INSERT INTO table1 (col1, col2, col3)
SELECT a.col1, a.col2, a.col3 from table2 as a
WHERE concat(a.col1,':', a.col2)
NOT IN (SELECT concat(col1,':',col2) from table1);
Another way is a left join:
INSERT INTO table1 (col1, col2, col3)
SELECT a.col1, a.col2, a.col3
from table2 as a
LEFT OUTER JOIN table1 as b
ON a.col1 = b.col1
AND a.col2 = b.col2
WHERE b.col1 IS NULL AND b.col2 IS NULL;
For example 2, it is better to use a primary key in the where clause.
Try this:
merge into tab2 a
using
(select col1,col2,col3 from tabl1) b
on
(b.col1=a.col1 and b.col2=a.col2)
when not matched then
insert (a.col1,a.col2,a.col3)
values
(b.col1,b.col2,b.col3);
Try this:
INSERT INTO table1 (col1, col2, col3)
(SELECT a.col1, a.col2, a.col3
FROM table2 a
WHERE NOT EXISTS (SELECT b.col1, b.col2
FROM table1 b
WHERE a.col1 = b.col1 AND a.col2 = b.col2));
I guess for table name as is not needed.

How can I search for values in three columns, but return rows that don't match all?

I have two tables, say A and B. I wish to compare three or more columns in both tables and to return any rows in table B that don't match all of the compared columns.
I've looked at doing a left join function from recommendations, but can't quite figure it out.
Please help!
You can use left join or not exists for this. Here is one method:
select b.*
from tableb as b
where not exists (select 1
from tablea as a
where a.col1 = b.col1 and a.col2 = b.col2 and a.col3 = b.col3
);
how about something like this
Select b.col1,b.col2,b.col3 from
tableb b left outer join tablea a
on ( b.col1 != a.co11 and b.col2 != a.co12 and b.col3 != a.co13 )