SQL開源替代品,誕生了!
| sales_amount | 銷售業(yè)績表 |
| sales | 銷售員姓名,假定無重名 |
| product | 銷售的產(chǎn)品 |
| amount | 該銷售員在該產(chǎn)品上的銷售額 |
現(xiàn)在我們想知道出空調(diào)和電視銷售額都在前 10 名的銷售員名單。
1. 按空調(diào)銷售額排序,找出前 10 名;
2. 按電視銷售額排序,找出前 10 名;
select * from( select top 10 sales from sales_amount where product='AC' order by amount desc )intersect( select top 10 sales from sales_amount where product='TV' order by amount desc )
with A asselect top 10 sales from sales_amount where product='AC' order by amount descB asselect top 10 sales from sales_amount where product='TV' order by amount descselect * from A intersect B
句子沒有更短,但分步后思路確實變清晰了。
1. 列出所有產(chǎn)品;
2.將每種產(chǎn)品的前 10 名取出,分別保存;
1.將數(shù)據(jù)按產(chǎn)品分組,將每組排序,取出前 10 名;
select salesfrom ( select sales,from ( select sales,rank() over (partition by product order by amount desc ) rankingfrom sales_amount)where ranking <=10 )group by saleshaving count(*)=(select count(distinct product) from sales_amount)
這是能寫出來,但這樣復(fù)雜的 SQL,有多少人會寫呢?
雖然 SQL 有集合概念,但并未把集合作為一種基礎(chǔ)數(shù)據(jù)類型提供,不能讓變量或字段的取值是個集合,除了表之外也沒有其它集合形式的數(shù)據(jù)類型,這使得大量集合運算在思維和書寫時都需要繞路。
select salesfrom ( select A.sales sales, A.product product,(select count(*)+1 from sales_amountwhere A.product=product AND A.amount<=amount) rankingfrom sales_amount A )where product='AC' AND ranking<=10
select salesfrom ( select A.sales sales, A.product product, count(*)+1 rankingfrom sales_amount A, sales_amount Bwhere A.sales=B.sales and A.product=B.product AND A.amount<=B.amountgroup by A.sales,A.product )where product='AC' AND ranking<=10
這樣的 SQL 語句,專業(yè)程序員寫出來也未必容易吧!而僅僅是計算了一個前 10 名。
| employee | 員工表 |
| name | 員工姓名,假定無重名 |
| gender | 員工性別 |
我們已經(jīng)計算出“好”銷售員的名單,比較自然的想法,是用名單到花名冊時找出其性別,再計一下數(shù)。但在 SQL 中要跨表獲得信息需要用表間連接,這樣,接著最初的結(jié)果,SQL 就會寫成:
select employee.gender,count(*)from employee,( ( select top 10 sales from sales_amount where product='AC' order by amount desc )intersect( select top 10 sales from sales_amount where product='TV' order by amount desc ) ) Awhere A.sales=employee.namegroup by employee.gender
select sales.gender,count(*)from (…) // …是前面計算“好”銷售員的SQLgroup by sales.gender
顯然,這個句子不僅更清晰,同時計算效率也會更高(沒有連接計算)。
mov ax,3mov bx,5mul bx,7add ax,bx
這樣的代碼無論書寫還是閱讀都遠不如 3+5*7 了(要是碰到小數(shù)就更要命了)。雖然對于熟練的程序員也算不了太大的麻煩,但對于大多數(shù)人而言,這種寫法還是過于晦澀難懂了,從這個意義上講,F(xiàn)ORTRAN 確實是個偉大的發(fā)明。
這些問題本身應(yīng)該也算不上很復(fù)雜,都是在日常數(shù)據(jù)分析中經(jīng)常會出現(xiàn)的,但已經(jīng)很難為 SQL 了。
集合無序
select name, birthdayfrom (select name, birthday, row_number() over (order by birthday) rankingfrom employee )where ranking=(select floor((count(*)+1)/2) from employee)
select max (consecutive_day)from (select count(*) (consecutive_dayfrom (select sum(rise_mark) over(order by trade_date) days_no_gainfrom (select trade_date,case whenclosing_price>lag(closing_price) over(order by trade_date)then 0 else 1 END rise_markfrom stock_price) )group by days_no_gain)
集合化不徹底
select * from employeewhere to_char (birthday, ‘MMDD’) in( select to_char(birthday, 'MMDD') from employeegroup by to_char(birthday, 'MMDD')having count(*)>1 )
select namefrom (select namefrom (select name,rank() over(partition by subject order by score DESC) rankingfrom score_table)where ranking<=10)group by namehaving count(*)=(select count(distinct subject) from score_table)
缺乏對象引用
select A.*from employee A, department B, employee Cwhere A.department=B.department and B.manager=C.name andA.gender='male' and C.gender='female'
select * from employeewhere gender='male' and department in(select department from departmentwhere manager in(select name from employee where gender='female'))
where gender='male' and department.manager.gender='female'
select name, company, first_companyfrom (select employee.name name, resume.company company,row_number() over(partition by resume. nameorder by resume.start_date) work_seqfrom employee, resume where employee.name = resume.name)where work_seq=1
select name,(select company from resumewhere name=A.name andstart date=(select min(start_date) from resumewhere name=A.name)) first_companyfrom employee A
| A | |
| 1 | =employee.sort(birthday) |
| 2 | =A1((A1.len()+1)/2) |
對于以有序集合為基礎(chǔ)的 SPL 來說,按位置取值是個很簡單的任務(wù)。
任務(wù) 2
| A | |
| 1 | =stock_price.sort(trade_date) |
| 2 | =0 |
| 3 | =A1.max(A2=if(close_price>close_price[-1],A2+1,0)) |
SPL 按自然的思路過程編寫計算代碼即可。
任務(wù) 3
| A | |
| 1 | =employee.group(month(birthday),day(birthday)) |
| 2 | =A1.select(~.len()>1).conj() |
SPL 可以保存分組結(jié)果集,繼續(xù)處理就和常規(guī)集合一樣。
任務(wù) 4
| A | |
| 1 | =score_table.group(subject) |
| 2 | =A1.(~.rank(score).pselect@a(~<=10)) |
| 3 | =A1.(~(A2(#)).(name)).isect() |
使用 SPL 只要按思路過程寫出計算代碼即可。
任務(wù) 5
| A | |
| 1 | =employee.select(gender=="male" && department.manager.gender=="female") |
支持對象引用的 SPL 可以簡單地將外鍵指向記錄的字段當作自己的屬性訪問。
任務(wù) 6
| A | |
| 1 | =employee.new(name,resume.minp(start_date).company:first_company) |
SPL 支持將子表集合作為主表字段,就如同訪問其它字段一樣,子表無需重復(fù)計算。
…Class.forName("com.esproc.jdbc.InternalDriver");Connection conn =DriverManager.getConnection("jdbc:esproc:local://");Statement st = connection.();CallableStatement st = conn.prepareCall("{call xxxx(?,?)}");3000);5000);ResultSet result=st.execute();...
GitHub:https://github.com/SPLWare/esProc
