【連接查詢】mySql多表連接查詢與union與union all用法


1.准備兩個表

表a:

  結構:

mysql> desc a;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| name  | varchar(40) | NO   | PRI | NULL    |       |
| age   | int(11)     | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+

 

  數據

 

 

 

 

表b:

  結構

mysql> desc b;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| nameB | varchar(40) | YES  |     | NULL    |       |
| ageB  | int(11)     | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+

  數據:

 

 

 

 

 

 

2.進行連接查詢測試:

(1)交叉連接(笛卡爾積)  cross join

mysql> select * from a,b;  #第一種 +------+------+-------+------+
| name | age  | nameB | ageB |
+------+------+-------+------+
| A1   |    1 | B1    |    1 |
| A2   |    2 | B1    |    1 |
| A1   |    1 | B2    |   22 |
| A2   |    2 | B2    |   22 |
+------+------+-------+------+
4 rows in set (0.00 sec)

mysql> select * from a cross join b;  #第二種 +------+------+-------+------+
| name | age  | nameB | ageB |
+------+------+-------+------+
| A1   |    1 | B1    |    1 |
| A2   |    2 | B1    |    1 |
| A1   |    1 | B2    |   22 |
| A2   |    2 | B2    |   22 |
+------+------+-------+------+
4 rows in set (0.00 sec)

mysql> select a.*,b.* from a cross join b;  #第二種的又一個寫法 +------+------+-------+------+
| name | age  | nameB | ageB |
+------+------+-------+------+
| A1   |    1 | B1    |    1 |
| A2   |    2 | B1    |    1 |
| A1   |    1 | B2    |   22 |
| A2   |    2 | B2    |   22 |
+------+------+-------+------+
4 rows in set (0.00 sec)

 

 

 

 

 (2)內連接    join 或 inner join(在笛卡爾積的基礎上過濾)

 

  • 顯示內連接

(1)不帶條件的內連接

mysql> select a.*,b.* from a inner join b on a.age=b.ageb;  #第一種 inner join
+------+------+-------+------+ | name | age | nameB | ageB | +------+------+-------+------+ | A1 | 1 | B1 | 1 | +------+------+-------+------+ 1 row in set (0.00 sec)

 

 

mysql> select a.*,b.* from a join b on a.age=b.ageb;  #第二種 join (默認是inner join) +------+------+-------+------+
| name | age  | nameB | ageB |
+------+------+-------+------+
| A1   |    1 | B1    |    1 |
+------+------+-------+------+
1 row in set (0.00 sec)

 

 

三個表的顯示內連接:

SELECT
  a.*,
  b.*,
  c.*
FROM exampaper a
  INNER JOIN bigquestion b
  INNER JOIN exampaperquestion c
    ON a.paperId = b.paperId
      AND b.bigQuertionId = c.bigQuertionId

 

四個表的顯示內連接:

SELECT
    train.trainingSchemaName,
    train.majorName,
    train.createTime,
    tc.*, course.*, type.*
FROM
    trainschemeinfo train
JOIN train_course tc ON train.trainingSchemeID = tc.trainningSchemeID
INNER JOIN t_course_base_info course ON tc.courseID = course.courseId
INNER JOIN coursetypeinfo type ON tc.typeNum = type.typeNum
WHERE
    tc.trainningSchemeID = '661ecb064b164d1ea133956f89beddb7'

 

與之等價的隱士內連接:

SELECT
    train.trainingSchemaName,
    train.majorName,
    train.createTime,
    tc.*, course.*, type.*
FROM
    trainschemeinfo train,
    train_course tc,
    t_course_base_info course,
    coursetypeinfo type
WHERE
    train.trainingSchemeID = tc.trainningSchemeID
AND tc.courseID = course.courseId
AND tc.typeNum = type.typeNum
AND tc.trainningSchemeID = '661ecb064b164d1ea133956f89beddb7'

 

 

 

 

 

 (2)顯示內連接帶條件

