支援連表等複雜查詢的PageHelper修改
新版本的PageHelper與mybatis請移步這裡——支援PageHelper5.1.4 Mybatis3.4.6
先說說使用PageHelper踩過的坑:
- 在mapper對映檔案中,如果使用了limit關鍵字,而又使用了PageHelper的功能,比如orderBy,那麼就會報錯。
- 在使用稍微複雜的查詢時,PageHelper是針對最外層(最下方)的資料進行分頁的。
出現這樣的問題,歸根結底還是PageHelper原始碼的問題。
這套修改的原理即是修改pagehelper “limit”的位置,從末尾改到我們想要的位置。
不多說PageHelper本身,本文使用的PageHelper版本為
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>4.2.1</version>
</dependency>
這裡以MySql為例,使得PageHelper支援複雜查詢的分頁。
一、新增CustomDialect,自定義方言
先看看原版的方言類的定義
package com.github.pagehelper.dialect;
@Override
public String getPageSql(String sql, Page page, RowBounds rowBounds, CacheKey pageKey) {
StringBuilder sqlBuilder = new StringBuilder(sql.length() + 14);
sqlBuilder.append(sql);
sqlBuilder.append(" limit ?,?");
return sqlBuilder.toString();
}
從這裡可以看出,PageHelper在針對MySql資料庫進行分頁時,是在sql語句的最後加上limit偏移量進行分頁查詢的。且不說這種查詢在資料量大時效率可能不高,這樣去操作的話,在稍微複雜的查詢中,通常無法正常的進行分頁。
/**
* Created by Anur IjuoKaruKas on 2017/9/28.
* Description :
*/
public class CustomDialect extends MySqlDialect {
public CustomDialect(SqlUtil sqlUtil) {
super(sqlUtil);
}
@Override
public Object processPageParameter(MappedStatement ms, Map<String, Object> paramMap, Page page, BoundSql boundSql, CacheKey pageKey) {
return super.processPageParameter(ms, paramMap, page, boundSql, pageKey);
}
@Override
public String getPageSql(String sql, Page page, RowBounds rowBounds, CacheKey pageKey) {
StringBuilder sqlBuilder = new StringBuilder(sql.length() + 14);
if (sql.indexOf(ProjectConstant.SQL_SIGN) != -1) {
StringBuffer stringBuffer = new StringBuffer(sql);
stringBuffer.indexOf(ProjectConstant.SQL_SIGN);
StringBuffer mae = new StringBuffer(stringBuffer.substring(0, stringBuffer.indexOf(ProjectConstant.SQL_SIGN)));
StringBuffer uShiRo = new StringBuffer(stringBuffer.substring(stringBuffer.indexOf(ProjectConstant.SQL_SIGN), sql.length()));
mae.insert(mae.lastIndexOf(")")," limit ?,?");
return mae.append(uShiRo).toString();
}
sqlBuilder.append(sql);
sqlBuilder.append(" limit ?,?");
return sqlBuilder.toString();
}
}
所以,在這裡,我對它進行了一點點的改寫。
新建一個CustomDialect繼承MySqlDialect,並重寫了原方法。
在這裡,做了一個判斷,如果sql語句中包含 * ProjectConstant.SQL_SIGN(limitable) ,那麼在這前面加上 “limit ?,?”*
這個SQL_SIGN是什麼呢?
public static final String SQL_SIGN = "AS limitable";
實際上就是一個用於標記哪裡需要使用偏移量的一個標識。
在mapper對映檔案中就可以這樣寫:
<select id="selectRecordByComplexCondition" resultMap="ListQueryMap" parameterMap="ListQueryPo">
SELECT
*
from
(
SELECT
*
FROM
record r
WHERE
r.record_release_state = 1
<if test="tagIdListToSqlString!=null">
AND r.record_id IN (
SELECT
object_id
FROM
record_tag rtag
WHERE
rtag.tag_id IN ${tagIdListToSqlString}
AND rtag.module = #{moduleEnumIndex}
GROUP BY
rtag.object_id
HAVING
count(*) >= #{tagCount}
)
</if>
AND r.module = #{moduleEnumIndex}
<if test="rcId!=null">
AND r.rc_id = #{rcId}
</if>
<if test="raId!=null">
AND r.ra_id = #{raId}
</if>
<if test="recordTitle!=null">
AND r.record_title LIKE CONCAT(CONCAT('%', #{recordTitle}), '%')
</if>
<if test="recordReleaseTimeFrom!=null">
AND r.record_release_time > #{recordReleaseTimeFrom}
</if>
/* 現在的PageHelper limit 加在這裡 */
) AS limitable
LEFT JOIN record_tag rt ON rt.module = #{moduleEnumIndex}
AND limitable.record_id = rt.object_id
LEFT JOIN tag t ON rt.tag_id = t.tag_id
/* 原來的PageHelper limit 加在這裡 */
</select>
在這個業務中,我們想要進行分頁的表是record,但如果不改mybatis,那麼PageHelper將會對聯表查詢後的資料進行分頁,那並不是我們想要的。
二、複寫CustomPageHelper和CustomSqlUtil
/**
* Created by Stack on 2017/9/28.
* Description :
*/
@SuppressWarnings("rawtypes")
@Intercepts(@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}))
public class CustomPageHelper extends PageHelper {
private final CustomSqlUtil sqlUtil = new CustomSqlUtil();
@Override
public Object intercept(Invocation invocation) throws Throwable {
return sqlUtil.intercept(invocation);
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
sqlUtil.setProperties(properties);
}
}
/**
* Created by Anur IjuoKaruKas on 2017/9/28.
* Description : 自定義sql處理工具
*/
public class CustomSqlUtil extends SqlUtil {
private Dialect dialect;
private Field additionalParametersField;
private Properties properties;
protected boolean autoDialect = true; //自動獲取dialect,如果沒有setProperties或setSqlUtilConfig,也可以正常進行
protected boolean autoRuntimeDialect; //執行時自動獲取dialect
protected boolean closeConn = true; //多資料來源時,獲取jdbcurl後是否關閉資料來源
private Map<String, Dialect> urlDialectMap = new ConcurrentHashMap<String, Dialect>(); //快取
private ReentrantLock lock = new ReentrantLock();
/**
* 真正的攔截器方法
*
* @param invocation
* @return
* @throws Throwable
*/
@Override
public Object intercept(Invocation invocation) throws Throwable {
try {
return doIntercept(invocation);
} finally {
BaseSqlUtil.clearLocalPage();
}
}
/**
* 真正的攔截器方法
*
* @param invocation
* @return
* @throws Throwable
*/
@Override
public Object doIntercept(Invocation invocation) throws Throwable {
//獲取攔截方法的引數
Object[] args = invocation.getArgs();
MappedStatement ms = (MappedStatement) args[0];
Object parameterObject = args[1];
RowBounds rowBounds = (RowBounds) args[2];
List resultList;
if (autoDialect) {
lock.lock();
try {
if (autoDialect) {
autoDialect = false;
this.dialect = getDialect(ms);
}
} finally {
lock.unlock();
}
}
Dialect runtimeDialect = dialect;
if (autoRuntimeDialect) {
runtimeDialect = getDialect(ms);
}
//呼叫方法判斷是否需要進行分頁,如果不需要,直接返回結果
if (!runtimeDialect.skip(ms, parameterObject, rowBounds)) {
ResultHandler resultHandler = (ResultHandler) args[3];
//當前的目標物件
Executor executor = (Executor) invocation.getTarget();
BoundSql boundSql = ms.getBoundSql(parameterObject);
//反射獲取動態引數
Map<String, Object> additionalParameters = (Map<String, Object>) additionalParametersField.get(boundSql);
//判斷是否需要進行 count 查詢
if (runtimeDialect.beforeCount(ms, parameterObject, rowBounds)) {
//建立 count 查詢的快取 key
CacheKey countKey = executor.createCacheKey(ms, parameterObject, RowBounds.DEFAULT, boundSql);
countKey.update("_Count");
MappedStatement countMs = msCountMap.get(countKey);
if (countMs == null) {
//根據當前的 ms 建立一個返回值為 Long 型別的 ms
countMs = MSUtils.newCountMappedStatement(ms);
msCountMap.put(countKey, countMs);
}
//呼叫方言獲取 count sql
String countSql = runtimeDialect.getCountSql(ms, boundSql, parameterObject, rowBounds, countKey);
List<ParameterMapping> countTempParameterMappingList = new ArrayList<>();
//**************** 擷取有效部分進行count操作 by Anur 17/10/25
if (countSql.contains(BmsConstant.SQL_SIGN)) {
Integer subIndex = countSql.indexOf(BmsConstant.SQL_SIGN) + BmsConstant.SQL_SIGN.length();// 擷取位置 到AS limitable
countSql = countSql.substring(0, subIndex);// 進行擷取
Integer usefulParamCount = 0;// 引數捨棄
for (int i = 0; i < countSql.length(); i++) {
if (countSql.indexOf("?", i) != -1) {
usefulParamCount++;
i = countSql.indexOf("?", i);
}
}
List<ParameterMapping> allCountTempParameterMappingList = boundSql.getParameterMappings();
countTempParameterMappingList = new ArrayList<>();
for (Iterator<ParameterMapping> iterator = allCountTempParameterMappingList.iterator(); iterator.hasNext(); ) {
if (usefulParamCount == 0) {
break;
}
usefulParamCount--;
ParameterMapping next = iterator.next();
countTempParameterMappingList.add(next);
}
} else {
countTempParameterMappingList = boundSql.getParameterMappings();
}
BoundSql countBoundSql = new BoundSql(ms.getConfiguration(), countSql, countTempParameterMappingList, parameterObject);
//當使用動態 SQL 時,可能會產生臨時的引數,這些引數需要手動設定到新的 BoundSql 中
for (String key : additionalParameters.keySet()) {
countBoundSql.setAdditionalParameter(key, additionalParameters.get(key));
}
Object countResultList = executor.query(countMs, parameterObject, RowBounds.DEFAULT, resultHandler, countKey, countBoundSql);// 執行 count 查詢
Long count = (Long) ((List) countResultList).get(0);// 處理查詢總數
runtimeDialect.afterCount(count, parameterObject, rowBounds);
if (count == 0L) { // 當查詢總數為 0 時,直接返回空的結果
return runtimeDialect.afterPage(new ArrayList(), parameterObject, rowBounds);
}
}
List<ParameterMapping> pageTempParameterMappingList;
// 判斷是否需要進行分頁查詢
if (runtimeDialect.beforePage(ms, parameterObject, rowBounds)) {
CacheKey pageKey = executor.createCacheKey(ms, parameterObject, rowBounds, boundSql);// 生成分頁的快取 key
parameterObject = runtimeDialect.processParameterObject(ms, parameterObject, boundSql, pageKey);// 處理引數物件
String pageSql = runtimeDialect.getPageSql(ms, boundSql, parameterObject, rowBounds, pageKey);// 呼叫方言獲取分頁 sql
//**************** 引數排程 by Anur 17/10/25
if (pageSql.contains(BmsConstant.SQL_SIGN)) {
String sqlInCount = pageSql.substring(0, pageSql.indexOf(BmsConstant.SQL_SIGN));
Integer count = -2;
for (int i = 0; i < sqlInCount.length(); i++) {
if (sqlInCount.indexOf("?", i) != -1) {
i = sqlInCount.indexOf("?", i);
count++;
}
}
List<ParameterMapping> tempParameterMappingList = boundSql.getParameterMappings();
ParameterMapping parameterFirst = tempParameterMappingList.get(tempParameterMappingList.size() - 2);
ParameterMapping parameterSecond = tempParameterMappingList.get(tempParameterMappingList.size() - 1);
tempParameterMappingList.add(0 + count, parameterFirst);
tempParameterMappingList.add(1 + count, parameterSecond);
tempParameterMappingList.remove(tempParameterMappingList.size() - 2);
tempParameterMappingList.remove(tempParameterMappingList.size() - 1);
pageTempParameterMappingList = tempParameterMappingList;
} else {
pageTempParameterMappingList = boundSql.getParameterMappings();
}
//****************
BoundSql pageBoundSql = new BoundSql(ms.getConfiguration(), pageSql, pageTempParameterMappingList, parameterObject);
//設定動態引數
for (String key : additionalParameters.keySet()) {
pageBoundSql.setAdditionalParameter(key, additionalParameters.get(key));
}
//執行分頁查詢
resultList = executor.query(ms, parameterObject, RowBounds.DEFAULT, resultHandler, pageKey, pageBoundSql);
} else {
resultList = new ArrayList();
}
} else {
args[2] = RowBounds.DEFAULT;
resultList = (List) invocation.proceed();
}
//返回預設查詢
return runtimeDialect.afterPage(resultList, parameterObject, rowBounds);
}
/**
* 初始化 dialect
*
* @param dialectClass
* @param properties
*/
private Dialect initDialect(String dialectClass, Properties properties) {
Dialect dialect;
try {
dialect = new CustomDialect(this);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("初始化 dialect [" + dialectClass + "]時出錯:" + e.getMessage());
}
dialect.setProperties(properties);
return dialect;
}
/**
* 獲取url
*
* @param dataSource
* @return
*/
@Override
public String getUrl(DataSource dataSource) {
Connection conn = null;
try {
conn = dataSource.getConnection();
return conn.getMetaData().getURL();
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
if (conn != null) {
try {
if (closeConn) {
conn.close();
}
} catch (SQLException e) {
//ignore
}
}
}
}
/**
* 根據datasource建立對應的sqlUtil
*
* @param ms
*/
@Override
public Dialect getDialect(MappedStatement ms) {
//改為對dataSource做快取
DataSource dataSource = ms.getConfiguration().getEnvironment().getDataSource();
String url = getUrl(dataSource);
if (urlDialectMap.containsKey(url)) {
return urlDialectMap.get(url);
}
try {
lock.lock();
if (urlDialectMap.containsKey(url)) {
return urlDialectMap.get(url);
}
if (StringUtil.isEmpty(url)) {
throw new RuntimeException("無法自動獲取jdbcUrl,請在分頁外掛中配置dialect引數!");
}
String dialectStr = BaseSqlUtil.fromJdbcUrl(url);
if (dialectStr == null) {
throw new RuntimeException("無法自動獲取資料庫型別,請通過 dialect 引數指定!");
}
Dialect dialect = initDialect(dialectStr, properties);
urlDialectMap.put(url, dialect);
return dialect;
} finally {
lock.unlock();
}
}
@Override
public void setProperties(Properties properties) {
super.setProperties(properties);
//多資料來源時,獲取jdbcurl後是否關閉資料來源
String closeConn = properties.getProperty("closeConn");
//解決#97
if (StringUtil.isNotEmpty(closeConn)) {
this.closeConn = Boolean.parseBoolean(closeConn);
}
//資料庫方言
String dialect = properties.getProperty("dialect");
String runtimeDialect = properties.getProperty("autoRuntimeDialect");
if (StringUtil.isNotEmpty(runtimeDialect) && runtimeDialect.equalsIgnoreCase("TRUE")) {
this.autoRuntimeDialect = true;
this.autoDialect = false;
this.properties = properties;
} else if (StringUtil.isEmpty(dialect)) {
autoDialect = true;
this.properties = properties;
} else {
autoDialect = false;
this.dialect = initDialect(dialect, properties);
}
try {
//反射獲取 BoundSql 中的 additionalParameters 屬性
additionalParametersField = BoundSql.class.getDeclaredField("additionalParameters");
additionalParametersField.setAccessible(true);
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
}
}
}
// 引數排程
if (pageSql.indexOf(ProjectConstant.SQL_SIGN) != -1) {
String sqlInCount = pageSql.substring(0, pageSql.indexOf(ProjectConstant.SQL_SIGN));
Integer count = 0;
for (int i = 0; i < sqlInCount.length(); i++) {
if (sqlInCount.indexOf("?", i) != -1) {
i = sqlInCount.indexOf("?", i);
count++;
}
}
List<ParameterMapping> tempParameterMappingList = boundSql.getParameterMappings();
ParameterMapping parameterFirst = tempParameterMappingList.get(tempParameterMappingList.size() - 2);
ParameterMapping parameterSecond = tempParameterMappingList.get(tempParameterMappingList.size() - 1);
tempParameterMappingList.add(0 + count, parameterFirst);
tempParameterMappingList.add(1 + count, parameterSecond);
tempParameterMappingList.remove(tempParameterMappingList.size() - 2);
tempParameterMappingList.remove(tempParameterMappingList.size() - 1);
parameterMappingList = tempParameterMappingList;
} else {
parameterMappingList = boundSql.getParameterMappings();
}
基於PageHelper最大的改動是這裡,在填充引數時,它的原本順序是 ?,?,?,?,?,?,查詢的位置,偏移量
但由於我們在前面吧 limit ?,? 移到了前面,所以這裡也必須進行同步修改,實際上就是把這兩個引數,根據sql語句的不同,提到前面去。
其他的也有一點點改動,比如說方言不再自動獲取,直接使用我們上面自己定義的這個CustomDialect
三、配置
@Configuration
public class MybatisConfiguration {
@Bean
public SqlSessionFactory sqlSessionFactoryBean(DataSource dataSource) throws Exception {
SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
factory.setDataSource(dataSource);
factory.setTypeAliasesPackage(MODEL_PACKAGE);
// 配置分頁外掛,詳情請查閱官方文件
CustomPageHelper customPageHelper = new CustomPageHelper();
Properties properties = new Properties();
properties.setProperty("pageSizeZero", "true");//分頁尺寸為0時查詢所有紀錄不再執行分頁
properties.setProperty("reasonable", "true");//頁碼<=0 查詢第一頁,頁碼>=總頁數查詢最後一頁
properties.setProperty("supportMethodsArguments", "true");//支援通過 Mapper 介面引數來傳遞分頁引數
customPageHelper.setProperties(properties);
// 新增外掛
factory.setPlugins(new Interceptor[]{customPageHelper});
// 新增XML目錄
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
factory.setMapperLocations(resolver.getResources("classpath:mapper/*.xml"));
return factory.getObject();
}
直接沿用原來的配置就可以,只需對一個地方進行細微的修改,那就是在plugin這裡,需要將pageHelper更換成自己定義的這個CustomPageHelper
6 <configuration>
7 <plugins>
8 <plugin interceptor="com.xxxx.xxxxx.CustomPageHelper">
9 <!--指明資料庫 4.0.0以後不需要設定此屬性-->
10 <property name="dialect" value="mysql"/>
11 <!-- 該引數預設為false -->
12 <!-- 設定為true時,會將RowBounds第一個引數offset當成pageNum頁碼使用 -->
13 <!-- 和startPage中的pageNum效果一樣-->
14 <property name="offsetAsPageNum" value="true"/>
15 <!-- 該引數預設為false -->
16 <!-- 設定為true時,使用RowBounds分頁會進行count查詢 -->
17 <property name="rowBoundsWithCount" value="true"/>
18 <!-- 設定為true時,如果pageSize=0或者RowBounds.limit = 0就會查詢出全部的結果 -->
19 <!-- (相當於沒有執行分頁查詢,但是返回結果仍然是Page型別)-->
20 <property name="pageSizeZero" value="true"/>
21 <!-- 3.3.0版本可用 - 分頁引數合理化,預設false禁用 -->
22 <!-- 啟用合理化時,如果pageNum<1會查詢第一頁,如果pageNum>pages會查詢最後一頁 -->
23 <!-- 禁用合理化時,如果pageNum<1或pageNum>pages會返回空資料 -->
24 <property name="reasonable" value="true"/>
25 <!-- 3.5.0版本可用 - 為了支援startPage(Object params)方法 -->
26 <!-- 增加了一個`params`引數來配置引數對映,用於從Map或ServletRequest中取值 -->
27 <!-- 可以配置pageNum,pageSize,count,pageSizeZero,reasonable,orderBy,不配置對映的用預設值 -->
28 <!-- 不理解該含義的前提下,不要隨便複製該配置 -->
29 <property name="params" value="pageNum=start;pageSize=limit;"/>
30 <!-- 支援通過Mapper介面引數來傳遞分頁引數 -->
31 <property name="supportMethodsArguments" value="true"/>
32 <!-- always總是返回PageInfo型別,check檢查返回型別是否為PageInfo,none返回Page -->
33 <property name="returnPageInfo" value="check"/>
34 </plugin>
35 </plugins>
36 </configuration>
如果配置檔案是xml的,也是同樣進行修改,將interceptor改成你自己定義的這個。
四、使用
PageHelper.startPage(pageNum,pageSize);
和之前沒有任何區別,你只需要在需要sql語句中需要進行偏移的地,做如下修改
需要分頁的地方套上一層外衣 SELECT (xxxxxxxxxxxxx)AS limitable,就可以實現分頁了
大功告成~ 這樣的修改,在不會對正常的分頁產生影響~
五、總結
不多說~ 這樣可以根據自己的需求,隨意對PageHelper進行修改,或者自己寫一個低配版但是貼合需求的PageHelper。
這是一種比較拙劣的方法!如果有更好的方法,歡迎指點指點~~
相關推薦
支援連表等複雜查詢的PageHelper修改
新版本的PageHelper與mybatis請移步這裡——支援PageHelper5.1.4 Mybatis3.4.6 先說說使用PageHelper踩過的坑: - 在mapper對映檔案中,如果使用了limit關鍵字,而又使用了PageHelper的
支援連表等複雜查詢的PageHelper修改 —— 支援PageHelper5.1.4 Mybatis3.4.6
一、PageHelper中分頁存在的問題: - 主表結構如下: provider_order表,訂單主表。我們這裡簡化處理,它只有一個欄位,即id。 VARCHAR | po_id | 訂單表id - 從表結
(ORACLE)PL/SQL 表的複雜查詢
表的複雜查詢 在實際應用中,常常需要執行復雜的資料統計,經常需要顯示多張表的資料現在我們來學習比較複雜的select的語句。我們將繼續使用scott使用者下emp表作為示例。 聚合函式 MAX函式: 對一列取最大值 MIN函式: 對一列取最小值 AVG函式: 對一列取平均值 SU
MySQL:記錄的增刪改查、單表查詢、約束條件、多表查詢、連表、子查詢、pymysql模組、MySQL內建功能
資料操作 插入資料(記錄): 用insert; 補充:插入查詢結果: insert into 表名(欄位1,欄位2,...欄位n) select (欄位1,欄位2,...欄位n) where ...; 更新資料update 語法: update 表名 set 欄位1=
表的複雜查詢----多表查詢、兩表的條件連線、內連線(自連線)、左外連線、右外連線、子查詢、分頁查詢
基於兩個或兩個以上的表或檢視的查詢。例如:emp和dept是兩張表。(這兩張表的deptno是共同欄位) ①通過什麼條件把兩張表關聯(如果不使用條件關聯將產生行數乘積的合集---笛卡爾集)例子:emp表字段包含:每行有自己的名字和id以及自己的上級的id,同時自己的上級
MySQL複雜查詢 —— 跨表/多表查詢,如何解決MySQL不支援全連線的問題 —— 使用結果集的合併
SELECT sex, MAX(salary), MIN(salary), AVG(salary) FROM emp GROUP BY sex; 5.MySQL複雜查詢 —— 跨表/多表查詢 —— 瞭解 查詢結果集中的資料來自於多個不同的
不同服務器數據庫表連接查詢,修改
server dlink 數據庫 exe bsp 連接查詢 sql 對數 als 不同服務器數據庫表連接查詢,修改 exec sp_addlinkedserver ‘ERP‘,‘‘,‘SQLOLEDB‘,‘10.0.10.0‘ exec sp_addlinkedsrvl
介紹 複雜查詢,包括多表關聯,分頁,排序等
本篇進行Spring-data-jpa的介紹,幾乎涵蓋該框架的所有方面,在日常的開發當中,基本上能滿足所有需求。這裡不講解JPA和Spring-data-jpa單獨使用,所有的內容都是在和Spring整合的環境中實現。如果需要了解該框架的入門,百度一下,很多入門的介紹。在這篇文章的接下來一篇,會有一個
hive表信息查詢:查看表結構、表操作等--轉
cal ica class depend yun sel getting 結構 dconf 原文地址:http://www.aboutyun.com/forum.PHP?mod=viewthread&tid=8590&highlight=Hive 問題導讀
連表查詢(3)之根據相關條件,查詢另外一個表或多個表的某字段
兩個 mode object 添加 就會 resultmap control var 多個 1、送檢單位 代理商是從代理商表中取得數據 銷售人員從銷售表中取得數據 說一個簡單的思路: sql語句找到連接兩個表的條件,把另外一個表要用到的字段 寫一個 <re
Java鏈接HBASE數據庫,創建一個表,刪除一張表,修改表,輸出插入,修改,數據刪除,數據獲取,顯示表信息,過濾查詢,分頁查詢,地理hash
can charat nfa true 目錄結構 dfa byte sin extra 準備工作 1、創建Java的Maven項目 創建好的目錄結構如下: 另外註意junit的版本,最好不要太高,最開始筆者使用的junit4.12的,發現運行的時候會報錯。最後把Junit
連表查詢的簡單方法!!
etl point return rim plist turn public 方法 nbsp 在主表(Appointment)裏面private+副表的對象 private Department(副表) depa; private User(副表) u; 然後source
安裝vsphere client時出現“錯誤2229 無法在SQL查詢中加載表”等錯誤
錯誤2229解決辦法:請按照以下步驟繼續進行升級:找到日誌文件 %TEMP%vim-sso-msi.log搜索上次安裝期間作為緩存文件的 *.mst 文件。例如: c:\Windows \Installer\xxxxx.mst找到該 *.mst 文件並將其刪除。重新安裝vsphere client即可本文出自
Linq to SQL 的連表查詢(轉)
equal query 交集 數據庫 調用 數據 變量 bst log 關於數據庫的查詢中經常需要用到多表的連接查詢,這裏就簡單地展示關於linq的查詢功能。 1、單表的查詢 [csharp] view plain copy var query = from
表連接和分組查詢
兩張 -- 多表連接查詢 數據行 產生 記錄 group bsp log 分組查詢:分組查詢就是按某一列分組,相同的列合並,得到結果可能他少於總記錄 使用group by分組查詢:按什麽分(年級、姓氏、地址、年齡)年級 分組查詢語法:Select * from <表名
SQL總結 連表查詢
表示 自然連接 簡單 put delete title null ros insert 連接查詢包括合並、內連接、外連接和交叉連接,如果涉及多表查詢,了解這些連接的特點很重要。 只有真正了解它們之間的區別,才能正確使用。 1、Union UNION 操作符用於合並兩個或
Sql連表查詢
teacher rom SQ 學生 全外連接 連接 教師表 tom 重點 1.Union:使用union是組合兩張表,消去表中重復行,兩張表查詢的結果有相同數量的列、列類型相似;UNION ALL,不消除重復行教師表: ID Name 101 Mrs Lee
在Mybatis中使用連表查詢的一次實際應用
多表關聯 del 應用 行記錄 全部 業務 val 一定的 att 以前在工作中很少使用多表關聯查詢,對連表查詢的具體作用和使用場景也沒有很直觀的認識,通過這次在項目中的實際應用,對此有了一定的認識,特記錄如下。 關聯表介紹: 分別是屬性表attr_info、屬性值表a
連表查詢都用Left Join吧
簡單 不知道 效率 行記錄 我們 主體 left 註意 說明 最近看同事的代碼,SQL連表查詢的時候很多時候用的是Inner Join,而我覺得對我們的業務而言,99.9%都應該使用Left Join(還有0.1%我不知道在哪),我用最簡單的方式來描述這兩者的區別,直接看圖
連表查詢
regex 另一個 employee 數據 tab png ima false 通配符 1.內鏈接查詢 1.查詢department表和employee表,d_id字段相等的數據 2.外連接查詢 1.左連接查詢:可以查詢出表1的所指的所有記錄,表2只能查詢出匹配的記錄