當前位置:首頁 » 編程語言 » SQL解惑筆記
擴展閱讀
webinf下怎麼引入js 2023-08-31 21:54:13
堡壘機怎麼打開web 2023-08-31 21:54:11

SQL解惑筆記

發布時間: 2023-08-17 12:02:20

1. oracle筆記-動態sql

第 章 動態SQL

為何使用動態SQL

實現動態SQL有兩種方式 DBMS_SQL和本地動態SQL(EXECUTE IMMEIDATE)

主要從以下方面考慮使用哪種方式

是否知道涉及的列數和類型

DBMS_SQL包括了一個可以 描述 結果集的存儲過程(DBMS_SQL DESCRIBE_COLUMNS) 而本地動態SQL沒有

是否知道可能涉及的綁定變數數和類型

DBMS_SQL允許過程化的綁定語句的輸入 而本地動態SQL需要在編譯時確定

是否使用 數組化 操作(Array Processing)

DBMS_SQL允許 而本地動態SQL基本不可以 但可以用其他方式實現(對查詢可用FETCH BULK COLLECT INTO 對INSERT等 可用一個BEGIN … END塊中加循環實現)

是否在同一個會話中多次執行同一語句

DBMS_SQL可以分析一次執行多次 而本地動態SQL會在每次執行時進行軟分析

是否需要用REF CURSOR返回結果集

僅本地動態SQL可用REF CURSOR返回結果集

如何使用動態SQL

DBMS_SQL

調用OPEN_CURSOR獲得一個游標句柄

調用PARSE分析語句 一個游標句柄可以用於多條不同的已分析語句 但一個時間點僅一條有效

調用BIND_VARIABLE或BIND_ARRAY來提供語句的任何輸入

若是一個查詢(SELECT語句) 調用DIFINE_COLUMN或DEFINE_ARRAY來告知Oracle如何返回結果

調用EXECUTE執行語句

若是一個查詢 調用FETCH_ROWS來讀取數據 可以使用COLUMN_VALUE從SELECT列表根據位置獲得這些值

否則 若是一個PL/SQL塊或帶有RETURN子句的DML語句 可以調用VARIABLE_VALUE從塊中根據變數名獲得OUT值

調用CLOSE_CURSOR

注意這里對任何異常都應該處理 以關閉游標 防止泄露資源

本地動態SQL

EXECUTE IMMEDIATE 語句

[INTO {變數 變數 … 變數N | 記錄體}]

[USING [IN | OUT | IN OUT] 綁定變數 … 綁定變數N]

[{RETURNING | RETURN} INTO 輸出 [ … 輸出N]…]

注意本地動態SQL僅支持弱類型REF CURSOR 即對於REF CURSOR 不支持BULK COLLECT

最後說明

lishixin/Article/program/Oracle/201311/18948

2. SQL計算電商各項指標數據

本次筆記主要是記錄通過SQL計算電商各項指標數據,包括AARRR部分指標、RFM模型等常用的指標數據;

平台指標:

商品指標:

用戶行為指標:

RFM模型:見之前的文章《 SQL建立RFM模型指標的兩種方法對比 》

用戶留存率:見之前文章《 SQL 查詢用戶留存率(根據兩種不同定義計算) 》

首先我們導入相關數據,並去重數據放進新表 temp_trade;

由於時間關系,以導入如下數據,期間利用
SET date_time = STR_TO_DATE(time,'%Y-%m-%d %H');
set dates=date(date_time);
這兩個函數對原表(紅框)日期進行處理;

再檢查一下關鍵欄位有無缺失值

查詢後得出並無缺失。

查詢結果無異常值;

檢查用戶行為數據有沒有其他類型;

查詢結果無異常值;

-- 建新表,放進 去重後的 數據

create table temp_trade like o_retailers_trade_user;
insert into temp_trade select distinct * from o_retailers_trade_user;

查詢結果:

這里定義跳失率=只有瀏覽行為的用戶數/總用戶數

查詢結果

這里的購買轉化率定義為:某段時間產生購買行為的用戶數/所有到達店鋪的訪客人數

查詢結果:

同時可以通過這演算法求得:每天總行為次數、每天點擊次數、收藏次數、加購物⻋次數、購買次數

