What does this sql mean with not exists? - mysql

a table like this
int char int int
id name a_id b_id
SELECT count(*) FROM tbl t1 WHERE b_id = 12 AND NOT EXISTS(select * from tbl t2 where t2.a_id = t1.b_id AND t2.b_id = t1.a_id)
I think it at least equals to
SELECT count(*) FROM tbl t1 WHERE b_id = 12 AND NOT EXISTS(select * from tbl t2 where t2.a_id = 12 AND t2.b_id = t1.a_id)
then what does this mean?
For example, SELECT a_id FROM tbl t1 WHERE b_id = 12 gives 1,2,3,4
then do following:
select * from tbl t2 where t2.a_id = 12 AND t2.b_id = 1 # NULL
select * from tbl t2 where t2.a_id = 12 AND t2.b_id = 2 # exists
select * from tbl t2 where t2.a_id = 12 AND t2.b_id = 3 # exists
select * from tbl t2 where t2.a_id = 12 AND t2.b_id = 4 # NULL
so the count(*) will be 2?

This one is very interesting because it finds "symmetries" in a_id and b_id with the number 12,so basically it counts the number of rows in the table where b_id=12 except for the ones which have a symmetric pair, like this:
| a_id | b_id |
---------------
| 12 | 12 |
| 12 | 2 |
| 2 | 12 |
Or more generally speaking, the query skips counting the rows which have a_id=X b_id=12 and there exists another row where a_id=12 and b_12=X.
So the NOT EXISTS is simply there to skip counting rows which have a symmetric pair, I don't know what this can be useful for in most applications but it is interesting nonetheless.

Related

How can I get a record which has two corresponding columns which are multiple in SQL?

For example, I have two tables:
ID | Name
------------
1 | test 1
2 | test 2
ID2| ID | Age
--------------
1 | 1 | 18
2 | 1 | 18
3 | 1 | 19
4 | 2 | 18
5 | 2 | 19
I want to have all records that have columns which are multiple in name with age but I don't know how to do that.
I want an output like this:
Name | Age
--------------------
test 1 | 18
test 1 | 18
Can anyone help me?
Try following query:
Select t1.*, t2.*
from table1 t1
join table2 t2
on t1.id = t2.id
join (select id, age
from table2
group by id, age
having count(*) > 1
) t3
on t1.id = t2.id and t2.id = t3.id and t2.age = t3.age
Use exists:
select t.*
from t
where exists (select 1
from t t2
where t2.name = t.name and t2.age = t.age and
t2.id <> t.id
);
With an index on (name, age, id), this should be the fastest approach.
You can also use an IN on tupples.
And a GROUP BY can be combined with a HAVING to only get those that have duplicate (name, age).
SELECT t1.Name, t2.Age
FROM YourTable2 t2
LEFT JOIN YourTable1 t1 ON t1.ID = t2.ID
WHERE (t2.ID, t2.Age) IN (
SELECT ID, Age
FROM YourTable2
GROUP BY ID, Age
HAVING COUNT(*) > 1
);

Return an entry from a table based on criteria, which is not in another table

I need help with a query and i cant figure out how to make it work.
Table1
uid | G | L
------------
cde 2 1
fgk 1 2
kgl 2 1
Table2
uid1 |uid2
-----------
abc cde
fgk cde
mnm kgl
I have a known uid which is
uid | G | L
-----------
abc 1 2
and i must match this uid with one from Table1
My query for this is :
SELECT * FROM Table1 WHERE G=2 AND L=1 ORDER BY RAND() LIMIT 1
This will return:
cde 2 1
kgl 2 1
The query that i am looking for must return only kgl because cde is already paired with abc in Table2
Any ideas?
UPDATE: With some tweaking i have come up with this query:
SELECT uid FROM table1 AS t1
WHERE G = 1 AND L = 2 AND NOT EXISTS
(SELECT * FROM table2 AS t2
WHERE (t1.uid = t2.uid1 OR t1.uid=t2.uid2) AND (t2.uid1 = 'abc' OR t2.uid2 = 'abc'))
You can do it using NOT EXISTS:
SELECT uid, G, L
FROM Table1 AS t1
WHERE G = 2 AND L = 1
AND NOT EXISTS (SELECT 1
FROM Table2 AS t2
WHERE t1.uid = t2.uid2 AND t2.uid1 = 'abc')
Demo here

Find the minimum discerning subset in MySQL

