Suppress rows with reverse/swapped values - sql

I would like to query a database table that contains rows that have reverse values than other rows. So the table looks like this
Src Trgt ValueA ValueB
A B 1,44 5
B A 1,44 5 <--
C D 1,23 8
D C 1,23 8 <--
F G 5,12 9
G F 5,12 9 <--
What I want is a query that returns all rows that do not again with the source and target value swapped. The rows that should not be queried are the ones that have the same Value A and B like another row, but only with source and target value swapped (The ones marked in above table)
So, the desired results would look like this:
Src Trgt ValueA ValueB
A B 1,44 5
C D 1,23 8
F G 5,12 9

I think this is what you want:
select t.*
from t
where t.src < t.trgt
union all
select t.*
from t
where t.src > t.trgt and
not exists (select 1
from t t2
where t2.src = t.trgt and t2.trgt = t.src and
t2.a = t.a and t2.b = t.b
);
It keeps the first row encountered, filtering out equivalent rows where the first two columns are switched.
EDIT:
Another approach if you just one one row per combo is:
select least(src, trgt) as src, greatest(src, trgt) as trgt, a, b
from t
group by least(src, trgt), greatest(src, trgt), a, b;
This runs the risk of returning a row not in the original data (if the row has no duplicate and trgt > src.

SELECT *
FROM ztable zt
WHERE zt.source < zt.target -- pick only one of the twins
OR NOT EXISTS( -- OR :if it is NOT part of a twin
SELECT *
FROM ztable nx
WHERE nx.source = zt.target
AND nx.target = zt.source
);
Assuming that rows with source=target are not present or not wanted.

Related

I have 3 columns [A, B, C] in my SQL table. I want to find table entries, where values in A is same, in B is same, but C is different

I have 3 columns [A, B, C] in my SQL table. I want to find table entries, where values in A is same, in B is same, but C is different.
A B C
1 2 3
4 5 6
*3 4 5*
*3 4 6*
*7 8 9*
6 1 2
*7 8 3*
I want to preferably get something like:
A B C
3 4 5
3 4 6
7 8 9
7 8 3
as my result.
Thanks :)
The core of the solution below is to aggregate over your table on both columns A and B, and then retain those groups having more than one C value. Then join your full table to this aggregation query to retain only the records you want.
SELECT t1.*
FROM yourTable t1
INNER JOIN
(
SELECT A, B
FROM yourTable
GROUP BY A, B
HAVING COUNT(DISTINCT C) > 1
) t2
ON t1.A = t2.A AND t1.B = t2.B
ORDER BY
t1.A, t1.B;
Here is a demo in MySQL, though the above query should run on pretty much any other database with little modification.
Demo
Try this:
select A,B,C from (
select A,B,C, avg(C * 1.0) over (partition by A,B) [avg] from MY_TABLE
) a where [avg] <> C
The idea behind is simple, if all numbers within a set are equal, they also are equal to the average of the set.
This one should work too:
SELECT DISTINCT
t1.*
FROM
test t1
INNER JOIN
test t2 ON t2.a = t1.a
AND t2.b = t1.b
AND t2.c <> t1.c;
Here's a demo: link
I'm not sure about performance due to lots of duplicates being generated/truncated compared to other solutions, though.
No need to count or rank; you only want to check if at least one qualifying row EXISTS
select *
from thetable tt
where exists(
select * from thetable x
where x.a = tt.a and x.b = tt.b
and x.c <> tt.c
);

How to find doubles in master-child table?

I need help with a query to find doubles. Let met explain the situation by example:
tableA (the master table) has a key field keyA with these values :
keyA
1
2
3
etc
tableB (the client table) has a foreign key field keyA and a value field, fieldB
keyA fieldB
1 a
1 b
2 a
2 b
3 a
3 c
4 a
4 b
4 c
etc
So, the values for fieldB in child table tableB are:
for tableA.keyA = 1 are: a and b
for tableA.keyA = 2 are: a and b
for tableA.keyA = 3 are: a and c
for tableA.keyA = 4 are: a, b and c
Now, given a value for keyA I need to find all records in tableA that have matching records in tableB for the field fieldB.
For example, if I search with keyA = 1 then
tableA.keyA = 2 is OK because both have same tableB.fieldB (a and b versus a and b)
tableA.keyA = 3 is not OK because both have not same tableB.fieldB (a and b versus a and c)
tableA.keyA = 4 is not OK because both have not same tableB.fieldB (a and b versus a, b and c)
I need a query that can give me this result. I hope someone can help me with this or can point me into the right direction.
Try this simple query , hope this will solve your problem
DECLARE #vkey int = 1
;WITH cte_test AS (
SELECT keyA,(SELECT ','+fieldb FROM tableB t1 WHERE t1.keyA = t.keyA FOR XML path('')) AS rslt
from tableB t
GROUP BY t.keyA)
SELECT t2.*
FROM cte_test t1
INNER JOIN cte_test t2 ON t1.[rslt] = t2.[rslt] AND t2.[keyA] <> t1.[keyA]
WHERE t1.[keyA] = #vkey
If there is no other item have the same combination , then there is no records in the result, otherwise it will return the matched items.
Assuming there are no duplicates, you can do this with a self-join and aggregation:
select c.keyA, c2.keyA
from (select c.*, count(*) over (partition by keyA) as numBs
from clientTable c
) c join
(select c.*, count(*) over (partition by keyA) as numBs
from clientTable c
) c2
on c2.fieldB = c.fieldB and
c2.keyA <> c.keyA and
c.keyA = 1 -- or whatever key you want to check
where c.numBs = c2.numBs
group by c.keyA, c2.keyA, c.numBs, c2.numBs
having count(*) = c.numBs;
The idea is to count the number of fieldB values for each keyA. These need to be equal (where c.numBs = c2.numBs) and to check that all match (having count(*) = c.numBs).