查詢結果如下:

由於轉化率的對象是商品,所以以商品id做分組,求對應的用戶行為數求和。可得出每商品的在該段時間內的瀏覽、收藏、加購、購買次數,同時可求得商品購買轉化率。

查詢結果:

此方法與上面商品轉化率大致相同,分組對象改為品類id即可。

查詢結果:

首先創建hours的新欄位,並提取時間;

查詢結果如下:

首先求出各用戶的購買次數

查詢結果:

用case when函數統計出各復購買次數的用戶數

查詢結果如下:

最後將行為串聯起來,並對其進行用戶數統計;

查詢結果如下:

(完結)

3. SQL中left join on 、right join on、inner join on之間的區別

最近在入門SQL,記錄下自己學習的一些筆記。

left join(左聯接) 返回包括以左表主表,左表中的所有記錄和右表中聯結欄位相等(左表中匹配不到的欄位對應的值為null)即:左表的記錄將會全部表示出來,而右表只會顯示符合搜索條件的記錄。

right join(右聯接) 返回包括右表中的所有記錄和左表中聯結欄位相等的記錄

       inner join(等值連接) 只返回兩個表中聯結欄位相等的行,即通過相應條件交集後展示的所有欄位的大表

舉例如下: 

--------------------------------------------

表A記錄如下:

aIDaNum

1a20050111

2a20050112

3a20050113

4a20050114

5a20050115

表槐散B記錄如下:

bIDbName

12006032401

22006032402

32006032403

42006032404

82006032408

--------------------------------------------

1.left join

sql語句如下: 

select * from A

left join B 

on A.aID = B.bID

結果如下:

aIDaNumbIDbName

1a2005011112006032401

2a2005011222006032402

3a2005011332006032403

4a2005011442006032404

5a20050115NULLNULL

(所影響的行數為 5 行)

結果說明:

left join是以A表的記錄為基礎的,A可以看成左表,B可以看成右表,left join是以左表為準的.

換句話說,左表(A)的記錄將會瞎明物全部表示出來,而右表(B)只會顯示符合搜索條件的記錄(例子中為: A.aID = B.bID).B表記錄不足的地方均為NULL.

--------------------------------------------

2.right join

sql語句如下: 

select * from A

right join B 

on A.aID = B.bID

結果如下:

aIDaNum磨液bIDbName

1a2005011112006032401

2a2005011222006032402

3a2005011332006032403

4a2005011442006032404

NULLNULL  82006032408

(所影響的行數為 5 行)

結果說明:

仔細觀察一下,就會發現,和left join的結果剛好相反,這次是以右表(B)為基礎的,A表不足的地方用NULL填充.

--------------------------------------------

3.inner join

sql語句如下: 

select * from A

innerjoin B 

on A.aID = B.bID

結果如下:

aIDaNumbIDbName

1a2005011112006032401

2a2005011222006032402

3a2005011332006032403

4a2005011442006032404

結果說明:

很明顯,這里只顯示出了 A.aID = B.bID的記錄.這說明inner join並不以誰為基礎,它只顯示符合條件的記錄.

從SQL開始入門,其他的語言繼續學習。生命不停,學習不止!

4. 數據分析課程筆記 - 19 - HiveSQL 常用優化技巧

大家好呀,這節課學習 HiveSQL 的常用優化技巧。由於 Hive 主要用來處理非常大的數據,運行過程由於通常要經過 MapRece 的過程,因此不像 MySQL 一樣很快出結果。而使用不同方法寫出來的 HiveSQL 語句執行效率也是不一樣的,因此為了減少等待的時間,提高伺服器的運行效率,我們需要在 HiveSQL 的語句上進行一些優化。

本節課的主要內容

引言
1、技巧一:列裁剪和分區裁剪
(1)列裁剪
(2)分區裁剪
2、技巧二:排序技巧——sort by代替order by
3、技巧三:去重技巧——用group by來替換distinct
4、技巧四:聚合技巧——grouping sets、cube、rollup
(1)grouping sets
(2)cube
(3)rollup
5、技巧五:換個思路解題
6、技巧六:union all時可以開啟並發執行
7、技巧七:表連接優化
8、技巧八:遵循嚴格模式