I have a t table, with let's say field1 and field2. field1 is an identifier of sets and field2 contains the member of the sets. Now, the question is, how to find out the smallest amount of field2 values that will uniquely find a given field1?
Sample data
+------+------+
|field1|field2|
| 1 | A |
| 1 | B |
| 1 | C |
| 2 | A |
| 2 | C |
| 2 | D |
| 3 | B |
| 3 | D |
+------+------+
I am looking for a query which given 1 as an argument returns (A,B), for 2 returns (A,D) or (C,D) both are good and for 3 returns (B,D). If the generic case is too hard then let's ask: is there such a pair that does this.
Once I have such a pair I can plug it into this query:
SELECT DISTINCT field1
FROM t t1
INNER JOIN t t2 USING(field1)
WHERE t1.field2 = 'A' AND t2.field2 = 'B'
and get only a single row.
I have tried something like SELECT field2 FROM t WHERE field2 NOT IN (SELECT field2 FROM t WHERE field1 != 1) and field1 = 1 but this obviously doesn't work.
You write a subquery that returns all pairs of field2 values for each field1. Then use a left join of this with itself, finding pairs that have the same field2 values, but different field1. These then get excluded with the NULL check, and you're left with the unique pairs for each field1.
SELECT subq1.field1, subq1.a, subq1.b
FROM (
SELECT t1.field1, t1.field2 AS a, t2.field2 AS b
FROM t AS t1
JOIN t AS t2 ON t1.field1 = t2.field1 AND t1.field2 < t2.field2
) as subq1
LEFT JOIN (
SELECT t1.field1, t1.field2 AS a, t2.field2 AS b
FROM t AS t1
JOIN t AS t2 ON t1.field1 = t2.field1 AND t1.field2 < t2.field2
) AS subq2 ON subq1.field1 != subq2.field1 AND subq1.a = subq2.a AND subq1.b = subq2.b
WHERE subq2.field1 IS NULL
DEMO
I have written below query
SELECT temp. field1,temp.firstValue,temp.secondValue
FROM (SELECT table1.field1 , table1.field2 firstValue ,table2.field2 secondValue FROM T table2 ,T table1
WHERE table1.field1 = table2.field1 AND table2.field2<> table1.field2 AND table1.field2 < table2.field2
) temp
GROUP BY temp. field1,temp.firstValue
It will give you below pairs
field1 firstValue secondValue
------ ---------- -----------
1 A B
1 B C
2 A C
2 C D
3 B D
Please let me know if for input 2 pair (A,C) and (A,D) would be sufficient

mysql selecting a union where values in one don't appear in the other

sorry for the poorly titled post.
Say I have the following table:
C1 | C2 | c3
1 | foo | x
2 | bar | y
2 | blaz | z
3 | something| y
3 | hello | z
3 | doctor | x
4 | name | y
5 | continue | x
5 | yesterday| z
6 | tomorrow | y
I'm trying to come up w/ a sql statement which performs the following union:
1st retrieval retrieves all records w/ c3 = 'y'
2nd retrieval retrieves the first instance of a record where c3 <> 'y' and the result is not in the previous union
So, for the result, I should see:
C1 | C2
1 | foo
2 | bar
3 | something
4 | name
5 | continue
6 | tomorrow
So two questions: 1: Am I totally smoking crack where I think I can do this, and 2: (assuming I can), how do I do this?
Try this one:
SELECT a.C1, a.C2
FROM MyTable a
WHERE a.C3 = 'y'
UNION
SELECT b.C1, b.C2
FROM MyTable b
WHERE b.C3 <> 'y' AND
b.C1 not in
(
SELECT c.C1
FROM MyTable c
WHERE c.C3 = 'y'
)
UPDATE 1
by the way, why is that there is only one record of 5 in your desired result? where, in fact, there could be two.
SEE FOR DEMO 1
OR
SELECT g.C1, MIN(g.C2) C2
FROM
(SELECT a.C1, a.C2
FROM MyTable a
WHERE a.C3 = 'y'
UNION
SELECT b.C1, b.C2
FROM MyTable b
WHERE b.C3 <> 'y' AND
b.C1 not in
(
SELECT c.C1
FROM MyTable c
WHERE c.C3 = 'y'
)
) g
GROUP BY g.C1
SEE FOR DEMO 2 (yields same result with your desired result)
DEMO # Sql Fiddle.
select *
from table1
where c3 = 'y'
union all
(select table1.*
from table1
left join table1 t1
on table1.c1 = t1.c1
and t1.c3 = 'y'
where table1.c3 <> 'y'
and t1.c1 is null
-- The meaning of first becomes clear here
order by table1.c3, table1.c2
limit 1)
Note: foo is not in a list because it is marked as x.
Try this:
SELECT C1, C2
FROM Table1
Where C3 = 'y'
UNION
(
SELECT C1, C2
FROM Table1
Where C3 <> 'y' ORDER BY C1 LIMIT 1
)
ORDER BY C1

Multiple data check in one query

I have the following problem. I have 2 tables in the database - table1 and table2.
Table1
id| val1| val2
--------------
1 | 234 | 342
2 | 325 | 356
...
Table2
id | uid | val
--------------
1 | 5 | 234
2 | 6 | 362
3 | 5 | 123
I would like to check for each record in table2 if val exists in table1 (table2.val=table1.va1 or table2.val > table1.vall).
In table1 is about 2 million records. In table2 several thousand.
If query result true i'd like to remove rows from table2.
Is it possible to do this in one query? mysql or postgresql
Performance is very important.
Assuming (t2.val = t1.val1) or (t1.val2 > t2.val) conditions:
delete table2
from table2 t2
inner join table1 t1 on (t2.val = t1.val1) or (t1.val2 > t2.val)
delete t
from #table2 t
inner join #table1 t2
on t.val = t2.val or t2.val>t.val
Assuming uid in Table2 reference id in Table1 (and that neither table contain nulls), this returns the rows in Table1 that satisfy your existence criteria:
SELECT *
FROM Table1
WHERE EXISTS (
SELECT *
FROM Table2
WHERE Table2.uid = Table1.id
AND (
Table2.val = Table1.val1
OR Table2.val > Table1.val2
)
);