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