1. 程式人生 > >支援連表等複雜查詢的PageHelper修改

支援連表等複雜查詢的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(*) &gt;= #{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 &gt; #{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只能查詢出匹配的記錄