SQL: outer join two tables on String and insert similar into another

I have two tables A and B with 30 columns (same variable names, data for different year), no primary key, almost a million records each.
I want to compare A.X1 with B.X1 (nvarchar8, contains spaces, -, letter and numbers) and insert the outer join results in another table C (with same 30 columns) so I have all rows of A and where B!=A on B.X1).
Example:
Table A
X1 X2 X3 ..... X30
11 E R ..... G
12 R 4 L
13 S 5 NULL
14 D T NULL
Table B
X1 X2 X3 ..... X30
11 E R ..... G
12 R 4 L
15 R2 56 NULL
16 R1 T1 NULL
Resulting table C
X1 X2 X3 ..... X30
11 E R ..... G
12 R 4 L
13 S 5 NULL
14 D T NULL
15 R2 56 NULL
16 R1 T1 NULL
How do I do that.
I tried
INSERT INTO C
SELECT *
from A
full outer join B
on A.X1 = B.X1
Error I get
Msg 213, Level 16, State 1, Line 1
Insert Error: Column name or number of supplied values does not match table definition.
I have C created, which is currently empty.
insert C
select *
from A
union all
select *
from B
where not exists
(
select *
from A
where X1 = B.X1
)
Your query will not work becasue you are joining the tables and retunring *, with ill results in twice the number of columns that you need.
What you really want to do is select everything from table A then APPEND (rather than join) all the records from table B.
Appends are achieved by using a UNION. Here is some sample code. Note: never, ever use SELECT *. Addapt the follwing to include the specifically named fields in the correct order.
Also, I am using UNION rather than UNION ALL so that the query automaticlly excludes the records in B that are duplicates of records in A.
SELECT FIELDS...
FROM TABLEA
UNION
SELECT SAME_FIELDS...
FROM TABLEB
Insert Into TableC
(
-- List your fields explicitly
)
Select
-- List all tableA.Fields explicitly
From tableA
Left Outer Join tableB On tableB.X1 = tableA.X1
Where tablB.X1 IS NULL

Help required with a complex self join sql query

myTable is having composite key formed of columns A and B (total columns A, B, C, D, E).
I want to exclude/ignore records where value of D (say order number) is same and E (say decision) is Y in one but N or Null in other. (means all the twin-records with same order number (equal D value) which were ordered first (so E=Y) and then again cancelled (so E=N) should be ignored)
So I pulled out A,B for all records where D is same but E is Y in one and N in other
SELECT *
FROM myTable A, myTable B
WHERE
(A.D=B.D)
AND
((A.E ='Y' AND (B.E ='N' OR B.E IS NULL)) OR (B.E='Y' AND (A.E='N' OR A.E IS NULL)))
Now my final output should be all records from myTable but not the records found above.
I wrote a join query but its not working as it should. Basically issue is how to compare two composite keys ??
Sample Data:
A B C D E
=========================
1 A xyz ONE Y
2 B pqr TWO Y
3 C lmn ONE N
4 D abc THREE Y
5 E ijk FOUR Y
=========================
Thus, my output should be records 2,4 and 5. As 1 and 3 will be ignored. Because 1.D = 3.D and 1.E is Y but 3.E is N.
Thanks,
Nik
I want to exclude records where value of D is "XYZ".
Why not simply query like this directly?
select *
from myTable
where D <> 'XYZ'
To exclude rows from Temp, you could:
select *
from myTable
where not exists
(
select *
from temp
where myTable.A = temp.A
and myTable.B = temp.B
)
Or with an exclusive left join:
select *
from myTable
left join
temp
on myTable.A = temp.A
and myTable.B = temp.B
where temp.A is null
If I've correctly understood you, what you need is this:
select x.*
from mytable x left outer join
( select mt1.a, mt1.b
from mytable mt1 inner join
mytable mt2 on mt1.d = mt2.d
where ((mt1.E ='Y' AND (mt2.E ='N' OR mt2.E IS NULL)) OR (mt2.E='Y' AND (mt1.E='N' OR mt1.E IS NULL)))
) y on x.a = y.a and x.b = y.b
where y.a is NULL
You need something like
select A.*
from myTable A
WHERE (SELECT COUNT(*) FROM myTable B WHERE B.D = A.D AND (B.E IS NULL OR B.E = 'N')) = 0

Multiple NOT distinct

I've got an MS access database and I would need to create an SQL query that allows me to select all the not distinct entries in one column while still keeping all the values.
In this case more than ever an example is worth thousands of words:
Table:
A B C
1 x q
2 y w
3 y e
4 z r
5 z t
6 z y
SQL magic
Result:
B C
y w
y e
z r
z t
z y
Basically it removes all unique values of column B but keeps the multiple rows of the
data kept. I can "group by b" and then "count>1" to get the not distinct but the result will only list one row of B not the 2 or more that I need.
Any help?
Thanks.
Select B, C
From Table
Where B In
(Select B From Table
Group By B
Having Count(*) > 1)
Another way of returning the results you want would be this:
select *
from
my_table
where
B in
(select B from my_table group by B having count(*) > 1)
select
*
from
my_table t1,
my_table t2
where
t1.B = t2.B
and
t1.C != t2.C
-- apparently you need to use <> instead of != in Access
-- Thanks, Dave!
Something like that?
join the unique values of B you determined with group by b and count > 1 back to the original table to retrieve the C values from the table.