Consider the following DB table:
c p
=========
1 'a'
1 'b'
2 'a'
2 'c'
Now, my goal is to retrieve a list of numbers c, for which holds that each number in this list has at least a record with p='a' AND p='b'.
In the example table above, that would be c=1.
Now my question is, how do I accomplish this using one MySQL query?
select t1.c
from MyTable t1
inner join MyTable t2 on t1.c = t2.c
where t1.p = 'a' and t2.p = 'b'
Update:
select c
from MyTable
where p in ('a', 'b', 'c', 'd')
group by c
having count(distinct p) = 4
There are different ways to attack the problem depending on the rules your data follows if any. Without knowing more about your problem, I would do:
SELECT t1.c FROM table t1 INNER JOIN table t2
ON t1.c = t2.c
WHERE t1.p = 'a' AND t2.p = 'b'
Related
I have the below table T in MySQL, with columns A and B.
I want to query this table to get a value 'C', that has the count of the number of times the value in Column 'A' appears in Column 'B'. For example, 1 appears 2 times in Column B, so the first row of column C should be 2. I don't want to iterate over the table, so I want to get this using subqueries. The desired output is given below.
I tried using the below query
SELECT A, B, (SELECT COUNT(A) FROM T WHERE B = A) AS C
FROM T
But I got 0 for all rows in column C. Please help me identify the mistake.
Use a correlated subquery:
SELECT t1.A, t1.B,
(SELECT COUNT(*) FROM tablename t2 WHERE t2.B = t1.A) AS C
FROM tablename t1
Or:
SELECT t1.A, t1.B,
(SELECT SUM(t2.B = t1.A) FROM tablename t2) AS C
FROM tablename t1
Or with a self LEFT join and aggregation:
SELECT t1.A, t1.B, COUNT(t2.B) AS c
FROM tablename t1 LEFT JOIN tablename t2
ON t2.B = t1.A
GROUP BY t1.A, t1.B
I have two tables with different indices that I can (manually) map from one to the other:
table1 table2
ID Name Data ID Name Data
1 A X 4 C1 11
2 B Y 5 B2 22
3 C Z 6 A3 33
A maps to A3, B maps to B2, C maps to C1
The result set I am hoping for is:
t1.ID t1.Name t1.Data t2.ID t2.Name t2.Data
1 A X 6 A3 33
2 B Y 5 B2 22
3 C Z 4 C1 11
This query fails because it doesn't recognize "map":
SELECT *,
CASE t1.name
WHEN 'A' THEN 'A3'
WHEN 'B' THEN 'B2'
WHEN 'C' THEN 'C1'
END AS map
FROM table1 AS t1
INNER JOIN table2 AS t2 ON (t2.name = map)
This query fails because you can't use CASE inside an ON condition:
[This query actually works. I had forgotten the END in my actual code. Turns out that makes a big difference.]
SELECT *
FROM table1 AS t1
INNER JOIN table2 AS t2 ON (t2.name = (SELECT CASE t1.name
WHEN 'A' THEN 'A3'
WHEN 'B' THEN 'B2'
WHEN 'C' THEN 'C1'
END ) )
So my questions are:
1) What Google search terms should I be using to find the solution I need?
2) What is the actual solution?
3) Can this be done without creating a lookup table (easiest solution)?
The where clause cannot access an alias defined in the select clause (because, basically, the former is evaluated before the latter).
You want the case expression in the join condition instead:
SELECT
t1.ID t1_id,
t1.name t1_name,
t1.data t1_data,
t2.ID t2_id,
t2.name t2_name,
t2.data t2_data
FROM table1 AS t1
INNER JOIN table2 AS t2
ON t2.name = CASE t1.name
WHEN 'A' THEN 'A3'
WHEN 'B' THEN 'B2'
WHEN 'C' THEN 'C1'
END
Note that it is better to use aliases in the select clause to disambiguate columns that have the same name across tables, as shown above;
Sorry for having difficulties in describing the context in the title.
My situation is that having 3 tables
T1
A|B
1|xyz
2|www
3|abc
4|ppp
5|iuy
T2
A|C
1|1
1|2
2|3
2|4
3|5
4|6
5|7
5|8
T3
C| D |E
1|dfg|NULL
2|jhg|1
3|bnm|NULL
4|lpo|NULL
5|tyu|NULL
6|qrt|2
7|bet|3
8|dsf|4
The objective of the query is to show B with its corresponding D under the condition of t2.A should have at least 1 corresponding C value to be not NULL in its E value
I am having difficulties in showing a C with null when actually it should be included when the condition of A is matched in the whole picture by consisting another non-null C that makes A a legit result.
With the mentioned conditions, desired A should be 1, 4, 5, and would like to show its corresponding B with ALL the D of the desired A from the relationship with C in t2.
A2 and A3 are undesired as their corresponding E of C are all null and what I want to have is that at least 1 of the E contains a value.
The wanted output should be
B | D
xyz|dfg
xyz|jhg
ppp|qrt
iuy|bet
iuy|dsf
I hope someone would understand.
I find the question a little hard to follow, but if I understand correctly, you want some sort of exists clause:
select t2.b, t3.d
from t1 join
t2
on t1.a = t2.a join
t3
on t3.c = t2.c
where exists (select 1
from t2 tt2 join
t3 tt3
on tt2.c = tt3.c
where t2.a = t1.a and t3.e is not null
);
Can you try this query please:
select T1.B, T3.D from T1 inner join T2 on
T1.A =T2.A
inner join T3 on T2.C = T3.C
This query is according to your output shown above.
But if you would E be not NULL
you have to add to the query :
and T3.E is not NULL
Hope this can help ypu.
SELECT B, D
FROM t2
JOIN t1 ON t1.A = t2.A
JOIN t3 ON t3.C = t2.C
WHERE t2.A IN(SELECT A
FROM t2 JOIN t3 ON t3.C = t2.C
GROUP BY A
HAVING COUNT(E) >= 1)
or using this as an alternative for COUNT(E) >=1 or COUNT(E) >0
SUM(CASE WHEN registration_number IS NOT NULL THEN 1 ELSE 0 END) > 0)
This somehow worked for me
However, could anyone explain whether COUNT(E) >=1 or COUNT(E) >0 is better for expression and which way (count vs sum boolean) would be more efficient?
SELECT
count(t1.id) AS c1
FROM
table2
LEFT JOIN table1 AS t1 ON (t1.uid = table2.uid)
WHERE
table2.mode = 'ls'
GROUP BY
t1.id
c1 = 6 -> CORRECT!
SELECT
count(t2.id) AS c2
FROM
table2
LEFT JOIN table1 AS t2 ON (t2.pid = table2.id)
WHERE
table2.mode = 'ls'
GROUP BY
t1.id
c2 = 1 -> CORRECT!
SELECT
count(t1.id) AS c1,
count(t2.id) AS c2
FROM
table2
LEFT JOIN table1 AS t1 ON (t1.uid = table2.uid)
LEFT JOIN table1 AS t2 ON (t2.pid = table2.id)
WHERE
table2.mode = 'ls'
GROUP BY
t1.id
c1 = 6 -> CORRECT!
c2 = 6 -> WRONG!
How do I request both counts in one query, without getting wrong results?
I need to count two different requests at the same table (table1).
so, I'm using an alias for both request. (t1). Each alias-request is working fine alone. If I use both in the same query, i got wrong results.
count() will get you the number of records that are returned by your query. Since if you removed the counts and replaced it with * you would have 6 rows both of those counts are giving you 6.
Is there any reason why you cant use two sub selects and return the result of each of those?
So:
SELECT subQ1.c1, subQ2.c2 FROM
(SELECT count(t1.id) AS c1 FROM table2
LEFT JOIN table1 AS t1 ON (t1.uid = table2.uid)
WHERE table2.mode = 'ls') as subQ1,
(SELECT count(t2.id) AS c2 FROM table2
LEFT JOIN table1 AS t2 ON (t2.pid = table2.id)
WHERE table2.mode = 'ls') as SubQ2;
I believe your problem on the full query is your group by function. You are grouping by t.id, thus a1.id will have a different count based on how many rows you have.
What I mean by this is if there are 6 rows in table t, then count is going to return 6 for table t; but also since there looks to be a 1 to 1 relation on table a, there are 6 matching rows in table a to the 6 matching rows in table t. such that
t.id = a.id
1 = 1
2= 2 ...etc.
Thus your count is returning rows versus the count you believe you should have? I believe sum function is what you want to use here.
You could try this...but I'm not really sure what you're trying to do.
SELECT (...)
count(CASE WHEN t1.uid = t3.uid THEN t1.id ELSE NULL END) AS CBanz,
count(CASE WHEN ta1.pid = t3.id THEN a1.id ELSE NULL END) AS CBanz1
FROM
t0
LEFT JOIN (...)
LEFT JOIN t1 ON (t1.uid = t3.uid)
LEFT JOIN t1 AS a1 ON (a1.pid = t3.id)
WHERE (...)
Suppose that I have a table called "tblTemp" with the following data
ID Name
1 A
2 B
3 C
4 A
4 B
5 A
5 B
5 C
6 C
6 B
I want to get ID from name of A&B only not A&B&C like below:
4 A
or
4 B
How can I do like this in sql?
I try the following sql but it return row 5 as well:
SELECT tblTemp.ID, tblTemp.Name
FROM tblTemp INNER JOIN
tblTemp AS tbltemp_1 ON tblTemp.ID = tbltemp_1.ID
WHERE (tblTemp.Name = 'A') AND (tbltemp_1.Name = 'B')
One of the ways to compare sets is to take the count of group, filter groups by search set, and see if number of matches per group equals original number of group members:
select tblTemp.ID
from tblTemp
inner join
(
select ID,
count(*) GroupCount
from tblTemp
group by ID
having count(*) = 2
) g
on tblTemp.ID = g.ID
where tblTemp.Name in ('A', 'B')
group by tblTemp.Id, g.GroupCount
having count (*) = g.GroupCount
This should work on both MySql and Sql Server.
You can play with this code # Sql Fiddle.
try:
SELECT distinct ID
FROM tblTemp a
LEFT JOIN tblTemp b
ON a.ID = b.ID AND
b.name = 'C'
WHERE b.ID IS NULL;
select id from table
group by id
having min(Name)='A' and max(Nmae)='B'
SELECT ID, Name FROM tblTemp WHERE (Name = 'A' OR Name = 'B') and ID not in(SELECT ID FROM tblTemp WHERE Name = 'C')
Do you just want a list of distinct IDs that have A or B but not C?
SELECT distinct ID
FROM tblTemp
WHERE Name = 'A' or Name = 'B'
EXCEPT
SELECT distinct ID
FROM tblTemp
WHERE Name = 'C'
My above solution work for 'A' and/or 'B', but I notice you actually want 'A' and 'B' with no or. In that case:
SELECT distinct ID
FROM tblTemp as T1
INNER JOIN tblTemp as T2
ON T1.ID = T2.ID
WHERE T1.Name = 'A' and T2.Name = 'B'
EXCEPT
SELECT distinct ID
FROM tblTemp
WHERE Name = 'C'
this is an extension of your original code and is perhaps not as elegant as #Madhivanan's solution but it is more general should A B and C change to words for example.