开发者

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;
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