mysql> select a.*,b.* from a join b on a.age=b.ageb having a.name='A1';  #having從查出的數據中挑選滿足條件的元祖 +------+------+-------+------+
| name | age  | nameB | ageB |
+------+------+-------+------+
| A1   |    1 | B1    |    1 |
+------+------+-------+------+
1 row in set (0.00 sec)
  
mysql> select a.*,b.* from a join b on a.age=b.ageb where a.name='A1';  #where查詢滿足條件的元素 +------+------+-------+------+
| name | age  | nameB | ageB |
+------+------+-------+------+
| A1   |    1 | B1    |    1 |
+------+------+-------+------+
1 row in set (0.00 sec)

 

 

 

 

  • 隱士內連接:
mysql> select * from a,b where a.age=b.ageb;  
+------+------+-------+------+
| name | age  | nameB | ageB |
+------+------+-------+------+
| A1   |    1 | B1    |    1 |
+------+------+-------+------+
1 row in set (0.00 sec)

mysql> select * from a,b where a.age=b.ageb and a.name='A1';
+------+------+-------+------+
| name | age  | nameB | ageB |
+------+------+-------+------+
| A1   |    1 | B1    |    1 |
+------+------+-------+------+
1 row in set (0.00 sec)

mysql> select * from a,b where a.age=b.ageb having a.name='A1';
+------+------+-------+------+
| name | age  | nameB | ageB |
+------+------+-------+------+
| A1   |    1 | B1    |    1 |
+------+------+-------+------+
1 row in set (0.00 sec)

 

  where是從本地磁盤查詢滿足條件的元素,having是從查出的數據中挑選滿足條件的元素。執行權限   where>sum()..聚合函數>having

  

 

 

 (3)左外連接:(拿左邊的匹配右邊的,沒有找到右邊的為null)

mysql> select * from a left join b on a.age = b.ageb;  #第一種 left join +------+------+-------+------+
| name | age  | nameB | ageB |
+------+------+-------+------+
| A1   |    1 | B1    |    1 |
| A2   |    2 | NULL  | NULL |
+------+------+-------+------+
2 rows in set (0.00 sec)

mysql> select * from a left outer join b on a.age = b.ageb;  #第二種 left outer join +------+------+-------+------+
| name | age  | nameB | ageB |
+------+------+-------+------+
| A1   |    1 | B1    |    1 |
| A2   |    2 | NULL  | NULL |
+------+------+-------+------+
2 rows in set (0.00 sec)

 

 

 

(4)右外連接:(拿右邊的匹配左邊的,沒有找到左邊的為null)

mysql> select * from a right join b on a.age = b.ageb;  #第一種 right join +------+------+-------+------+
| name | age  | nameB | ageB |
+------+------+-------+------+
| A1   |    1 | B1    |    1 |
| NULL | NULL | B2    |   22 |
+------+------+-------+------+
2 rows in set (0.00 sec)

mysql> select * from a right outer join b on a.age = b.ageb;  #第二種 right outer join +------+------+-------+------+
| name | age  | nameB | ageB |
+------+------+-------+------+
| A1   |    1 | B1    |    1 |
| NULL | NULL | B2    |   22 |
+------+------+-------+------+
2 rows in set (0.00 sec)

 

 

3.Union 和 union all  取兩個表的並集測試

修改b表,加一條和a表重復的數據

b表數據:

 

 

a表數據:

 

 

 

(1)   union:   自動去掉重復元素

mysql> select * from a union select * from b;
+------+------+
| name | age  |
+------+------+
| A1   |    1 |
| A2   |    2 |
| B1   |    1 |
| B2   |   22 |
+------+------+
4 rows in set (0.00 sec)

 

 

 總結:

union:聯合的意思,即把兩次或多次查詢結果合並起來。
要求:兩次查詢的列數必須一致
推薦:列的類型可以不一樣,但推薦查詢的每一列,想對應的類型以一樣
可以來自多張表的數據:多次sql語句取出的列名可以不一致,此時以第一個sql語句的列名為准。
如果不同的語句中取出的行,有完全相同(這里表示的是每個列的值都相同),那么union會將相同的行合並,最終只保留一行。也可以這樣理解,union會去掉重復的行。
如果不想去掉重復的行,可以使用union all。
如果子句中有order by,limit,需用括號()包起來。推薦放到所有子句之后,即對最終合並的結果來排序或篩選,可以對union之后的數據進行排序和分頁等操作。

 

