<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    紙飛機

      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
      22 隨筆 :: 28 文章 :: 30 評論 :: 0 Trackbacks

    問題:計算一列數字值的中間值(中間值就是一組有序元素中間成員的值)。例如,查找DEPTNO 20中工資的中間數。如下列工資:

    select sal

       from emp

    where deptno = 20

    order by sal

            SAL

    ----------

            800

           1100

           2975

           3000

           3000

    中間數為2975。

    解決方案

    除了Oracle解決方案(用函數計算中間數)之外,其他所有解決方案都是以Rozenshtein、Abramovich和Birger在Optimizing Transact-SQL: Advanced Programming Techniques (SQL Forum Press, 1997)中描述的方法為基礎的。與傳統的自聯接相比,窗口函數的引入,使解決方案更為有效。

    DB2

    使用窗口函數COUNT(*) OVER和ROW_NUMBER,查找中間數:

    1   select avg(sal)

    2     from (

    3   select sal,

    4          count(*) over() total,

    5          cast(count(*) over() as decimal)/2 mid,

    6          ceil(cast(count(*) over() as decimal)/2) next,

    7          row_number() over (order by sal) rn

    8     from emp

    9    where deptno = 20

    10          ) x

    11    where ( mod(total,2) = 0

    12            and rn in ( mid, mid+1 )

    13          )

    14       or ( mod(total,2) = 1

    15            and rn = next

    16          )

    MySQL和PostgreSQL

    使用自聯接查找中間數:

    1   select avg(sal)

    2     from (

    3   select e.sal

    4     from emp e, emp d

    5    where e.deptno = d.deptno

    6      and e.deptno = 20

    7    group by e.sal

    8   having sum(case when e.sal = d.sal then 1 else 0 end)

    9                             >= abs(sum(sign(e.sal - d.sal)))

    10          )

    Oracle

    使用函數MEDIAN(Oracle Database 10g)或PERCENTILE_CONT(Oracle9i Database):

    1 select median (sal)

    2    from emp

    3   where deptno=20

    1 select percentile_cont(0.5)

    2          within group(order by sal)

    3    from emp

    4   where deptno=20

    對于Oracle8i Database,使用DB2解決方案。對于Oracle8i Database之前的版本,可以采用PostgreSQL/MySQL解決方案。

    SQL Server

    使用窗口函數COUNT(*) OVER和ROW_NUMBER,可得到中間數:

    1   select avg(sal)

    2     from (

    3   select sal,

    4          count(*)over() total,

    5          cast(count(*)over() as decimal)/2 mid,

    6          ceiling(cast(count(*)over() as decimal)/2) next,

    7          row_number()over(order by sal) rn

    8     from emp

    9    where deptno = 20

    10          ) x

    11    where ( total%2 = 0

    12            and rn in ( mid, mid+1 )

    13          )

    14       or ( total%2 = 1

    15            and rn = next

    16          )

    討論

    DB2和SQL Server

    DB2和SQL Server 解決方案的唯一差別是語法的稍許不同:SQL Server用“%”求模,而DB2使用MOD函數;其余的都相同。內聯視圖X返回三個不同的計數值,TOTAL、MID和NEXT,還用到由ROW_NUMBER生成的RN。這些附加列有助于求解中間數。檢驗內聯視圖X的結果集,就會看到這些列表示的意義:

    select sal,

            count(*)over() total,

            cast(count(*)over() as decimal)/2 mid,

            ceil(cast(count(*)over() as decimal)/2) next,

            row_number()over(order by sal) rn

       from emp

    where deptno = 20

    SAL TOTAL   MID NEXT    RN

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

    800      5   2.5     3     1

    1100      5   2.5     3     2

    2975      5   2.5     3     3

    3000      5   2.5     3     4

    3000      5   2.5     3     5

    要得到中間數,一定要把SAL值由低到高排序。由于DEPTNO 20中的職員數是奇數,因此它的中間數就是其RN與NEXT相等的SAL(即大于職員總數除以2的最小整數)。

    如果結果集返回奇數行,WHERE子句的第一部分(第11~13行)條件不滿足。如果能夠確定結果集是奇數行,則可以簡化為:

    select avg(sal)

       from (

    select sal,

            count(*)over() total,

            ceil(cast(count(*)over() as decimal)/2) next,

            row_number()over(order by sal) rn

       from emp

    where deptno = 20

            ) x

    where rn = next

    令人遺憾的是,如果結果集包含偶數行,上述簡化的解決方案就行不通。在最初的解決方案中,采用MID列中的值處理偶數行。想想DEPTNO 30的內聯視圖X的結果會怎樣,該部門有6名職員:

    select sal,

            count(*)over() total,

            cast(count(*)over() as decimal)/2 mid,

            ceil(cast(count(*)over() as decimal)/2) next,

            row_number()over(order by sal) rn

       from emp

    where deptno = 30

    SAL TOTAL   MID NEXT    RN

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

    950      6     3     3     1

    1250      6     3     3     2

    1250      6     3     3     3

    1500      6     3     3     4

    1600      6     3     3     5

    2850      6     3     3     6

    由于返回了偶數行,則采用下述方式計算中間數:計算RN分別等于MID和MID + 1兩行的平均數。

    MySQL和PostgreSQL

    根據第一個自聯接表EMP計算中間數,而該表返回了所有工資的笛卡兒積(GROUP BY    E.SAL會去掉重復值)。HAVING子句使用函數SUM計算E.SAL等于D.SAL的次數;如果這個值大于等于E.SAL且大于D.SAL次數,那么該行就是中間數。在SELECT列表中加入SUM就可以觀察到這種情況:

    select e.sal,

            sum(case when e.sal=d.sal

                     then 1 else 0 end) as cnt1,

            abs(sum(sign(e.sal - d.sal))) as cnt2

       from emp e, emp d

    where e.deptno = d.deptno

        and e.deptno = 20

    group by e.sal

    SAL CNT1 CNT2

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

    800     1     4

    1100     1     2

    2975     1     0

    3000     4     6

    Oracle

    在Oracle Database 10g或Oracle9i Database中,可以使用Oracle提供的函數計算中間數;對于Oracle8i Database,可以采用DB2解決方案;其他版本必須采用PostgreSQL解決方案。顯然可以用MEDIAN函數計算中間值,用PERCENTILE_CONT函數也可以計算中間值就不那么顯而易見了。傳遞給PERCENTILE_CONT的值0.5是一個百分比值。子句WITHIN GROUP (ORDER BY SAL)確定PERCENTILE_CONT要搜索哪些有序行(記住,中間值就是一組已排序值的中間值)。返回的值就是搜索的有序行中符合給定百分比(在這個例子中是0.5,因為其兩個邊界值分別為0和1)的值。

    posted on 2008-05-14 21:45 紙飛機 閱讀(1236) 評論(0)  編輯  收藏 所屬分類: Database
    主站蜘蛛池模板: 亚洲国产精品尤物yw在线 | 永久免费A∨片在线观看| 亚洲国产一区在线| 久久亚洲最大成人网4438| 午夜小视频免费观看| 中文字幕看片在线a免费| 亚洲今日精彩视频| 日韩中文字幕在线免费观看| a级片免费在线观看| 亚洲午夜无码久久久久软件| 免费可以看黄的视频s色| 黄网站在线播放视频免费观看| 亚洲乱码中文字幕综合| 一个人看的免费观看日本视频www| 久久精品国产亚洲AV果冻传媒| 成**人免费一级毛片| 久久精品免费网站网| 亚洲高清有码中文字| 亚洲日韩国产精品第一页一区| 永久免费的网站在线观看| 久久国产美女免费观看精品 | 亚洲综合久久成人69| 亚洲国产精品人人做人人爽| 一本岛高清v不卡免费一三区| 一个人免费观看www视频| 亚洲 日韩经典 中文字幕 | 在线亚洲精品自拍| 久久精品a一国产成人免费网站 | 最近2019中文字幕免费直播| 美女被艹免费视频| 久久精品国产亚洲AV忘忧草18 | 亚洲日韩精品无码一区二区三区 | 免费人成网站7777视频| 67194熟妇在线永久免费观看 | 成视频年人黄网站免费视频| 精品国产麻豆免费人成网站| 男男黄GAY片免费网站WWW| 色偷偷女男人的天堂亚洲网| 精品亚洲成AV人在线观看| 亚洲精品乱码久久久久66| 免费人成视频在线观看视频|