I am trying to select all those rows where t1.col1 value is in t1.col2 value AND t1.col2 value is in t1.col1 value. This imply that for a given row it exists the "mirror" value in another row.
For example, I would select both rows if:
col1 col2
A B
B A
But not select if the table contains only one of those 2 rows.
I tried the following query without success:
SELECT distinct t1.*
FROM table AS t1
INNER JOIN table t2 ON (t1.col1 = t2.col2 AND t2.col1 = t1.col2)
Any help would be very appreciated.
You can join the table to itself (using different aliases), for matching "opposing rows". For example:
select a.*
from t a
join t b on b.col2 = a.col1 and b.col1 = a.col2
Result:
col1 col2
----- ----
A B
B A
See running example at DB Fiddle.
Related
A sample table with two column and I need to compare the column 1 and column 2 to the same table records and need to remove the column 1 + column 2 = column 2+column 1.
I tried to do self join and case condition. But its not working
If I understand correctly, you can run a simple select like this if you have all reversed pairs in the table:
select col1, col2
from t
where col1 < col2;
If you have some singletons, then:
select col1, col2
from t
where col1 < col2 or
(col1 > col2 and
not exists (select 1
from t t2
where t2.col1 = t.col2 and
t2.col2 = t.col1
)
);
You can use the except operator.
"EXCEPT returns distinct rows from the left input query that aren't output by the right input query."
SELECT C1, C2 FROM table
Except
SELECT C2, C1 FROM table
Example with your given data set : dbfiddle
I am posting the answer based on oracle database and also the columns are string/varchar:
delete from table where rowid in (
select rowid from table
where column1 || column2 =column2 || column1 )
Feel free to provide more input and we can tweak the answer.
Okay. There might be a simpler way of doing this but this might work as well. {table} is to be replaced with your table name.
;with orderedtable as (select t1.col1, t1.col2, ROW_NUMBER() OVER(ORDER BY t1.col1, t1.col2 ASC) AS rownum
from (select distinct t2.col1, t2.col2 from {table} t2) as t1)
select f1.col1, f1.col2
from orderedtable f1
left join orderedtable f2 on f1.col1 = f2.col2 and f1.col2 = f2.col1 and f1.rownum < f2.rownum
where f2.rownum is null
The SQL below will get the reversed col1 and col2 rows:
select
distinct t2.col1,t1.col2
from
table t1
join
table t2 on t1.col1 = t2.col2 and t1.col2 = t2.col1
And when we get these reversed rows, we can except them with the left join clause, the complete SQL is:
select
t.col1,t.col2
from
table t
left join
(
select
distinct t2.col1,t1.col2
from
table t1
join
table t2 on t1.col1 = t2.col2 and t1.col2 = t2.col1
) tmp on t.col1 = tmp.col1 and t.col2 = tmp.col2
where
tmp.col1 is null
Is it clear?
table 1
col1 col 2
A aaa
B bbb
C ccc
table 2
col1 col 2 col3
A aaa xx
B bbb yy
C ccc zz
D ddd hh
E eee mm
How to write a query where i get all of table1 data and only col3 to existing records of Table 1. table1 has only 50 records and Table2 has 100k. But i need only all 50 records of Table 1 and only col3 added to the record by joining
table1. col1 = table2.col1
Based on the description, I would suggest this query:
SELECT
t1.col1,
t2.col2,
t2.col3
FROM
table1 AS t1
INNER JOIN
table2 AS t2 ON (t2.col1 = t1.col1 AND t2.col2 = t1.col2)
The SELECT clause determines what columns will appear in the result set. Your description gives us some assistance here.
For a join, choosing the correct join type is important to what query you are making. Your description is helpful for this:
How to write a query where I get all of table1 data and only col3 to existing records of Table 1.
“get all of table1” implies that the result set should include all columns from that table.
SELECT table1.col1, table1.col2 […]
“get all of table1” implies that table1 is the primary source in the FROM clause.
[…] FROM table1 […]
“only col3 [from table2]” implies that the result set should also include that column.
SELECT […] table2.col3
“only […] to existing records of table1” implies that the join type is INNER JOIN.
FROM table1
INNER JOIN table2 […]
“only col3 to existing records of table1” implies that is the join condition.
FROM table1
INNER JOIN table2 ON table2.[…] = table1.[…]
But you don't specify exactly what condition tells us what records are equivalent between the tables. Shall we assume that the condition is for all columns named the same to have the same value?
FROM table1
INNER JOIN table2 ON (table2.col1 = table1.col1 AND table2.col2 = table1.col2)
We will be using the tables several times, so it's good practice to set concise AS aliases in the FROM clause.
You want INNER JOIN :
SELECT t1.col1, t1.col2, t2.col3
FROM table1 t1 INNER JOIN
table2 t2
ON t2.col1 = t1.col1;
Try left join:
SELECT t1.col1, t1.col2, t2.col3
FROM table1 t1 LEFT JOIN
table2 t2
ON t1.col1 = t2.col1 AND t1.col2 = t2.col2;
I have a source table A with a number of columns. I want to do a transformation of the source table to a target table. I would like to have a mapping table with same columns as the source table A and with rows that make up the translations.
Here is an example of the table A:
COL1 COL2 COL3
aktie ja 2
aktie nej 3
obli ja 2
and here is the mapping table
COL1 COL2 COL3 TRANSFORM
aktie ja NULL 3
aktie NULL NULL 4
Now, the idea is to join the source table with the mapping and get the transformed value returned. The use of NULL should serve as a wildcard. So my desired result should be that the first row in table A would match the first row in the mapping table and return the value 3
For the second row - and here is my challenge - I want it to match the second row in the mapping table because it is NOT matched by rows that have a value already (which would result in the transformed value 3) and as the second mapping row has NULL in column two, it should be treated as a wildcard (although taking into account other rows in the mapping table as well).
My first attempt would be something like
select A.*, m.res
from tab1 A
inner join mapping m on t.col1 = isnull(m.col1, t.col1)
and t.col2 = isnull(m.col2, t.col2)
and ...
but the problem is that the isnull(..,..) will match everything and not only return matches except the listed possible values that would result in a different transformation.
I am looking for a generic solution that would Work for any table with any number of columns, not only this particular table-layout mentioned here.
I have been thinking a lot about this and cannot really seem to come up with the solution, so please help :)
Here is one way to do this using a CTE (will work on SQL Server and Oracle)
WITH Map3 as
( -- TRANSFORM WILL BE NULL IF A MATCH WAS NOT MADE
SELECT T1.COL1, T1.COL2, T1.COL3, M.TRANSFORM
FROM Table1 T1
LEFT JOIN Mapping M ON T1.COL1 = M.COL1
AND T1.COL2 = M.COL2
AND T1.COL3 = COALESCE(M.COL3, T1.COL3)
), Map2 as
(
SELECT T1.COL1, T1.COL2, T1.COL3, COALESCE(T1.TRANSFORM,M.TRANSFORM)
FROM Map3 T1
LEFT JOIN Mapping M ON T1.COL1 = M.COL1
AND T1.COL2 = COALESCE(M.COL2, T1.COL2)
AND T1.TRANSFORM IS NULL
)
SELECT *
FROM Map2
I believe it is clear how this works and how to "extend" this to more columns.
If you can't use a CTE this is functionally the same and can be nested as far as you like:
SELECT T1.COL1, T1.COL2, T1.COL3, COALESCE(T1.TRANSFORM,M.TRANSFORM)
FROM (
-- TRANSFORM WILL BE NULL IF A MATCH WAS NOT MADE
SELECT T1.COL1, T1.COL2, T1.COL3, M.TRANSFORM
FROM Table1 T1
LEFT JOIN Mapping M ON T1.COL1 = M.COL1
AND T1.COL2 = M.COL2
AND T1.COL3 = COALESCE(M.COL3, T1.COL3)
) T1
LEFT JOIN Mapping M ON T1.COL1 = M.COL1
AND T1.COL2 = COALESCE(M.COL2, T1.COL2)
AND T1.TRANSFORM IS NULL
I have 2 tables table A and table B. In table B we have to check if all the column entered is exactly as in table A, means if a row exists in table B then the same row will be there in table A too. also table A may have rows which are not in table B. if there is a row which is not in table A and is there in table B, an alert should be displayed showing which element is extra in table B.
Can we do this using join? if so what will be the sql code?
this is the best picture about joins i've ever seen :)
You probably want to have a look at the following article
SQL SERVER – Introduction to JOINs – Basic of JOINs
This should give you a very clear understanding of JOINs in Sql.
From there you should be able to find the solution.
As an example, you would have to look at something like
TABLE1
Col1
Col2
Col3
Col4
TABLE2
Col1
Col2
Col3
Col4
--all rows that match
SELECT *
FROM TABLE1 t1 INNER JOIN
TABLE2 t2 ON t1.Col1 = t2.Col1
AND t1.Col2 = t2.Col2
...
AND t1.Col3 = t2.Col3
--rows only in TABLE1
SELECT *
FROM TABLE1 t1 LEFT JOIN
TABLE2 t2 ON t1.Col1 = t2.Col1
AND t1.Col2 = t2.Col2
...
AND t1.Col3 = t2.Col3
WHERE t2.Col1 IS NULL
--rows only in TABLE2
SELECT *
FROM TABLE1 t2 LEFT JOIN
TABLE2 t1 ON t1.Col1 = t2.Col1
AND t1.Col2 = t2.Col2
...
AND t1.Col3 = t2.Col3
WHERE t1.Col1 IS NULL
If you want to compare based on single column, then you can do something like this:
SELECT ID FROM B LEFT JOIN A ON B.ID = A.ID WHERE A.ID IS NULL;
The above query will give you the list of records that are not present in A but in B.
Instead if you want to compare the entire row, you can use the following approach:
SELECT COUNT(*) FROM B;
SELECT COUNT(*) FROM A;
SELECT COUNT(*) FROM (
SELECT * FROM B UNION SELECT * FROM A
)
If all the queries returns the same count then you can assume that both the tables are exactly equal.
I have 1 table with data thus:
Col1 Col2
------- --------
Admin001 A
Admin001 B
Admin002 C
Admin002 C
Admin003 A
Admin003 C
I need to find all instances of Col2 values with 'A' immediately followed by 'B'. 'A' followed by any other symbol does not count. Is there a way to use SQL to accomplish this?
Environment is DB2 LUW v9.5
Update:
How can I do this if I make the table like below?
Col1 Col2 Col3
---- ------- --------
1 Admin001 A
2 Admin002 C
3 Admin002 C
4 Admin003 A
5 Admin003 C
6 Admin001 B
7 Admin001 A
8 Admin001 C
9 Admin001 B
Given that there is no implicit ordering of a set, then no, there isn't any reliable way to do this. Your data will need to be ordered (perhaps by a third column, or by column 1) for this to make any sense.
SELECT DISTINCT T1.Col2
FROM Table T1 INNER JOIN Table T2
ON T2.Col2 = T1.Col2 AND T2.Col1 = (T1.Col1 + 1)
WHERE T1.Col3 = 'A' AND T2.Col3 = 'B'
Update: As mentioned by Peter Lang, below, this will not work if the sequence in Col1 is interrupted. This version handles that situation and is more guaranteed to produce the correct result although if you're 100% certain the sequence will not be interrupted (that is, if you generate the sequence yourself in the same transaction as the analysis) the first should be faster:
SELECT DISTINCT T1.Col2
FROM Table T1 INNER JOIN Table T2
ON T2.Col2 = T1.Col2
AND T2.Col1 = (SELECT MIN(Col1) FROM Table T3 WHERE T3.Col1 > T1.Col1)
WHERE T1.Col3 = 'A' AND T2.Col3 = 'B'
It looks like you're trying to find out who's grade dropped from A to B, so we'll also assume that you want the results where B follows A for the same admin.
SELECT DISTINCT t1.Col2
FROM table t1
INNER JOIN table t2 ON t1.Col2 = t2.Col2
LEFT OUTER JOIN table t3 ON t1.Col2 = t3.Col2
AND t3.Col1 < t2.Col1 AND t3.Col1 > t1.Col1
WHERE t1.Col3 = 'A'
AND t2.Col3 = 'B' AND t2.Col1 > t1.Col1
AND t3.Col1 IS NULL
This yields any admin who has 'A' followed by 'B'.
The INNER JOIN and the first two expressions in the WHERE clause finds all records where 'B' occurs after 'A'. The left OUTER join and the last expression in the WHERE clause finds all records where there are grades between the A and B, and only takes the records without.
You asked to get these results, one per row, like this:
Col1 Col2 Col3
---- ------- --------
1 Admin001 A
6 Admin001 B
I'm going to adapt the above query the easy way.
I'll simply get the A records, get the B records, and union them:
(SELECT t1.Col1, t1.Col2, t1.Col3
FROM table t1
INNER JOIN table t2 ON t1.Col2 = t2.Col2
LEFT OUTER JOIN table t3 ON t1.Col2 = t3.Col2
AND t3.Col1 < t2.Col1 AND t3.Col1 > t1.Col1
WHERE t1.Col3 = 'A'
AND t2.Col3 = 'B' AND t2.Col1 > t1.Col1
AND t3.Col1 IS NULL)
UNION
(SELECT t2.Col1, t2.Col2, t2.Col3
FROM table t1
INNER JOIN table t2 ON t1.Col2 = t2.Col2
LEFT OUTER JOIN table t3 ON t1.Col2 = t3.Col2
AND t3.Col1 < t2.Col1 AND t3.Col1 > t1.Col1
WHERE t1.Col3 = 'A'
AND t2.Col3 = 'B' AND t2.Col1 > t1.Col1
AND t3.Col1 IS NULL)
ORDER BY Col2, Col1
Notice that we're ordering by Col2 first, then Col1. You may also get more than one set of records for each user.
How are you sorting the columns? If you aren't sorting them, you could get different results each time, as sometimes A would follow B, and sometimes B would follow A. If you are sorting them, you may be able to use an 'exists' test with the sorting expression.
There is no general method of getting the next (or previous) row in SQL, but many implementations provide their own built-in functions to help with that kind of thing. Unfortunately I'm not familiar with DB2.
This query assumes that col1 is some sort of sequence or timestamp for each row. Without it, there's no way to determine if A happened before or after B.
WITH sorted AS
(SELECT col1, col2, col3, ROWNUMBER()
OVER (PARTITION BY col2 ORDER BY col1) AS col4
FROM sometable
)
SELECT a.col1, a.col2, a.col3, b.col1, b.col3
FROM sorted a INNER JOIN sorted b
ON a.col2 = b.col2
WHERE a.col3 = 'A' AND b.col3 = 'B'
AND b.col4 = a.col4 + 1
;
I think the following should work, assuming your updated table layout with 3 columns. (Otherwise it's impossible, because no ordering is available):
select t1.col2
from yourtable t1, yourtable t2
where t1.col3 = 'A'
and t2.col3 = 'B'
and t1.col1 + 1 = t2.col1;