Hive 作為大數據領域常用的數據倉庫組件,在平時設計和查詢時要特別注意效率。影響Hive效率的幾乎從不是數據量過大,而是數據傾斜、數據冗餘、job 或 I/O 過多、MapRece 分配不合理等等。對 Hive 的調優既包含對HiveSQL 語句本身的優化,也包含 Hive 配置項和 MR 方面的調整。

列裁剪就是在查詢時只讀取需要的列。當列很多或者數據量很大時,如果select 所有的列或者不指定分區,導致的全表掃描和全分區掃描效率都很低。Hive中與列裁剪優化相關的配置項是 hive.optimize.cp ,默認是 true 。

分區裁剪就是在查詢時只讀需要的分區。Hive中與分區裁剪優化相關的則是 hive.optimize.pruner ,默認是 true 。

HiveSQL中的 order by 與其他 SQL 語言中的功能一樣,就是將結果按某個欄位全局排序,這會導致所有map端數據都進入一個 rece 中,在數據量大時可能會長時間計算不完。

如果使用 sort by ,那麼就會視情況啟動多個 recer 進行排序,並且保證每個 recer 內局部有序。為了控制 map 端數據分配到 rece 的 key,往往還要配合 distribute by 一同使用。如果不加 distribute by 的話,map 端數據就會隨機分配給 recer。

這里需要解釋一下, distribute by 和 sort by 結合使用是如何相較於 order by 提升運行效率的。

假如我們要對一張很大的用戶信息表按照年齡進行分組,優化前的寫法是直接 order by age 。使用 distribute by 和 sort by 結合進行優化的時候, sort by 後面還是 age 這個排序欄位, distribute by 後面選擇一個沒有重復值的均勻欄位,比如 user_id 。

這樣做的原因是,通常用戶的年齡分布是不均勻的,比如20歲以下和50歲以上的人非常少,中間幾個年齡段的人又非常多,在 Map 階段就會造成有些任務很大,有些任務很小。那通過 distribute by 一個均勻欄位,就可以讓系統均勻地進行「分桶」,對每個桶進行排序,最後再組合,這樣就能從整體上提升 MapRece 的效率。

取出 user_trade 表中全部支付用戶:

原有寫法的執行時長:

優化寫法的執行時長:

考慮對之前的案例進行優化:

注意: 在極大的數據量(且很多重復值)時,可以先 group by 去重,再 count() 計數,效率高於直接 count(distinct **) 。

如果我們想知道用戶的性別分布、城市分布、等級分布,你會怎麼寫?

通常寫法:

缺點 :要分別寫三次SQL,需要執行三次,重復工作,且費時。

那該怎麼優化呢?

注意 :這個聚合結果相當於縱向地堆在一起了(Union all),分類欄位用不同列來進行區分,也就是每一行數據都包含 4 列,前三列是分類欄位,最後一列是聚合計算的結果。

GROUPING SETS() :在 group by 查詢中,根據不同的維度組合進行聚合,等價於將不同維度的 group by 結果集進行 union all。聚合規則在括弧中進行指定。

如果我們想知道用戶的性別分布以及每個性別的城市分布,你會怎麼寫?

那該怎麼優化呢?

注意: 第二列為NULL的,就是性別的用戶分布,其餘有城市的均為每個性別的城市分布。

cube:根據 group by 維度的所有組合進行聚合

注意 :跑完數據後,整理很關鍵!!!

rollup:以最左側的維度為主,進行層級聚合,是cube的子集。

如果我想同時計算出,每個月的支付金額,以及每年的總支付金額,該怎麼辦?

那應該如何優化呢?

條條大路通羅馬,寫SQL亦是如此,能達到同樣效果的SQL有很多種,要學會思路轉換,靈活應用。

來看一個我們之前做過的案例:

有沒有別的寫法呢?

Hive 中互相沒有依賴關系的 job 間是可以並行執行的,最典型的就是
多個子查詢union all。在集群資源相對充足的情況下,可以開啟並
行執行。參數設置: set hive.exec.parallel=true;

時間對比:

所謂嚴格模式,就是強制不允許用戶執行3種有風險的 HiveSQL 語句,一旦執行會直接報錯。