例如:采用union合並的多個表的數據的SQL

  需求是:為了顯示學院、專業、班級樹,但是這些信息不在一個月表,而且班級表中有專業編號,專業表中有學院編號。思路就是:分別從三個表中獲取數據,然后采用union進行合並數據。

SELECT
  classID   AS departNum,
  className AS departName,
  "class" AS departType,
  (SELECT
     majorID
   FROM t_major_base_info
   WHERE majorID = class.majorID) AS updepartNum
FROM t_class_base_info class
UNION 
SELECT majorID AS departNum,
    majorName AS departName,
    "major" AS departType,
      (SELECT
        collegeID   FROM t_college_base_info
   WHERE collegeID=major.collegeID) AS updepartNum
 FROM t_major_base_info major
UNION
SELECT collegeId AS departNum,
    collegeName AS departName,
    "college" AS departType,
    "000" AS updepartNum
    FROM t_college_base_info

 

 

 

(2)    union all  保留重復元素

   UNION ALL 命令和 UNION 命令幾乎是等效的,不過 UNION ALL 命令會列出所有的值。

mysql> select * from a union all select * from b;
+------+------+
| name | age  |
+------+------+
| A1   |    1 |
| A2   |    2 |
| B1   |    1 |
| B2   |   22 |
| A1   |    1 |
+------+------+
5 rows in set (0.00 sec)

 

  

 

 

 

總結:

  UNION 用於合並兩個或多個 SELECT 語句的結果集,並消去表中任何重復行。
  UNION 內部的 SELECT 語句必須擁有相同數量的列,列也必須擁有相似的數據類型。
  同時,每條 SELECT 語句中的列的順序必須相同.

  默認地,UNION 操作符選取不同的值。如果允許重復的值,請使用 UNION ALL。
  當 ALL 隨 UNION 一起使用時(即 UNION ALL),不消除重復行

 注意:

1、UNION 結果集中的列名總是等於第一個 SELECT 語句中的列名
2、UNION 內部的 SELECT 語句必須擁有相同數量的列。列也必須擁有相似的數據類型。同時,每條 SELECT 語句中的列的順序必須相同

 

補充:今天在項目種用到了從多個表種查詢數據把並且分頁,實現過程是將所有表的名字傳到dao,然后遍歷表名字,一起添加條件(前提是需要查詢的列名字相同):

 

    public List<Map<String, Object>> getAllData(List<String> tableNames) {
        List<String> sqls = new ArrayList();
        StringBuilder sb = null;
        for (String tableName : tableNames) {
            sb = new StringBuilder();
            sb.append("select id,name from ");
            sb.append(tableName);
            sb.append(" where 1=1");
            sb.append(" and name = 'zhangsan'");
            sqls.add(sb.toString());
        }

        String sqlFinally = StringUtils.join(sqls, " union ");
        sqlFinally += "order by name limit 5,5";
        System.out.println(sqlFinally);

        /*Session session = getSessionFactory().openSession();
        SQLQuery sqlQuery = session.createSQLQuery(sqlFinally);
        sqlQuery.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
        return sqlQuery.list();*/
        return null;

    }

 

 

 

 

測試:

    public static void main(String[] args) {
        GroupDaoImpl g = new GroupDaoImpl(); List tableNames = new ArrayList(); tableNames.add("t1"); tableNames.add("t2"); tableNames.add("t3"); g.getAllData(tableNames); }

 

結果:

select id,name from t1 where 1=1 and name = 'zhangsan' union select id,name from t2 where 1=1 and name = 'zhangsan' union select id,name from t3 where 1=1 and name = 'zhangsan' order by name limit 5,5

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM