SELECT * FROM Table WHERE colA and colB has at least 3 identical
I have to combine these two mySQL queries into one. I duplicated a solution and used it on a join table. I am querying a join table that has two columns (labeled "to_" and "from_"). Both 'to_' and 'from_' hold an id number for the same table. I need to combine these queries in such a way that I get results based on: [('from_' + 'to_') > 3], where 'from_' and 'to_' have the same value (i.e., they ref开发者_开发知识库er to the same id).
$query = "select * from nodes where nodeID in (
select to_ from joinTable group by to_ having count(*) > 3
)";
...
$query = "select * from nodes where nodeID in (
select from_ from joinTable group by from_ having count(*) > 3
)";
Acknowledgement: I'm using a query based very closely on a solution 'Mr E' helped me with earlier.
You can try (see important notice at the last paragraph regarding to_ and from_ matching requirements):
SELECT X.to_, COUNT(*)
FROM joinTable X, joinTable Y
WHERE
X.to_ = Y.from_
GROUP BY X.to_
HAVING COUNT(*) > 2
Or
SELECT X.to_, COUNT(*)
FROM joinTable X LEFT JOIN joinTable Y ON X.to_ = Y.from_
GROUP BY X.to_
HAVING COUNT(*) > 2
Using Mr E's test data:
CREATE TABLE `foo` (
`id` int(1) DEFAULT NULL,
`to_` varchar(5) DEFAULT NULL,
`from_` varchar(5) DEFAULT NULL
);
INSERT INTO `foo` VALUES (1,'A','B'),(2,'B','A'),(3,'B','C'),(4,'X','C'),(4,'X','B');
It will work, half-way, by issuing:
SELECT X.to_, Y.from_
FROM foo X LEFT JOIN foo Y ON X.to_ = Y.from_
which will then yield:
mysql> SELECT X.to_, Y.from_ /*--, COUNT(*) */
-> FROM foo X LEFT JOIN foo Y ON X.to_ = Y.from_;
+------+-------+
| to_ | from_ |
+------+-------+
| A | A |
| B | B |
| B | B |
| B | B |
| B | B |
| X | NULL |
| X | NULL |
+------+-------+
7 rows in set (0.00 sec)
and by running in full:
mysql> SELECT X.to_, COUNT(*)
-> FROM foo X LEFT JOIN foo Y ON X.to_ = Y.from_
-> GROUP BY X.to_
-> HAVING COUNT(*) > 2;
+------+----------+
| to_ | COUNT(*) |
+------+----------+
| B | 4 |
+------+----------+
Basically, join the table with itself and then generate an N:N list of matching records from both tables where to_ and from_ match (whether or not on the same row), then work with a single column and aggregate its values for the final COUNT(*).
And, most importantly, why have I lowered the number on the HAVING COUNT(*) from 3 to 2? The N:N relationship will issue N1 * N2 records (where N1 is the count of matching records on the first table and N2 on the second). So if the lower bound is three, we can only have over 3 records on these two tables by having one record in one of them and then 3 on the other (in whatever order) or 2 in one and 2 on the other (and then up from there) - otherwise there will be no matches on the to_ and from_ fields and this is something I am not sure about - whether the OP wants only records whose values appear on both fields or if having a COUNT(*) from a single side would suffice. If the latter is the case, however, I don't see any other option apart from separating the queries to deal with each column individually, as some people already have posted since that's an isolated sum we're dealing with. This will be slow if running against large tables.
SELECT * FROM(
SELECT nodeID, to_, count(*) cto_ FROM joinTable jta GROUP BY to_
OUTER JOIN
SELECT from_, count(*) cfrom_ FROM joinTable jtb GROUP BY from_
ON jta.nodeID = jtb.nodeID
) WHERE ((cto_ + cfrom) > 3) as tableA
INNER JOIN
node
ON node.nodeID = tableA.nodeID
I haven't tested to make sure this code compiles and runs but I think that's generally the right direction for the answer to what you want--
first get the count of to's from the to table
then get the count of from's from the from table
finally put the addition in the criteria for the two tables.
As long as the outer join is on same nodeID's it should only have one entry per nodeID, if I understand my code right.
OK, I ran it through a database I had handy, here's actual code that works on my database (change the names for yours of course)
SELECT * FROM (
SELECT * FROM
(
SELECT ticket_id, author_uid, count(*) cto_
FROM strato_ticket GROUP BY author_uid
) as jta
LEFT JOIN
(
SELECT ticket_id as tid, uid, count(*) cfrom_
FROM strato_ticket GROUP BY uid
) as jtb
ON jta.ticket_id = jtb.tid
WHERE ((cto_ + cfrom_) > 3)
) as jt
INNER JOIN strato_invite
ON strato_invite.ticket_id = jt.tid
It's not pretty, but:
select * from nodes where nodeID in (
select x from (
select to_ as x, count(*) as num
from joinTable group by to_
union all
select from_ as x, count(*) as num
from joinTable group by from_
) as temp_table
group by x having sum(num) > 3;
)
Doesn't seem to work for the OP. All I can say is "works on my machine" - here's the data and exact query I used:
CREATE TABLE `foo` (
`id` int(1) DEFAULT NULL,
`to_` varchar(5) DEFAULT NULL,
`from_` varchar(5) DEFAULT NULL
);
INSERT INTO `foo` VALUES (1,'A','B'),(2,'B','A'),(3,'B','C'),(4,'X','C'),(4,'X','B');
The query:
select x from (
select to_ as x, count(*) as num
from foo group by to_
union all
select from_ as x, count(*) as num
from foo group by from_
) as temp_table
group by x having sum(num) > 3;
精彩评论