要開啟嚴格模式,需要將參數 hive.mapred.mode 設為 strict 。

好啦,這節課的內容就是這些。以上優化技巧需要大家在平時的練習和使用中有意識地去注意自己的語句,不斷改進,就能掌握最優的寫法。

5. PLSQL資料庫許可權基礎筆記(GRANT,REVOKE)

許可權包括:

SELECT 

INSERT

UPDATE[(col1,col2)]; 可以加括弧表示只賦予特定列的許可權

DELETE

ALTER

ALL PRIVILEGES

...

CREATE INDEX

CREATE TABLE

ALL PRIVILEGES

...

PUBLIC 關鍵字可以替換用戶名 代表全體用戶

ALL 關鍵字替代許可權 代表所有許可權

WITH GRANT OPTION 表示 賦予用戶許可權的許可權

GRANT OPTION FOR表示撤銷賦予用戶許可權的許可權

我們可以把許可權賦予角色 然後將角色賦予用戶 簡化操作。

創建角色

CREATE ROLE ROLENAME;

GRANT 許可權 ON 表名 TO 角色;

將角色賦予用戶

GRANT ROLENAME TO USERNAME;

GRANT CONNECT TO laurent IDENTIFIED BY motDePasse

6. MySQL筆記1select基礎

查詢語句:select 語句
三種能力:投影、選擇、連接
投影:在一張二維表中根據所需要的條件選出所需要的列

選擇:在二維表中根據所需的條件選擇合適的行

連接:從一張或者多張表中獲取所需要的行,並且把這個行結合在一起的查詢

SQL語句大小寫不敏感。

select語句是可以計算的
算術表達式和運算符優先順序

舉例:select ename,sal 12*sal+100 from emp

計算出年薪+100塊

NULL值是不可用,且未分配的,未知並且不適用的值,可以當成是保留值

AS其實可以省略

例如:select ename as name,sal salary from emp;

查詢出的欄位會自動換成別名
例子:select ename "Name",sal*12 "Annual Salary" from emp;

級聯操作是將列或字元串和其他列串聯,由兩條豎線(||)表示
select ename,job,ename || job as "Employees" from emp;

可以看出Employees就將ENAME和JOB進行結合的一個操作

在select句子中適用DISTINCT 關鍵字消除重復行
select distinct deptnp from emp;

限制選擇的行:
where關鍵字
如果where後面查的數據是字元串類型或者日期類型的要加''號
#######比較條件

舉幾個例子:
select ename,job,sal,deptno from emp where sal between 5000 and 10000;

這個是包含了5000和10000的

in的表達:
select empno,ename,mgr,deptno from emp where mgr in (7788,7782,7000);

只要mgr有括弧裡面的值都顯示出來。

通配符:%通配的是多個字元,_通配的是一個字元

IS NULL是查詢某個欄位為空的顯示出來

and、or、not
例子:

查詢sal>=2000和job的內容是包括MAN字元串的,當同時滿足兩個條件時候才返回結果。

and就是兩邊同時為真,or的話是有一邊為真就行,not就是不等於

ASC 升序,默認升序
DESC 降序
例子:

將deptno中進行升序排列,排列出來後,在將sal進行降序排列。

單行函數:就是對單行數據進行處理的函數,只針對這一條數據得出一個結果
函數工作的過程

ROUND(45.926,2)是將45.926這個數字的小數點後兩位進行四捨五入操作得到45.93
TRUNC(45.926,2) 是將45.926這個數字的小數點後兩位後面的進行丟掉。

返回當前系統日期

經常是不同類型之間的轉換

TO_CHAR就是將日期型數字型轉換成字元型
例子:

數字型的轉換

把字元轉換成數字:

把字元轉換成日期:

什麼是分組函數?
另外的名字叫多行函數,針對於多行數據進行一個匯總處理的一類函數,最後會得到一個匯總的結果。
例子:

其實就是對一系列數據找最大值

基本格式:select group_function(column),... from table [where condition];

首先對一個數據進行分類匯總把每一組的數據單獨的拿出來。就是對每一列數據的相同數據進行一個分組,然後在將分組後的結果再去執行select後面跟的一個分組函數的操作。
例子:

那下面這樣的怎麼操作呢?

