1. 程式人生 > 實用技巧 >程式碼片段(二):SQL片段

程式碼片段(二):SQL片段

記錄一些破碎的,有意思的SQL片段

大都是日常工作中使用到的,但具體的業務場景也都記不清了,從有道雲筆記的記錄中扒拉出來,僅作記錄使用

MySQL部分

MySQL 5.7版本實現分組取topN

Hive,Oracle等資料庫系統都有row_number等函式,對於實現分組取topN之類的操作,都很簡單,MySQL8.x也實現了row_number,rank等諸多函式,但對於5.7版本來說,並沒有實現該功能,但又不會寫儲存過程,故鼓搗出下面的這個版本,僅供引數

 -- 該功能實現的其實是 分組後,再分別去掉幾個最高值,去掉幾個最低值,然後再取平均數
select 
	prov_id,avg(data_size_all) 
from (
	select 
		a.prov_id,a.data_size_all,a.daily_date,a.type,count(b.prov_id)
	from  lf_zb_src_prov_d_quality_daily_anylize a 
	left join lf_zb_src_prov_d_quality_daily_anylize b 
		on a.prov_id = b.prov_id and a.type=1 and b.type=1 -- 關聯條件,不用管
		and a.daily_date < b.daily_date -- 該條件是不等值連線,會導致關聯多次,下面用這個次數進行取topN
	where a.type=1 and b.type=1  -- 篩選條件,不用管
	group by a.prov_id,a.data_size_all,a.daily_date,a.type -- 分組條件
	having count(b.prov_id)<7  -- 取得是關聯次數小於7次的,再多加幾個,即可實現掐頭去尾取平均值
	order by a.prov_id,a.daily_date
) c
group by c.prov_id      

實現累加需求

公司建模組的小姐姐來問了個問題:要計算一個使用者的一年內的話費累積額,也就是說他1月份花了100,二月份花了100,則出的結果是1月份100,2月份累計,是200,以此類推

-- 以下方案是百度後實現的,不記得是哪位大佬的方案了,只有但是把方案記錄在有道里,特此記錄一下
實現一:
select t.*
,(select sum(price) from t_charge temp where temp.date <= t.date) as total_price
from t_charge t
group by t.id;
實現二:
select t.*, sum(temp.price) as total_price
from t_charge t,t_charge temp
where t.date <= temp.date
group by t.id;

group_concat的用法:分組後組內的全部concat起來

這一條隱約記得應該是計算所有延遲的省份數量,資料量變化在10%之上的省份列出來,其原始表結構以及忘記了,僅作為記錄group_concat使用的案例

SELECT
  daily_date AS "time",
  sum(case when delay_data_hour>=1 then 1 else 0 end) as delay_num,
  sum(case when remark is not null then 1 else 0 end) as repari_data_num,
  sum(case when datasize_charge >= 0.1 then 1 else 0 end ) as charge_num,
  GROUP_CONCAT(case when delay_data_hour>=1 then prov_name else null end,' ') as delay_prov_name,
  GROUP_CONCAT(case when  remark is not null then prov_name else null end,' ') as repair_prov_name,
  GROUP_CONCAT(case when abs(datasize_charge)>=0.1 then prov_name else null end,' ') as charge_prov_name
FROM lf_zb_src_prov_d_quality_daily_anylize
WHERE
   now_date = DATE_FORMAT(DATE_SUB(CURDATE(), INTERVAL 2 day),'%Y-%m-%d')
   and prov_name != '全國彙總'
group BY time
----------------------------------------------------------------------------
time       |delay_num |repari_data_num |charge_num |delay_prov_name     |repair_prov_name                                                                                                              |charge_prov_name                                         |
-----------|----------|----------------|-----------|--------------------|--------------------------|--------------------|
2019-02-25 |5         |5              |4          |河南 ,廣西 ,海南 ,福建 ,安徽  |黑龍江 ,遼寧 ,吉林 ,,福建 ,浙江 ,江蘇 ,上  |
 資料做了部分修改

一個不同的合併方式

昨晚加班到很晚,建模組的小姐姐又來難為我了
小姐姐:要實現下面的結果。
我: 為啥要有這麼與眾不同的需求
小姐姐:你就說能不能幹吧?
我:這還不簡單嘛!

select id,max(c_1) ,max(c_2) from(
select ta.id,ta.c_1 as c_1 ,null as c_2 from table_a ta 
union 
select tb.id ,null as c_1,tb .c_2 from table_b tb 
)a
group by id

其內層結構如下

應該還有其他方法,暫時還未想到,記錄一下

MySQL使用select出來的值進行更新

該需求的場景是,我們要把Hive元資料裡的表,全部同步一份到我們公司的專案平臺上,專案平臺的表分為table_info表,column_info表,partition_info表,現在各表都已經同步完畢。但是1.0版本的檢索使用的是table_info中的full_search欄位(2.0版本是使用elasticsearch解決),所以現在需要先更新該欄位。

-- 使用了group_concat和使用select出來的值,進行join關聯後更新,表結構記不得了,只有筆記了,記錄下思路,以備他日之需
SET SESSION group_concat_max_len = 102400; -- 修復concat_ws過長被截斷
UPDATE unicom_advanced.ubd_table_info t4 INNER JOIN 
	(
	select 
		table_id,concat(replace(a,char(13),''),replace(b,char(13),'')) as full_search
	from (
		select 
			 t1.table_id,
			 concat(t1.table_code,'|',t1.table_name,'|',t1.desc_info,'|',t1.table_business_desc,'|') a,
			group_concat(t2.column_name,t2.column_code,'|',t5.partition_code,'|',t5.partition_name) as b
		from unicom_advanced.ubd_table_info t1
		left join unicom_advanced.ubd_column_info t2
			on t1.table_id = t2.table_id
		left join unicom_advanced.ubd_partition_info t5
			on t1.table_id = t5.table_id
		-- where t1.table_id in (1363372844563160069,1363372844563160581,1363372844563160837,1363372844563161605,1363372844563160070,1363372844563160582)
		group by t1.table_id
	)c
	group by table_id
	) as t3
ON t4.table_id=t3.table_id
set t4.full_search=t3.full_search;