MySQL选择连接表

时间:2017-03-28 11:31:56

标签: mysql sql group-by inner-join having

我们说我有两张桌子,比如:

+-----------------------------+
|a                            |
+------+-----------+----------+
| a_id | firstname | lastname |
+------+-----------+----------+
|    1 | Tom       | Cruise   |
|    3 | Matt      | Damon    |
|    4 | Ben       | Affleck  |
|    8 | Ryan      | Gosling  |
+------+-----------+----------+

+-----------------------+
| b                     |
+------+------+---------+
| b_id | a_id | b_value |
+------+------+---------+
|    2 |    3 | one     |
|    1 |    3 | two     |
|    4 |    8 | three   |
|    8 |    1 | four    |
+------+------+---------+

我希望能够SELECT a行满足b中可能有多行的b_value标准。{/ p>

例如:

  • 获取b_value个{和} b_value的任何人的名字和姓氏。在示例数据中,这仅指Matt Damon。

  • 获取b_value为三个,或b_value为四的任何人的名字和姓氏。在示例数据中,Ryan Gosling有三个b_value,而Tom Cruise有四个b_value,所以Ryan Gosling和Tom Cruise都会被退回。

  • 获取具有以下任何一个的人的名字和姓氏:

    • b_value一个b_value两个。{/ li>
    • 三个HAVING

在示例数据中,Matt Damon遇到了第一个条件,而Ryan Gosling遇到了第二个条件,因此两者都返回了。

困难来自于这些条件复杂,多个和/或条件组合以及长度变量。

我目前的尝试(在这种情况下具体解决了示例3),正在使用SELECT firstname, lastname FROM temp_a INNER JOIN temp_b ON temp_a.a_id = temp_b.a_id GROUP BY temp_a.a_id HAVING (SUM(b_value="one") AND SUM(b_value="two")) OR SUM(b_value="three"); 中的聚合函数:

SUM

哪一行得到了正确的行,但这种方法对我来说存在两个直接问题:

  • SUM似乎错了,很复杂。我必须找到每个条件,并确保每个条件包裹在b_value中,其中可能有很多条件。
  • b已编入索引,HAVING有很多行。 $("#addfield").click(function(){ alert($(this).data('id')+1); $(this).data('id', + $('#addfield').data('id')+1); console.log($(this).data('id')); })子句不使用索引,因此查询速度非常慢。

我是否应采取不同的方法来进行此类查询,同时牢记我并非真正直接控制用于过滤的条件。

3 个答案:

答案 0 :(得分:0)

drop table if exists a,b;
create table a( a_id int, firstname varchar(20), lastname varchar(20));
insert into a values
(    1 , 'Tom'       , 'Cruise' ),  
(    3 , 'Matt'      , 'Damon'  ),  
(    3 , 'Ben'       , 'Affleck'),  
(    8 , 'Ryan'      , 'Gosling');  

create table b( b_id int, a_id int, b_value varchar(20));
insert into b values
(    2 ,    3 , 'one'  ),   
(    1 ,    3 , 'two'  ),   
(    4 ,    8 , 'three'),   
(    8 ,    1 , 'four' );


select firstname, lastname,s.vals
from a
join
(
select b.a_id, group_concat(b_value) vals from b group by b.a_id
) s on a.a_id = s.a_id

where s.vals in ('one,two') or s.vals in ('three')

+-----------+----------+---------+
| firstname | lastname | vals    |
+-----------+----------+---------+
| Matt      | Damon    | one,two |
| Ben       | Affleck  | one,two |
| Ryan      | Gosling  | three   |
+-----------+----------+---------+
3 rows in set (0.02 sec)

答案 1 :(得分:0)

SELECT rows from a where it has b_value of both one and two would return Matt Damon.

如果你想要上面的结果那么表" a" " ID"列应该有唯一的记录, 表a和b都应该有主键。

或者您可以尝试以下查询,但它会返回" matt守护程序"

的双重记录
select firstname,lastname from a left join b on a.a_id=b.a_id ;

答案 2 :(得分:0)

在动态SQL中,它会像这样,首先我建议在应用程序中创建一个变量,根据过滤器的选择填充

 - var exampleOne = "(b_value = 'one') OR (b_value = 'two')";
 - var exampleTwo = "(b_value = 'three') OR (b_value = 'four')";
 - var exampleThree = "(b_value = 'one' or b_value = 'two') OR (b_value = 'three')"

然后,您可以使用一个参数创建存储过程,在此处传递变量

CREATE PROCEDURE `spNames`(IN whereFilter VARCHAR(255))
BEGIN
  SET @SqlText = CONCAT('SELECT DISTINCT a.firstname, a.lastname 
                         FROM @a AS a INNER JOIN @b AS b ON a.a_id=b.a_id
                         WHERE ', whereFilter);
  PREPARE stmt FROM @SqlText;
  EXECUTE stmt;
  DEALLOCATE PREPARE stmt
END

然后,您可以从代码中调用此存储过程并传入变量

CALL spNames (exampleOne);