其實就是對分組以後的結果再次進行一個限制篩選

where和Having的區別?
where是針對於整體的一個查詢結果
Having是針對於分組後的查詢結果的一個條件限制,它是不能單獨存在的,它只能夠在group by後面
下面是它的表達式:

顯示部門的最大平均薪水是多少
select max(avg(sal))
是這樣的一個嵌套

當我們查的數據存在於多個表的時候就需要多表查詢

下面是用到的表

一個是EMP的職員表、一個是DEPT的部分表

表連接的三種方式:
從總類上來看:自連接、等值連接、外連接(又可以分為三類:左連接、右連接、全連接)

自連接:一個表自己與自己建立連接成為自連接或自身連接。
在查詢的時候多表,這兩張表是同一張表,所以在查詢前我們需要對這個表進行一個別名的重命名。
舉例:查詢出員工編號、名字及其經理名字

MGR對應的是經理的ID號,這個對應的就是另一張經理表中的名字

表示比較連接列的值顯示出最終的一個結果,其查詢結果中列出被連接表中的所有列,包括其中的重復列。
查詢員工的姓名 工作 部門號 部門名稱

左連接就是返回左邊的匹配行,不考慮右邊的表是否有相應的行

(+)的意思就是dept是個匹配表,左邊是一個基礎表,基礎表優先,如果右邊這個表找不到對應的值去匹配,會自動填空

右連接就是返回右邊的匹配行,不考慮左邊的表是否有相應的行,如果沒有會自動填空

左表右表都不做限制,所有的記錄都顯示,不足的地方用null填充

FULL JOIN表示emp和dept做一個全連接
ON表示觸發條件 。

7. 資料庫筆記-SQL過濾(LIKE&正則表達式)

查詢語句:

結果:

查詢語句:

結果:

查詢語句:

結果:

查詢語句:

正則表達式 [32]1,[32]定義一組字元,它的意思是匹配 3 或匹配 2,也就是「31」或者 「21」都算是匹配的。

結果:

查詢語句:

結果:

如果要匹配特殊字元的,需要加上前導「」,「-」表示查找「-」,「.」表示查找「.」
這種就是 「轉義(escaping)」 ,在正則表達式里,本身有意義的字元,比如「.」是匹配任意字元的意思。那如果要匹配它,需要轉義。
注意:在 MySQL 里,是比其他的正則表達式多一個「」的,就是「」。

趣味提問:

如何匹配「」?
答案:「\」

\([0-9] sticks?\) 匹配的是(NUM stick)或者(NUM sticks)。s後的 ? 使得s可選。

重復元字元

* 是 0 個或多個匹配
? 是 1 個或多個匹配
{n} 是指定n個匹配
{n,} 是 不少於 n 個匹配
{n,m} 是 指定匹配的范圍,m不超過 255

查詢語句:

^值的是字元串的開始,$是字元串的結尾。

這就是 REGEXP 與 LIKE 類似,但是它獨特的好處:可以通過「定位符」只匹配「子字元串」。

結果:

8. 如何在SQL表中的性別進行check約束

1、下面打開SQL SERVER查看一下要操作的表的數據結構。

9. SQL中EXISTS怎麼用

EXISTS在SQL中的作用是:檢驗查詢是否返回數據。

select a.* from tb a where exists(select 1 from tb where name =a.name)返回真假,當 where 後面的條件成立,則列出數據,否則為空。

exists強調的是是否返回結果集,不要求知道返回什麼。比如:select name from student where sex = 'm' and mark exists(select 1 from grade where ...)

只要exists引導的子句有結果集返回,那麼exists這個條件就算成立了,大家注意返回的欄位始終為1

如果改成「select 2 from grade where ...」,那麼返回的欄位就是2,這個數字沒有意義。所以exists子句不在乎返回什麼,而是在乎是不是有結果集返回。

(9)SQL解惑筆記擴展閱讀:

Exists 方法描述如果在 Dictionary對象中指定的關鍵字存在,返回True,若不存在,返回False。

語法object.Exists(key)Exists 方法語法有如下幾部分:部分描述Object必需的。始終是一個 Dictionary對象的名字。Key必需的,在 Dictionary對象中搜索的Key值。

