1、Mybatis和Hibernate
1.1、獲取結果爲list<map<String,Object>>
1.1.1、mybatis
解釋
1、返回類型必須是java.util.HashMap
2、map中的value 必須是Objecrt
1.1.1.1、mapper接口**
public interface HealerJeanMapper {
List<Map<String,Object>> sqlMap();
}
1.1.1.2、mapper.xml
<select id="sqlMap" resultType="java.util.HashMap">
SELECT h.id as id ,h.subject as subject FROM healerjean h;
</select>
1.1.1.3、controller測試
@RequestMapping("sqlMap")
@ResponseBody
public List<Map<String,Object>> sqlMap(){
return healerJeanMapper.sqlMap();
}
1.1.2、Jpa分組製作
- 1、mapper.xml
@Query(value = "select new map(g.department as department,count(*) as count) from GraduateDestination g group by g.department")
List<Map<String,Object>> getAcademyEmplo(String graduateDate);
- 2、使用
Map<String ,Integer> academyEmploMap=new HashMap<>();
List<Map<String,Object>> list = destinationRepostiory.getAcademyEmplo(graduateDate);
for(Map<String,Object> map:list){
String key = map.get("department").toString() ;
String value = Integer.parseInt(map.get("count").toString()) ;
emploMap.put(key,value);
}
1.2、resultMap
作爲Mybatis返回類型
解釋
1、
property
實體類中的屬性名2、
column
默認是數據表的列名,或者比如
1.2.1、mapper.xml
<select id="select" parameterType="Query" resultMap="BaseResultMap">
select * from scf_contract
</select>
<select id="select" parameterType="Query" resultMap="BaseResultMap">
select c.id as user_id from scf_contract c
</select>
1.2.2、resultMap
<resultMap id="BaseResultMap" type="com.taotao.pojo.TbUser" >
<id column="user_id" property="id" jdbcType="BIGINT" />
<result column="username" property="username" jdbcType="VARCHAR" />
<result column="password" property="password" jdbcType="VARCHAR" />
<result column="phone" property="phone" jdbcType="VARCHAR" />
<result column="email" property="email" jdbcType="VARCHAR" />
<result column="created" property="created" jdbcType="TIMESTAMP" />
<result column="updated" property="updated" jdbcType="TIMESTAMP" />
</resultMap>
1.3、If
標籤的使用
<select id="findCustomerList" resultType="com.entity.db.customer.Customer">
SELECT t.* from crm_customer t
WHERE t.isVisiblisVisiblee = 1
<if test="name != null and name != ''">
and t.name like CONCAT('%','${name}','%' )
</if>
<if test="status != null">
and t.status = #{status}
</if>
</select>
1.4、where標籤和trim的使用
解釋
1、where標籤會使sql語句自動加上where
2、 trim標籤內sql語句 ,去除 ”前“,”後“ 內容、加前後綴
- suffixOverrides= “,” 去除多餘的後綴 ','
- prefixOverrides=“and” 去除多餘的前綴 'and '
- **prefix="(" 加前綴 **
- **suffix=")" 加後綴 **
<select id="selectByExample" parameterType="ScfContractQuery" resultMap="BaseResultMap">
select
<trim suffixOverrides=",">
<include refid="Base_Column_List" />
</trim>
from scf_contract
<include refid="Example_Where_Clause" />
</select>
<sql id="Example_Where_Clause">
<where>
<trim prefix="(" prefixOverrides="and" suffix=")">
<if test="refSysFileId != null and refSysFileId != ''">
and ref_sys_file_id = #{refSysFileId,jdbcType=VARCHAR}
</if>
</trim>
</where>
</sql>
1.5、foreach標籤 的使用
<if test="statusList != null and statusList.size() > 0">
and status in
<foreach collection="list" index="index" item="item"
open="(" separator="," close=")">
#{item}
</foreach>
</if>
1.6、choose when 標籤 (相當於if else)的使用
<choose>
<when test="flag == 1">
and t.status = 0
</when>
<when test="flag == 2">
and t.status = 1
</when>
<when test="flag == 3">
and t.expressStatus = 1
</when>
<when test="flag == 4">
and t.status = -2
</when>
<otherwise>
</otherwise>
</choose>
1.7、製作參數map值在mybatis的mapper.xml使用
1.7.1、controller接收參數
@RequestMapping("data")
@ResponseBody
public ResponseBean data(String name,
Integer type,
Integer status,
@RequestParam(value = "page",defaultValue = "0") Integer page){
int pageSize = 15;
Pageable pageable = new PageRequest(page,pageSize);
Page<AppInfoData> dataPage = skinsService.findList(pageable,
"name",name,
"type",type,
"status",status);
return ResponseBean.buildSuccess(dataPage);
}
1.7.2、service 製作map參數
pageable 主要是利用裏面的參數製作limit參數的
@Override
public Page<AppInfoData> findList(Pageable pageable, Object... param) {
Map data = MyBatisHelper.mergeParameterMap(pageable,param);
if(data.get("startDate") != null){
Date startDate = (Date) data.get("startDate");
data.put("startDate", .DateHelper.getDateFirstTime(startDate));
}
if(data.get("endDate") != null){
Date endDate = (Date) data.get("endDate");
data.put("endDate",DateHelper.getDateLastTime(endDate));
}
List<SkinAppInfoData> dataList = skinsMapper.findSkinList(data);
Long count = skinsMapper.countSkinList(data);
return new PageImpl<SkinAppInfoData>(dataList,pageable,count);
}
1.7.3、MyBatisHelper工具類
public class MyBatisHelper {
public static final String PARAM_OFFSET = "offset";
public static final String PARAM_LIMIT = "limit";
public MyBatisHelper() {
}
public static Map<String, Object> mergeParameterMap(Object... parameter) {
if (parameter.length % 2 != 0) {
throw new IllegalArgumentException("parameter須爲key-value對應參數");
} else {
Map<String, Object> map = new HashMap();
for(int i = 0; i < parameter.length; i += 2) {
map.put(parameter[i].toString(), parameter[i + 1]);
}
return map;
}
}
public static Map<String, Object> mergeParameterMap(Pageable pageable, Object... parameter) {
if (parameter.length % 2 != 0) {
throw new IllegalArgumentException("parameter須爲key-value對應參數");
} else {
Map<String, Object> map = new HashMap();
map.put("offset", pageable.getOffset());
map.put("limit", pageable.getPageSize());
for(int i = 0; i < parameter.length; i += 2) {
map.put(parameter[i].toString(), parameter[i + 1]);
}
return map;
}
}
}
1.7.4、mapper接口
public interface SkinsMapper {
public List<SkinAppInfoData> findSkinList(Map param);
}
1.7.5、mapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.duodian.admore.dao.db.skins.SkinsMapper">
<select id="findSkinList" resultType="com.duodian.admore.data.skins.SkinAppInfoData">
SELECT
A1.`appid`,
A1.`appSecret`,
A1.`icon`,
A1.`makerMemo`,
A1.`haveBackstage`,
A1.`channelJson`,
A1.`filePath`
FROM `skin_app_info_check` a1
where A1.status not in (9)
<if test="name != null and name != ''">
AND (A1.trackId = #{name}
OR A1.name LIKE CONCAT('%',#{name},'%' )
OR A1.appid LIKE CONCAT('%',#{name},'%' )
OR A1.appSecret LIKE CONCAT('%',#{name},'%' )
)
</if>
<if test="type != null and type != '' ">
and A1.type = #{type}
</if>
<if test="status != null and status != '' ">
and A1.status = #{status}
</if>
order by A1.cdate desc
<if test="offset != null and limit != null">
limit #{offset}, #{limit}
</if>
</select>
</mapper>
1.8、query對象作爲參數傳入
1.8.1、query對象
public class SysUserQuery implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
private Integer offset;
private Integer limit;
private Date startDate;
private Date endDate ;
private String userid;
private String userParam;
private Integer status;
}
1.8.2、controller層
@RequestMapping("data")
@ResponseBody
public ResponseBean data(@RequestParam(defaultValue = "0")Integer page,
@RequestParam(defaultValue = "15")Integer pageSize,
SysUserQuery query){
Pageable pageable = new PageRequest(page,pageSize);
return ResponseBean.buildSuccess(sysDingUserService.getData(pageable,query));
}
1.8.3、service層,將pageable分頁對象放入
@Override
public Page<SysDingUser> getDingUserData(Pageable pageable, SysUserQuery query) {
query.setOffset(pageable.getOffset());
query.setLimit(pageable.getPageSize());
List<SysDingUser> list = sysMapper.findSysDingUserList(query);
Long count = sysMapper.countSysDingUser(query);
return new PageImpl<>(list, pageable, count);
}
}
1.9、resultType 返回對象
解釋
1、對於數據庫字段匹配的,可以直接選擇
2、對於不匹配的使用 as 轉化
<select id="findRedStartSpread"
parameterType="com.duodian.RedStartSpreadQuery"
resultType="com.duodian.RedStartHistoryBean">
select
k.trackId,
e.smallIcon,
e.formattedPrice,
e.price,
e.fileSizeBytes,
e.trackName,
f.name admName,
a.nickName userName,
DATE_FORMAT(k.spreadDateStart, '%Y-%m-%d') AS ymd,
k.userId
FROM
redstart_spread k
1.10、不使用註解@Param 只有一個參數傳入
解釋
使用了@Param正常情況下,直接寫參數名字,也可以直接傳入數據,但是隻有一個參數傳入的時候,,不能直接寫參數名字了 而是使用下面的_parameter
1.10.1、mapepr接口
List<CustomerChance> getCustomerList(Long adminId);
1.10.2、mapper.xml
<select id="getCustomerList" resultType="com.duodian.db.CustomerChance">
select *
from `crm_customer_chance` c
where c.isVisible = 1
<if test="_parameter != null">
and c.adminId = #{_parameter}
</if>
</select>
1.11、原生符號
解釋
被<![CDATA[]]>這個標記所包含的內容將表示爲純文本,比如<![CDATA[<]]>表示文本內容“<”。
此標記用於xml文檔中,我們先來看看使用轉義符的情況。我們知道,在xml中,”<”、”>”、”&”等字符是不能直接存入的,否則xml語法檢查時會報錯,如果想在xml中使用這些符號,必須將其轉義爲實體,如”<”、”>”、”&”,這樣才能保存進xml文檔。
1.11.1 舉例說明
但是經過我測試,在mybaits執行的時候,沒有使用 <![CDATA[>]]> 直接 >=也沒有提示報錯
where rownum <![CDATA[<=]]> #{end,jdbcType=INTEGER} )
1.12、一個條件參數匹配多個 字段
<if test="userParam != null and userParam != ''">
AND (t.userId = #{userParam}
OR a.nickName LIKE CONCAT('%',#{userParam},'%' )
OR b.realName LIKE CONCAT('%',#{userParam},'%' )
OR c.realName LIKE CONCAT('%',#{userParam},'%' )
OR t.customerId LIKE CONCAT('%',#{userParam},'%' )
OR t.customerName LIKE CONCAT('%',#{userParam},'%'))
</if>
1.13、多條件排序
1.13.1、正確的多條件排序,排序字段由前端進行傳入${order}
<if test="order != null">
order by ${order}
</if>
1.13.2、chose where進行判斷
舉例:訂單降序 1,訂單升序 2 ,成交額降序 3,成交額升序 4,
<select id="findCouponTaoKeDataByParam" resultType="com.duodian.youhui.data.coupon.CouponTaoKeItemGoodSummaryData">
SELECT c.itemTitle,
COUNT(c.itemId) as orderSize,
sum(c.estimateAmount) AS sumEstimateAmount ,
c.adzoneName,c.adzonePid,
c.createTime,c.itemId
FROM coupon_taoke_data c
<where>
c.dataType = 1 and c.status = 1
<include refid="findCouponTaoKeDataByParamSQL"></include>
</where>
GROUP by c.itemId,c.adzonePid
<if test="order != null">
<choose>
<when test="order == 1">
order by orderSize DESC
</when>
<when test="order == 2">
order by orderSize asc
</when>
<when test="order == 3">
order by sumEstimateAmount DESC
</when>
<when test="order == 4">
order by sumEstimateAmount asc
</when>
</choose>
</if>
<if test="offset != null and limit != ''">
limit #{offset}, #{limit}
</if>
</select>
1.13.3、給排序添加非空條件
使用order by orderid desc實現降序時 ,orderid 爲null數據的會排在數據的最後面;
但是,order by orderid升序時,orderid 爲null的數據則會排在最前面 ,如果想要將orderid爲null的數據排在最後,就需要加上is null
select * from b_programme u order by u.orderid is null
1.13.4、自定義排序規則
order by field (c.status,'Ready','Part','Completed','Close')
1.14 、參數爲0,判斷null
id傳值爲0時(前提是id對應的類型爲long 或者 Integer,String型無此問題),發現並沒有執行if裏的sql,因爲在mybatis中會自動把0當成‘’空字符串,
使用時增加多一個or status == 0判斷
<if test="status != null and status != '' or status == 0">
1.15、 #和$項目中使用的區別
1.15.1、解釋
{變量名} 可以進行預編譯、類型匹配等操作,#{變量名}會轉化爲jdbc的類型
${變量名} 不進行數據類型匹配,直接替換。
select * from tablename where id = #{id}
假設id的值爲12
如果id爲字符型,那麼#{id}表示的就是'12'
如果id爲整型, 那麼#{id}表示的就是12
select * from tablename where id = ${id}
如果字段id爲整型,sql語句就不會出錯,但是如果字段id爲字符型, 那麼sql語句應該寫成select * from table where id = '${id}'。
1.15.2、使用
-
#方式能夠很大程度防止sql注入。因爲#會自動轉換,而&爲直接替換,所以$方式無法防止sql注入
-
項目中的使用,儘量使用# ,少用& 臭小子,明白了吧
#
適用於普通的參數傳入
$
方式一般用於傳入數據庫對象,例如傳入表名。
order爲 A ASC, A DESC ,B DESC ,B asc數據,這裏直接使用#是錯誤的
<when test="order != null">
order by ${order}
</when>
總結:mytabis常見錯誤
1、mybatis日期報錯
異常:invalid comparison: java.util.Date and java.lang.String。
<if test="date!= null and date !=''">
date爲Date類型,不能和‘’比較,只判斷是不是null就行啦:
<if test="date!= null">
2、函數
2.1、ifnull (如果爲空返回第二個,如果不空返回第一個)
ifnull(b.realName,c.realName) authName,
2.2、delete刪除的正確方法
1,delete from user as u where u.userid=6; 錯誤
2,delete from user u where u.userid=6; 錯誤
3,delete from user where userid=6; 正確
4,delete u.* from user u where u.userid=6; 正確
5,delete u from user u where u.userid=6; 正確
2.3、group_concat:語句將某一列的值查詢成逗號分隔的字符串
select GROUP_CONCAT(c.id) from coupon_item_good;
返回結果
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,22,23,24,25,26,27,28,29,30,31,32,33
2.4、find_in_set 查詢字段爲逗號隔開的字段屬性
字段 pnum爲逗號隔開的字符串
1,2,3,4,21,9
select * from test t where find_in_set(2,t.pnum) ;
2.5、隨機查詢
2.5.1 、rand() 性能比較差
RAND() 函數返回的是一個小於1的隨機數
BY RAND() LIMIT 1
<select id="getUrl" resultType="java.lang.String">
SELECT c.url FROM coupon_item_good 5 order by rand() limit 1
</select>
2.5.2、round() 進行優化
SELECT round(column_name,decimals) FROM table_name
參數 | 描述 |
---|---|
column_name | 必需。要舍入的字段 |
decimals | 非必需,規定返回的小數位數,如果不給值,則自動四捨五入取整取整,select round(100.9) ; 101 |
隨機選擇一個id,然後選擇一個大於他的數據,limit控制爲1
隨機選擇一個推廣位,具體條件就是下面and中連接的and t1.status 開始
<select id="findUserCouponAdzone" resultType="com.duodian.coupon.CouponAdzone">
SELECT *
FROM `coupon_adzone` AS t1
JOIN (SELECT ROUND(RAND() * (SELECT MAX(id)
FROM `coupon_adzone`)
) AS id) AS t2
WHERE t1.id >= t2.id
and t1.status = 1
AND t1.adzoneType = 3
and
ORDER BY t1.id ASC
LIMIT 1;
</select>
2.6、case when (試着和if進行替換使用)
2.6.1、普通使用
case cp.ssid when 'aa'
then '0'
else'1'
end as flag
2.6.2、複雜條件
以下場景 我們要扣減金額 operateMoney ,並且要求分配額度和臨時額度扣減完成必須大於 0
字段說明:
分配額度 allot_amount
臨時額度 temp_amount
總額度 total_amount總額度直接減去total_amount
判斷臨時額度是否 大於等於 扣減的額度,
如果大於,那麼直接扣減臨時額度,分配額度不變
如果小於,則是先扣減臨時額度,然後再扣減分配額度
使用主鍵進行更新,只鎖一行,當id和 當分配額度和臨時額度扣減後是否大於0 成立的時候更新
update scf_risk_department_limit set
total_amount = total_amount - #{operateMoney,jdbcType=DECIMAL},
available_amount = available_amount - #{operateMoney,jdbcType=DECIMAL},
allot_amount = (
case when temp_amount >= #{operateMoney,jdbcType=DECIMAL}
then allot_amount
else allot_amount - ( #{operateMoney,jdbcType=DECIMAL} - temp_amount )
end ),
temp_amount = (
case when temp_amount >= #{operateMoney,jdbcType=DECIMAL}
then temp_amount - #{operateMoney,jdbcType=DECIMAL}
else 0
end )
where id = #{id,jdbcType=BIGINT}
and (allot_amount + temp_amount ) > #{operateMoney,jdbcType=DECIMAL}
2.6.3、case 中 when和and一起使用
update driver_online
set vRemainCapacity = case when (vRemainCapacity>0) and ((vRemainCapacity-0.5) >0)
then vRemainCapacity-0.5
else 0 end
where driverId = 'DR120161118100001';
2.6.4、case when 多個條件
update goods
set price = (
case
when price between 0 and 99 then price * 1.2
when price between 100 and 999 then price * 1.1
when price between 1000 and 1999 then price * 1.05
when price > 1999
then price * 1.02
end);
select * from goods;
2.6.5、case的目標 中添加函數
select substr(t1.area_id, 1, 1) type,
substr(t1.area_id, 2) id,
case substr(t1.area_id, 1, 1)
when 'c' then
(select t2.country
from countnumber.dbtable_countryid t2
where t2.id = substr(t1.area_id, 2))
else
(select distinct t3.province
from countnumber.dbtable_provinceid t3
where t3.id = substr(t1.area_id, 2))
end name
from t_ad_area t1
2.7、If 函數使用
select if( 1 > 0 ,1 ,0 ) ;
IF(expr1,expr2,expr3)
expr1 是TRUE 返回 expr2 否則返回 expr3
2.8、mysql除法、加法
2.8.1、除法
餘數可以爲0,得到的結果爲NUll
SELECT 1/0 from dual ;
2.8.2、加法
如果有的參數是null,則可以讓參數帶上ifNULL,防止null+size造成的數據時null,不顯示
select o.payAmount,
o.estimateAmount,
(o3.notValidOrderSize +o.orderSize) as orderSize
from user_info u
(IFNULL(o3.notValidOrderSize ,0 ) + IFNULL(o.orderSize ,0 ) ) as orderSize
2.9、mysql 取小數 convert round cast
2.9.1、convert
select convert(10000,decimal(10,2));
# 四捨五入,decimal(10,2)後面的代表最大長度10以及保留的小數位數2
select convert(10569.3645,decimal(10,2)); #10569.36
select convert(10569.3665555,decimal(10,2)); #10569.37
2.9.2、round
round 第二個表示小數保留幾位,不足的補上0。
第二個如果爲負數
-1 代表個位數爲0 ROUND(114.6,-1) 結果 110,
-2 代表個位數和十分位 爲0 ROUND(114.6,-2) 結果 100
ROUND(100.3465,2) 100.35
ROUND(100,2), 100
ROUND(0.6,2), 0.60
ROUND(114.6,-1) 110
2.9.3、cast函數:強制轉換
select cast(10*1/4 as decimal(18,2)) from dual
2.10、abs函數取絕對值
有時候項目中出現兩個數字相減,可能是負數,但是隻是需要這連個數的差值,所以就需要用它
ABS( TIMESTAMPDIFF(MINUTE,i.cdate,#{createTime}) ))< #{adzoneTime})
2.11、isnull、length 函數:判斷是否爲null或空字符串
isnull(aBegBalRule) || length (trim(aBegBalRule))<1
2.12、清表(不要用delete)
delete刪除之後還會佔用id,
truncate table_name ;
2.13、拼接字符串
2.13.1、concat:普通拼接
如果有一個參數爲null,則返回結果爲null
SELECT CONCAT(’My’, NULL, ‘QL’);
NULL
2.13.2、concat_ws,分隔符連接字符串
第一個參數是其它參數的分隔符。分隔符的位置放在要連接的兩個字符串之間。分隔符可以是一個字符串,也可以是其它參數。
- 如果分隔符爲 NULL,則結果爲 NULL
- 函數會忽略任何分隔符參數後的 NULL 值。
SELECT CONCAT_WS(',','First name','Second name','Last Name');
First name,Second name,Last Name
SELECT CONCAT_WS(',','First name','','Last Name');
First name,,Last Name (空字符串不會忽略)
SELECT CONCAT_WS(',','First name',null ,'Last Name');
First name,Last Name
2.13.3、使用
模糊查詢使用
concat('%',#{params},'%'))
<if test="params != null and params != ''">
u.nickName like concat('%',#{params},'%')
</if>
2.14、locate: 出現的index位置
SELECT LOCATE('bar', 'foobarbar'); #4
SELECT LOCATE('xbar', 'foobarbar'); #0
位置從4開始數起
SELECT LOCATE('bar', 'foobarbar',4); # 4
項目使用
查找具有http字段的用戶
select * from users where locate('http',itemUrl);
判斷site表中的url是否包含'http://'子串,如果不包含則拼接在url字符串開頭
update site set url =concat('http://',url) where locate('http://',url)=0;
2.15、like 匹配
2.15.1、_:表示任意單個字符。匹配單個任意字符
2.15.2、[charlist] :只要在裏面存在就匹配
2.16、日期的一些函數使用
2.16.1、date_format 、str_to_date
date類型默認的時分秒 爲00:00:00
數據準備
create table date_test(
id bigint(20) not null auto_increment ,
name varchar(20) default '',
yyyyMMdd date default null ,
yyyyMMddHHmmss datetime default null ,
primary key (id)
)
INSERT INTO date_test (id, name, yyyyMMdd, yyyyMMddHHmmss) VALUES (1, 'healerjean', '2018-12-12', '2018-12-12 23:11:11');
1、date_format
# yyyyMMddHHmmss 存儲數據爲 2018-12-12 23:11:11
select * from date_test d where date_format(d.yyyyMMddHHmmss,"%Y-%m-%d") = '2018-12-12';
select * from date_test d where date_format(d.yyyyMMddHHmmss,"%Y-%m-%d %H:%i:%s") = '2018-12-12 23:11:11';
# yyyyMMdd 存儲的爲 2018-12-12
select * from date_test d where date_format(d.yyyyMMdd,"%Y-%m-%d") = '2018-12-12';
select * from date_test d where date_format(d.yyyyMMdd, "%Y-%m-%d %H:%i:%s") = '2018-12-12 00:00:00';
2、str_to_date
select str_to_date('08/09/2008', '%m/%d/%Y'); -- 2008-08-09
select str_to_date('08/09/08' , '%m/%d/%y'); -- 2008-08-09
select str_to_date('08.09.2008', '%m.%d.%Y'); -- 2008-08-09
select str_to_date('08:09:30', '%h:%i:%s'); -- 08:09:30
select str_to_date('08.09.2008 08:09:30', '%m.%d.%Y %h:%i:%s'); -- 2008-08-09 08:09:30
#注意哦,下面這種我們匹配數據庫中一定存在的,不可以類似於format那樣模糊查詢,因爲條件是我們字數輸入的
select * from date_test d where d.yyyyMMdd = STR_TO_DATE('2018-12-12','%Y-%m-%d') ;
select * from date_test d where d.yyyyMMdd = STR_TO_DATE('2018-12-12 00:00:00','%Y-%m-%d %H:%i:%s') ;
select * from date_test d where (d.yyyyMMdd) = '2018-12-12';
# 下面這個找不到數據,說明date類型默認的時分秒 爲00:00:00
select * from date_test d where date_format(d.yyyyMMdd, "%Y-%m-%d %H:%i:%s") = '2018-12-12 11:00:00';
2.16.2、timestampdiff :選擇大於或小於某個時間段的數據
單位 | 說明 |
---|---|
SECOND | 秒 |
MINUTE | 分鐘 |
HOUR | 小時 |
DAY | 天 |
MONTH | 月 |
YEAR | 年 |
2.16.2.1、計算日期差
計算日期差,不要使用now()而是使用 curdate() ;
TIMESTAMPDIFF(DAY, curdate(),cb.bill_end_time) as warning_day,
2.16.2.2、計算小時差
獲取48小時之內的數據
<select id="find48Hours" resultType="com.duodian.OnlineChatPerson">
SELECT * from call_online_chat_person c
WHERE timestampdiff(HOUR,c.cdate,now()) < 48
</select>
2.16.3、unix_timestamp:獲取日期的時間戳
unix_timestamp(),
unix_timestamp(date),
from_unixtime(unix_timestamp),
from_unixtime(unix_timestamp,format)
select unix_timestamp(); -- 1218290027
select unix_timestamp('2008-08-08'); -- 1218124800
select unix_timestamp('2008-08-08 12:30:00'); -- 1218169800
SELECT unix_timestamp(u.date) from user_info u;
1528427765000 毫秒
2.16.4、from_unixtime : 時間戳轉化爲日期(時間戳爲毫秒)
select from_unixtime(1218290027); -- '2008-08-09 21:53:47'
select from_unixtime(1218169800, '%Y %D %M %h:%i:%s %x'); -- '2008 8th August 12:30:00 2008'
SELECT from_unixtime(1500109248, '%Y-%m-%d %H:%i:%S');
2017-07-15 17:00:48
2.16.5、date_add 、date_sub:日期加減計算
date_add(date,INTERVAL expr type)
date_sub(date,INTERVAL expr type)
"OrderDate" 添加 2 天
SELECT
OrderId,
date_add(OrderDate,INTERVAL 2 DAY) AS OrderPayDate
FROM Orders
MICROSECOND
SECOND
MINUTE
HOUR
DAY
WEEK
MONTH
QUARTER
YEAR
SECOND_MICROSECOND
MINUTE_MICROSECOND
MINUTE_SECOND
HOUR_MICROSECOND
HOUR_SECOND
HOUR_MINUTE
DAY_MICROSECOND
DAY_SECOND
DAY_MINUTE
DAY_HOUR
YEAR_MONTH
2.16.6、 to_days(date), from_days(days) :(日期、天數(互轉))
select to_days('0000-00-00'); -- 0
select to_days('2008-08-08'); -- 733627
2.16.7、time_to_sec(time), sec_to_time(seconds) (時間、秒(互轉))
select time_to_sec('01:00:05'); -- 3605
select sec_to_time(3605); -- '01:00:05'
2.16.8、 makdedate(year,dayofyear), maketime(hour,minute,second) (拼湊日期、時間函數:)
select makedate(2001,31); -- '2001-01-31'
select makedate(2001,32); -- '2001-02-01'
select maketime(12,15,30); -- '12:15:30'
2.16.9、查詢一些特定日期
今天
select * from 表名 where to_days(時間字段名) = to_days(now());
昨天
SELECT * FROM 表名 WHERE TO_DAYS( NOW( ) ) - TO_DAYS( 時間字段名) <= 1
7天
SELECT * FROM 表名 where DATE_SUB(CURDATE(), INTERVAL 7 DAY) <= date(時間字段名)
近30天
SELECT * FROM 表名 where DATE_SUB(CURDATE(), INTERVAL 30 DAY) <= date(時間字段名)
本月
SELECT * FROM 表名 WHERE DATE_FORMAT( 時間字段名, '%Y%m' ) = DATE_FORMAT( CURDATE( ) , '%Y%m' )
上一月
SELECT * FROM 表名 WHERE PERIOD_DIFF( date_format( now( ) , '%Y%m' ) , date_format( 時間字段名, '%Y%m' ) ) =1
#查詢本季度數據
select * from `ht_invoice_information` where quarter(create_date)=quarter(now());
#查詢上季度數據
select * from `ht_invoice_information` where QUARTER(create_date)=QUARTER(DATE_SUB(now(),interval 1 QUARTER));
#查詢本年數據
select * from `ht_invoice_information` where YEAR(create_date)=YEAR(NOW());
#查詢上年數據
select * from `ht_invoice_information` where year(create_date)=year(date_sub(now(),interval 1 year));
查詢當前這周的數據
SELECT name,submittime FROM enterprise WHERE YEARWEEK(date_format(submittime,'%Y-%m-%d'))
= YEARWEEK(now());
查詢上週的數據
SELECT name,submittime FROM enterprise WHERE YEARWEEK(date_format(submittime,'%Y-%m-%d')) = YEARWEEK(now())-1;
查詢當前月份的數據
select name,submittime from enterprise where date_format(submittime,'%Y-%m')=date_format(now(),'%Y-%m')
查詢距離當前現在6個月的數據
select name,submittime from enterprise where submittime between date_sub(now(),interval 6 month) and now();
2.16.10、其他
https://www.cnblogs.com/ggjucheng/p/3352280.html
3、表相關
3.1、添加表的備註和字段備註
3.1.1、創建表的時候添加備註
CREATE TABLE `healerjean_comment` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(32) NOT NULL COMMENT '名字備註',
`email` varchar(64) NOT NULL,
`message` text ,
PRIMARY KEY (`id`),
KEY `index_name` (`name`)
) COMMENT='表名備註' ;
3.1.2、表創建完成添加表名備註和字段備註
ALTER TABLE healerjean_comment COMMENT='測試索引表';
ALTER table healerjean_comment MODIFY name VARCHAR(32) NOT NULL COMMENT '名字備註'
3.2、查詢建表語句
show create table table_name ;
3.3、查看列的屬性
show full columns from healerjean;
3.4、修改字段順序
3.4.1、放到第1位
alter table demo_entity modify name varchar(32) comment '名字' first ;
3.4.2、放到某個字段後面
alter table demo_entity modify name varchar(32) comment '名字' after id ;
3.5、給表添加約束(唯一索引)
這個其實很常見,經常我們會使用主鍵作爲唯一約束,如果是手機用戶,或者是郵箱用戶進行登錄,那麼這個登錄的字段並不是主鍵。在高併發,註冊的時候,如果不設置唯一約束,則可能會導入兩個相同的數據。爲了防止這種情況發生,我們要注意添加約束。
創建聯合約束,我們發現,這裏設置爲唯一約束,建立唯一約束和唯一索引又什麼區別?建立唯一約束的時候,也會自動的創建唯一索引。建立唯一索引可以說是唯一約束的一種手段。
3.5.1、添加普通和唯一索引
DROP TABLE user_info ;
create table user_info(
id BIGINT(20) not null auto_increment,
fuWuBusinessNoId BIGINT(20) default null,
dingYueBusinessNoId BIGINT(20) default null,
openId varchar(20) DEFAULT NULL UNIQUE ,
iphone varchar(20) default null COMMENT '',
status int(11) default null ,
cdate timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
udate timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY unique_fuWuBusinessNoId_iphone (fuWuBusinessNoId,iphone) COMMENT '服務號和手機號唯一標識一個用戶,可用於手機號登錄判斷',
PRIMARY key (id));
添加普通索引
ALTER TABLE user_info add name VARCHAR(20) DEFAULT NULL ;
CREATE INDEX index_name on user_info(name) ;
添加唯一索引
ALTER TABLE user_info add mail VARCHAR(20) DEFAULT NULL ;
CREATE UNIQUE INDEX index_mail on user_info(mail) ;
alter table user_inf add unique index_mail `user_info` ( mail);
3.5.2、查看索引
show INDEX from user_info ;
3.5.1、刪除約束(唯一索引)
ALTER TABLE jw_role DROP INDEX resource_name;
3.5.4、SpringBoot註解
@Table(name = "user_info",
uniqueConstraints = {
@UniqueConstraint(columnNames = "openId"),
@UniqueConstraint(columnNames = {"fuId","iphone"})},
indexes = {
@Index(name = "index_itemGoodId",columnList = "authority,permission",unique = true),
@Index(name = "index_cdate",columnList = "cdate")
})
@Entity
@Accessors(chain = true)
@Data
@NoArgsConstructor
@ApiModel(description = "微信用戶信息")
public class UserInfo {
3.6、存儲引擎
3.6.1、show engines:查看存儲引擎
mysql> SHOW ENGINES ;
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
| Engine | Support | Comment | Transactions | XA | Savepoints |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
| InnoDB | DEFAULT | Supports transactions, row-level locking, and foreign keys | YES | YES | YES |
| MRG_MYISAM | YES | Collection of identical MyISAM tables | NO | NO | NO |
| MEMORY | YES | Hash based, stored in memory, useful for temporary tables | NO | NO | NO |
| BLACKHOLE | YES | /dev/null storage engine (anything you write to it disappears) | NO | NO | NO |
| MyISAM | YES | MyISAM storage engine | NO | NO | NO |
| CSV | YES | CSV storage engine | NO | NO | NO |
| ARCHIVE | YES | Archive storage engine | NO | NO | NO |
| PERFORMANCE_SCHEMA | YES | Performance Schema | NO | NO | NO |
| FEDERATED | NO | Federated MySQL storage engine | NULL | NULL | NULL |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
9 rows in set (0.05 sec)
3.6.1、修改表的存儲引擎
alter table healerjean_comment ENGINE = MyISAM ;
3.6.2、查看錶的存儲引擎
show create table table_name ;
複雜查詢
1、count
1.1、count(*)、count(id)
如果版本不太高的會報錯*(因爲沒有分組),高級的版本下面這個只會輸出一行
SELECT count(*) as "count",idfa from apps_click_record a;
1.2、和group分組一起使用 ,就表示分組之後每組的個數
SELECT count(*) as "count",idfa
from apps_click_record a
WHERE a.keywordId = '169995'
GROUP by idfa
ORDER BY count(*) DESC ;
1.3、count(*) 和 * 的查詢 是錯誤的
下面是錯誤的
SELECT count(*) as "count",* from apps_click_record a;
1.4、count(distinct Sname)去掉重複得到唯一的數量
select count(distinct b.type) from B b
# 下面這種寫法垃圾死了
select count(*) from
(
select b.type from B b group by b.type
) m
2、Group by
5.7 版本的 mysql中可能會遇到取唯一值的問題。一定要注意
2.1、分組過濾重複
2.1.1、表中有id和name 兩個字段,查詢出name重複的所有數據
select *
from healerjean a
where (a.username) in (
select username
from healerjean
group by username
having count(*) > 1
)
2.1.2、刪除分組中重讀的數據,只保留id最小的記錄
1、查詢每組重複的用戶名
select username from healerjean group by username having count(username) > 1
2、先查詢每組重複的id最小的數據
select min(id) from healerjean group by username having count(username)>1
3、判斷用戶名重複,並排除掉id最小的數據,進行刪除
delete from healerjean
where username in (
select username
from healerjean
group by username
having count(username) > 1
)
and id not in (
select min(id)
from healerjean
group by username
having count(username)>1)
2.1.3、查找表中多餘的重複記錄(多個字段)
select *
from vitae a
where (a.peopleId,a.seq) in (
select peopleId, seq
from vitae
group by peopleId,seq
having count(*) > 1)
2.2、havaing count用法
2.2.1、舉例說明1
數據樣例
create table tb_grade (
Sno int(11) default 0 comment '學號',
Sname varchar(20) default '' comment '姓名',
Cno int(11) default 0 comment '學號',
Cname varchar(20) default ''comment '課程名',
score int(11) default 0 comment '分數'
) comment '成績表' ;
INSERT INTO tb_grade (Sno, Sname, Cno, Cname, score) VALUES (1001, '李菲', 1, '語文', 86);
INSERT INTO tb_grade (Sno, Sname, Cno, Cname, score) VALUES (1001, '李菲', 2, '數學', 50);
INSERT INTO tb_grade (Sno, Sname, Cno, Cname, score) VALUES (1001, '李菲', 3, '英語', 41);
INSERT INTO tb_grade (Sno, Sname, Cno, Cname, score) VALUES (1001, '李菲', 4, '化學', 89);
INSERT INTO tb_grade (Sno, Sname, Cno, Cname, score) VALUES (1001, '李菲', 5, '物理', 20);
INSERT INTO tb_grade (Sno, Sname, Cno, Cname, score) VALUES (1002, '張宇晉', 1, '語文', 86);
INSERT INTO tb_grade (Sno, Sname, Cno, Cname, score) VALUES (1002, '張宇晉', 2, '數學', 50);
INSERT INTO tb_grade (Sno, Sname, Cno, Cname, score) VALUES (1002, '張宇晉', 3, '英語', 70);
INSERT INTO tb_grade (Sno, Sname, Cno, Cname, score) VALUES (1002, '張宇晉', 4, '化學', 89);
INSERT INTO tb_grade (Sno, Sname, Cno, Cname, score) VALUES (1002, '張宇晉', 5, '物理', 20);
INSERT INTO tb_grade (Sno, Sname, Cno, Cname, score) VALUES (1003, '翠花', 1, '語文', 10);
INSERT INTO tb_grade (Sno, Sname, Cno, Cname, score) VALUES (1003, '翠花', 2, '數學', 20);
INSERT INTO tb_grade (Sno, Sname, Cno, Cname, score) VALUES (1003, '翠花', 3, '英語', 70);
INSERT INTO tb_grade (Sno, Sname, Cno, Cname, score) VALUES (1003, '翠花', 4, '化學', 40);
INSERT INTO tb_grade (Sno, Sname, Cno, Cname, score) VALUES (1003, '翠花', 5, '物理', 10);
Sno | Sname | Cno | Cname | score |
---|---|---|---|---|
1001 | 李菲 | 1 | 語文 | 86 |
1001 | 李菲 | 2 | 數學 | 50 |
1001 | 李菲 | 3 | 英語 | 41 |
1001 | 李菲 | 4 | 化學 | 89 |
1001 | 李菲 | 5 | 物理 | 20 |
1002 | 張宇晉 | 1 | 語文 | 86 |
1002 | 張宇晉 | 2 | 數學 | 50 |
1002 | 張宇晉 | 3 | 英語 | 70 |
1002 | 張宇晉 | 4 | 化學 | 89 |
1002 | 張宇晉 | 5 | 物理 | 20 |
1003 | 翠花 | 1 | 語文 | 10 |
1003 | 翠花 | 2 | 數學 | 20 |
1003 | 翠花 | 3 | 英語 | 70 |
1003 | 翠花 | 4 | 化學 | 40 |
1003 | 翠花 | 5 | 物理 | 10 |
1、查詢不及格科目數大於等於2的學生學號和學生姓名:
select t.Sno,t.Sname
from tb_grade t
where t.score < 60
group by t.Sno having count(t.Cno) > 2
Sno | Sname |
---|---|
1001 | 李菲 |
1003 | 翠花 |
2、查詢不及格科目數大於等於2的學生學號和不及格科目數量:
select t.Sno,
count(t.Cno) as '不及格科目數量'
from tb_grade t
where t.score < 60
group by t.Sno having count(t.Cno) > 2
Sno | 不及格科目數量 |
---|---|
1001 | 3 |
1003 | 4 |
3、查詢不及格科目數大於等於2的學生學號、學生姓名、科目號、科目名稱和分數,並按學號降序、科目號升序排序
select t.Sno,
t.Sname,
t.Cno,
t.Cname,
t.score
from tb_grade t
where t.score < 60
and t.Sno in (select b.Sno
from tb_grade b
where b.score < 60 group by b.Sno having count(b.Cno) > 2)
order by t.Sno desc, Cno asc;
Sno | Sname | Cno | Cname | score |
---|---|---|---|---|
1003 | 翠花 | 1 | 語文 | 10 |
1003 | 翠花 | 2 | 數學 | 20 |
1003 | 翠花 | 4 | 化學 | 40 |
1003 | 翠花 | 5 | 物理 | 10 |
1001 | 李菲 | 2 | 數學 | 50 |
1001 | 李菲 | 3 | 英語 | 41 |
1001 | 李菲 | 5 | 物理 | 20 |
2.3、having中添加and
接上面的舉例說明1的數據樣例
select t.Sno,t.Sname
from tb_grade t
where t.score < 60
group by t.Sno having count(t.Cno) > 1 and Sname = '李菲';
Sno | Sname |
---|---|
1001 | 李菲 |
3、join連接
3.1、內連接 左鏈接,右連接,全連接
3.1.1、INNER JOIN 和 JOIN
- **返回左表和 右表同時存在的行 **
- 和from 直接查詢兩個表示一樣的效果,只不過from這種方式正在被棄用
SELECT Persons.LastName, Persons.FirstName, Orders.OrderNo
FROM Persons
INNER JOIN Orders ON Persons.Id_P = Orders.Id_P
ORDER BY Persons.LastName
3.1.2、LEFT JOIN
即使右表中沒有匹配,也從左表返回所有的行
select Persons.LastName, Persons.FirstName, Orders.OrderNo
from Persons
left join Orders on Persons.Id_P = Orders.Id_P
order by Persons.LastName
3.1.3、RIGHT JOIN:
即使左表中沒有匹配,也從右表返回所有的行
select Persons.LastName, Persons.FirstName, Orders.OrderNo
from Persons
right join Orders on Persons.Id_P = Orders.Id_P
order by Persons.LastName
3.1.4、FULL JOIN:
只要其中一個表中存在匹配,就返回行
select Persons.LastName, Persons.FirstName, Orders.OrderNo
from Persons full
join Orders on Persons.Id_P = Orders.Id_P
order by Persons.LastName
3.2、舉例說明1
數據樣例
create table department (
dept_id int(11) default 0 comment '部門id',
dept_name varchar(20) default '' comment '部門名稱'
)comment ='部門' ;
insert into department values(1,'廣告部');
insert into department values(2,'媒體部');
insert into department values(3,'管理部');
select * from department ;
create table employee (
emp_id int(11) default 0 comment '員工id',
emp_name varchar(20) default '' comment '員工名字',
dept_id int(11) default 0 comment '部門id',
emp_wage decimal(19,2) default 0 comment '薪水'
)comment ='員工表' ;
INSERT INTO VALUES (1, '喬峯', 1, 17000.00);
INSERT INTO VALUES (2, '張三丰', 1, 15000.00);
INSERT INTO VALUES (3, '段譽', 2, 18000.00);
INSERT INTO VALUES (4, '虛竹', 2, 12000.00);
INSERT INTO VALUES (5, '楊過', 3, 16000.00);
INSERT INTO VALUES (6, '黃老邪', 1, 17000.00);
INSERT INTO VALUES (7, '黃蓉', 1, 15000.00);
INSERT INTO VALUES (8, '郭靖', 2, 15000.00);
INSERT INTO VALUES (9, '金龍法王', 3, 15000.00);
INSERT INTO VALUES (10, '老頑童', 3, 11000.00);
dept_id | dept_name |
---|---|
1 | 廣告部 |
2 | 媒體部 |
3 | 管理部 |
emp_id | emp_name | dept_id | emp_wage |
---|---|---|---|
1 | 喬峯 | 1 | 17000.00 |
2 | 張三丰 | 1 | 15000.00 |
6 | 黃老邪 | 1 | 17000.00 |
7 | 黃蓉 | 1 | 15000.00 |
3 | 段譽 | 2 | 18000.00 |
4 | 虛竹 | 2 | 12000.00 |
8 | 郭靖 | 2 | 15000.00 |
5 | 楊過 | 3 | 16000.00 |
9 | 金龍法王 | 3 | 15000.00 |
10 | 老頑童 | 3 | 11000.00 |
1、left join
select
d.dept_id,
d.dept_name,
e.emp_name,
e.emp_wage
from
department d
left join employee e on e.dept_id = d.dept_id ;
dept_id | dept_name | emp_name | emp_wage |
---|---|---|---|
1 | 廣告部 | 張宇晉 | 17000.00 |
1 | 廣告部 | 張三丰 | 15000.00 |
2 | 媒體部 | 張翠 | 18000.00 |
2 | 媒體部 | 林徽因 | 12000.00 |
3 | 管理部 | 趙國強 | 17000.00 |
2、left join on and
先會在副表中對and條件進行過濾,然後再跟左邊主表進行關聯
- 主表 (只會對副表起作用)
select d.dept_id,
d.dept_name,
e.emp_name,
e.emp_wage
from department d
left join employee e on e.dept_id = d.dept_id and d.dept_id = 1
dept_id | dept_name | emp_name | emp_wage |
---|---|---|---|
1 | 廣告部 | 喬峯 | 17000.00 |
1 | 廣告部 | 張三丰 | 15000.00 |
1 | 廣告部 | 黃老邪 | 17000.00 |
1 | 廣告部 | 黃蓉 | 15000.00 |
2 | 媒體部 | NULL | NULL |
3 | 管理部 | NULL | NULL |
- 副表(只會對副標起作用)
select d.dept_id,
d.dept_name,
e.emp_name,
e.emp_wage
from department d
left join employee e on e.dept_id = d.dept_id and e.emp_wage = 17000
dept_id | dept_name | emp_name | emp_wage |
---|---|---|---|
1 | 廣告部 | 喬峯 | 17000.00 |
1 | 廣告部 | 黃老邪 | 17000.00 |
2 | 媒體部 | NULL | NULL |
3 | 管理部 | NULL | NULL |
3、where實現全部查詢結果的過濾
select d.dept_id,
d.dept_name,
e.emp_name,
e.emp_wage
from department d
left join employee e on e.dept_id = d.dept_id
where e.emp_wage = 17000;
dept_id | dept_name | emp_name | emp_wage |
---|---|---|---|
1 | 廣告部 | 喬峯 | 17000.00 |
1 | 廣告部 | 黃老邪 | 17000.00 |
4、進階sql
1、求每個部門中的最大工資和最小工資
- 求各個部門的最大工資 和最小工資
select e.dept_id,
max(emp_wage) as max_exp_wage,
min(emp_wage) as min_exp_wage
from employee e
group by e.dept_id
dept_id | max_exp_wage | min_exp_wage |
---|---|---|
1 | 17000.00 | 15000.00 |
2 | 18000.00 | 12000.00 |
3 | 16000.00 | 11000.00 |
- 上面的查詢已經知道部門的最大工資和最小工資了,但是部門的名稱還沒有查出來,可以關聯查出部門的名稱(因爲是一一對應,所以join查詢可以滿足)
select d.dept_id,
d.dept_name,
s.max_exp_wage,
s.min_exp_wage
from department d
left join (
select e.dept_id,
max(emp_wage) as max_exp_wage,
min(emp_wage) as min_exp_wage
from employee e
group by e.dept_id
) s on s.dept_id = d.dept_id;
dept_id | dept_name | max_exp_wage | min_exp_wage |
---|---|---|---|
1 | 廣告部 | 17000.00 | 15000.00 |
2 | 媒體部 | 18000.00 | 12000.00 |
3 | 管理部 | 16000.00 | 11000.00 |
2、查詢每個部門中最大工資僱員並按照部門排序
需要考慮的是,部門中肯定有工資相同的,那麼最大工資也肯定有可能會相同,所以肯定主表是employee
- 1、先查詢每個部門最大的工資
select e.dept_id,
max(e.emp_wage) as max_exp_wage
from employee e
group by e.dept_id
dept_id | max_exp_wage |
---|---|
1 | 17000.00 |
2 | 18000.00 |
3 | 16000.00 |
- 2、查詢工資是最大工資的僱員
select em.dept_id,
em.emp_id,
em.emp_name,
em.emp_wage
from employee em
join (select e.dept_id, max(emp_wage) as max_exp_wage from employee e group by e.dept_id) s
on s.dept_id = em.dept_id
where em.emp_wage = s.max_exp_wage
order by em.dept_id
dept_id | emp_id | emp_name | emp_wage |
---|---|---|---|
1 | 1 | 喬峯 | 17000.00 |
1 | 6 | 黃老邪 | 17000.00 |
2 | 3 | 段譽 | 18000.00 |
3 | 5 | 楊過 | 16000.00 |
- 3、上面基本上完事了,就差部門沒出來,所以關聯查詢部門即可
select em.dept_id,
de.dept_name,
em.emp_id,
em.emp_name,
em.emp_wage
from employee em
join department de on de.dept_id = em.dept_id
join (select e.dept_id, max(emp_wage) as max_exp_wage from employee e group by e.dept_id) s
on s.dept_id = em.dept_id
where em.emp_wage = s.max_exp_wage
order by em.dept_id
dept_id | dept_name | emp_id | emp_name | emp_wage |
---|---|---|---|---|
1 | 廣告部 | 6 | 黃老邪 | 17000.00 |
1 | 廣告部 | 1 | 喬峯 | 17000.00 |
2 | 媒體部 | 3 | 段譽 | 18000.00 |
3 | 管理部 | 5 | 楊過 | 16000.00 |
3、查詢大於平均工資的僱員,並按照部門排序
- 1、先查詢各個部門的平均工資
select e.dept_id, avg(e.emp_wage)
from employee e
group by e.dept_id;
dept_id | AVG(e.emp_wage) |
---|---|
1 | 16000.000000 |
2 | 15000.000000 |
3 | 14000.000000 |
- 2、查詢工資大於平均工資的僱員,這個時候需要left join(join都可以,因爲肯定是一一對應的關係)查詢僱員表了
select em.dept_id,
s.avg_wage,
em.emp_id,
em.emp_name,
em.emp_name,
em.emp_wage
from employee em
left join (select e.dept_id,
avg(e.emp_wage) as avg_wage
from employee e group by e.dept_id)
s on s.dept_id = em.dept_id
where em.emp_wage > s.avg_wage
order by em.dept_id;
dept_id | avg_wage | emp_id | emp_name | emp_name | emp_wage |
---|---|---|---|---|---|
1 | 16000.000000 | 1 | 喬峯 | 喬峯 | 17000.00 |
1 | 16000.000000 | 6 | 黃老邪 | 黃老邪 | 17000.00 |
2 | 15000.000000 | 3 | 段譽 | 段譽 | 18000.00 |
3 | 14000.000000 | 5 | 楊過 | 楊過 | 16000.00 |
3 | 14000.000000 | 9 | 金龍法王 | 金龍法王 | 15000.00 |
- 3、其實上面的結果已經完事了,就是部門名字沒出來
select em.dept_id,
d.dept_name,
s.avg_wage,
em.emp_id,
em.emp_name,
em.emp_wage
from employee em
join department d on d.dept_id = em.dept_id
join (select e.dept_id,
avg(e.emp_wage) as avg_wage
from employee e group by e.dept_id)
s on s.dept_id = em.dept_id
where em.emp_wage > s.avg_wage
order by em.dept_id;
dept_id | dept_name | avg_wage | emp_id | emp_name | emp_wage |
---|---|---|---|---|---|
1 | 廣告部 | 16000.000000 | 6 | 黃老邪 | 17000.00 |
1 | 廣告部 | 16000.000000 | 1 | 喬峯 | 17000.00 |
2 | 媒體部 | 15000.000000 | 3 | 段譽 | 18000.00 |
3 | 管理部 | 14000.000000 | 5 | 楊過 | 16000.00 |
3 | 管理部 | 14000.000000 | 9 | 金龍法王 | 15000.00 |
4、union和 union all 操作符
1、select語句必須擁有相同數量的列。列也必須擁有相似的數據類型。同時,每條 SELECT 語句中的列的順序必須相同。
2、默認情況下 union操作符已經刪除了重複數據。如果允許重複的值,請使用 UNION ALL。
SELECT column_name(s) FROM table_name1
UNION
SELECT column_name(s) FROM table_name2
5、distinct:必須放在開頭
數據樣例
create table `test_table`
(
`id` int(11) default '0' comment 'id',
`english` varchar(20) default '' comment 'name',
`age` int(11) default 0
)
INSERT INTO test_table (id, english, age) VALUES (1, 'a', 12);
INSERT INTO test_table (id, english, age) VALUES (2, 'b', 12);
INSERT INTO test_table (id, english, age) VALUES (3, 'c', 13);
INSERT INTO test_table (id, english, age) VALUES (4, 'c', 16);
INSERT INTO test_table (id, english, age) VALUES (5, 'b', 12);
id | english | age |
---|---|---|
1 | a | 12 |
2 | b | 12 |
3 | c | 13 |
4 | c | 16 |
5 | b | 12 |
5.1、 只作用於一個字段
select distinct english from test_table ;
name |
---|
a |
b |
c |
5.2、作用於2個字段 :必須得id與name都相同的纔會被排除
select distinct english, age from test_table ;
可以觀察到排除一個 b 12
english | age |
---|---|
a | 12 |
b | 12 |
c | 13 |
c | 16 |
5.3、count(distinct colume )
select count(english) from test_table ;
5
select count(distinct english) from test_table
3
5.4、distinct 和 count、group by
select age, count( english) from test_table group by age ;
age | count( english) |
---|---|
12 | 3 |
13 | 1 |
16 | 1 |
select age, count(distinct english) from test_table group by age ;
age | count(distinct english) |
---|---|
12 | 2 |
13 | 1 |
16 | 1 |