exist相當於存在量詞:表示集合存在,也就是集合不為空只作用一個集合.

例如 exist P表示P不空時為真; not exist P表示p為空時為真in表示一個標量和一元關系的關系。

例如:s in P表示當s與P中的某個值相等時為真; s not in P 表示s與P中的每一個值都不相等時為真。

exits與not exits

exists(sql 返回結果集為真)

not exists(sql 不返回結果集為真)

如果not exists子查詢只有自己本身的查詢條件,這樣只要子查詢中有數據返回,就證明是false,結果在整體執行就無返回值;一旦跟外面的查詢關聯上,就能准確查出數據。

10. sql查詢兩個欄位相同的記錄

EXCEL中用VBA連接ACCESS資料庫
有如下一張表,要分別查找出所有同名的人、所有同名並且學號也一樣的人以及所有同名但不同學號的人。

查詢所有同名人員
select * from [18年考試成績] where [姓名] in (SELECT [姓名] FROM [18年考試成績] group by [姓名] having count(姓名)>1)
查詢結果:

查找所有姓名和學號兩個欄位都重復的人
select * from [18年考試成績] where [姓名] in (SELECT [姓名] FROM [18年考試成績] group by [姓名] having count(姓名)>1) and [學號] in (SELECT [學號] FROM [18年考試成績] group by [學號] having count(學號)>1)
查詢結果:

查找所有姓名重復但學號不重復的人
select * from [18年考試成績] where [姓名] in (SELECT [姓名] FROM [18年考試成績] group by [姓名] having count(姓名)>1) and [學號] not in (SELECT [學號] FROM [18年考試成績] group by [學號] having count(學號)>1)
注意:要把SELECT查詢子句配合in或not in 操作符使用,SELECT查詢子句只能有一列內容。
查詢結果:

其中子句 「SELECT [姓名] FROM [18年考試成績] group by [姓名] having count(姓名)>1」是顯示所有重復的姓名,如果如下:

如果要知道重復出現次數,則可以這樣寫:
SELECT [姓名],count(姓名) as 出現次數 FROM [18年考試成績] group by [姓名] having count(姓名)>1
結果如下:

查找唯一記錄
group by [姓名],意思是按姓名分組,having count(姓名)>1 是分組條件,意思是姓名次數出現2次以上的重復內容以姓名進行分組,前面的count(姓名)是對分組以後的姓名統計出現次數。在後面要使用函數條件時應該使用having,而不是使用where
查找唯一值,比如本例的班級中,只有一個「四班」,要把這個四班的所有欄位顯示出來可以這樣:
select * from [18年考試成績] where 班級 not in (SELECT 班級 FROM [18年考試成績] group by 班級 having count(班級)>1)
結果:

如果使用「SELECT DISTINCT 班級 FROM [18年考試成績]」語句查詢唯一值,結果將會如下:

DISTINCT 會顯示不重復的值,如果有重復的,只顯示第一個,所以如果需要顯示僅出現一次的值並不適合使用SELECT DISTINCT語句
分組查詢語句:
比如要班級為單位,查詢每個班的總人數,科目總分,科目平均分等
SELECT [班級],count(姓名) as 班級人數,sum(語文) as 語文總成績,sum(數學) as 數學總成績,ROUND(avg(語文),1) as 語文平均分,ROUND(avg(數學),1) as 數學平均分 FROM [18年考試成績] group by [班級]
查詢結果如下:

注意:如果使用函數的欄位,不使用AS指定別名,將會自動生成一個欄位名,第一列名字Expr1000,第二列名為Expr1001,第三列名為Expr1002,以此類推
如:
SELECT [班級],count(姓名),sum(語文),sum(數學),ROUND(avg(語文),1) ,ROUND(avg(數學),1) FROM [18年考試成績] group by [班級]
查詢結果如下:

如果不指定別名,你將無法清楚在查詢結果中知道每一列是干什麼的。
如果需要再細分,查詢每個班女生總人數和科目平均分,只需要再加一個where條件就可以了
SELECT [班級],count(姓名) as 班級女性人數,ROUND(avg(語文),1) as 語文平均分,ROUND(avg(數學),1) as 數學平均分 FROM [18年考試成績] where 性別='女' group by [班級]