複雜SQL的編寫要領


SQL的編碼顯得越來越重要,原因是很多邏輯處理,都可以跟sql掛鉤。 個人排斥將邏輯層代碼複雜化, 因此sql在未來的項目架構中,舉足輕重, 特地開一章節, 來總結一下以往項目中sql的精髓部分。

顯示某個店鋪的任務列表,同時把某個用戶的任務完成情況列出來。 傳入用戶的id_user值,  看看該用戶是否完成任務, 先前寫的sql如下:

<select id="listShopTask" parameterType="java.util.Map" resultMap="shopTaskResult">
SELECT
  id_shop,
  id_task,
  is_online_task,
  type_task,
  freq,
  url,
  score,
  descripe,
  title,
  time_start,
  time_end
FROM shop_task t
WHERE t.id_shop = #{id_shop}
<if test="type_task != null "> 
      AND t.type_task =#{type_task}
    </if> 
    order by time_start desc
         <if test="beginIdx != null "> 
        LIMIT ${beginIdx}, ${length}
    </if>
</select>

這個SQL是完全在一張表裏面做的, 現在要將用戶的情況加入,用戶完成一個任務,相應的積分有增加, 這個表叫做score_user表, 爲了滿足需求,sql是這樣設計的:

增加一個任務是否完成的屬性status_finish, 需記住:(Left Join是一個表,牢記這點就好):
 

SELECT
            t.id_shop,
            t.id_task,
            t.is_online_task,
            t.type_task,
            t.freq,
            t.url,
            t.score,
            t.descripe,
            t.title,
            t.time_start,
            t.time_end,
            uu.status_finish
          FROM shop_task t
               LEFT JOIN (SELECT
                         COUNT(1) AS status_finish,
                         mark, id_user,type_score, time_get
                       FROM score_user su
                       WHERE su.id_user='519006470'
                       GROUP BY su.mark) uu
              ON t.id_task = uu.mark
          WHERE t.id_shop = '50001020'
          order by time_start desc


由於Left join 存在多個數量時, 返回內容過多,需要調整一下:

SELECT
            t.id_shop,
            t.id_task,
            t.is_online_task,
            t.type_task,
            t.freq,
            t.url,
            t.score,
            t.descripe,
            t.title,
            t.time_start,
            t.time_end,
            uu.time_get,
            uu.id_user
          FROM shop_task t
               LEFT JOIN (SELECT
                         mark, id_user,type_score, time_get
                       FROM score_user su
                       WHERE su.id_user='340001477'
                       And type_score = 6
                       order by time_get desc) uu
              ON t.id_task = uu.mark
          WHERE t.id_shop = '50001020'
          order by time_start desc

由於Left join 存在多個數量時, 返回內容過多,需要調整一下:

SELECT
            t.id_shop,
            t.id_task,
            t.is_online_task,
            t.type_task,
            t.freq,
            t.url,
            t.score,
            t.descripe,
            t.title,
            t.time_start,
            t.time_end,
            uu.time_get,
            uu.id_user
          FROM shop_task t
               LEFT JOIN (SELECT
                         mark, id_user,type_score, time_get
                       FROM score_user su
                       WHERE su.id_user='519006470'
                       And type_score = 6
                       order by time_get desc
                       limit 0,1) uu
              ON t.id_task = uu.mark
          WHERE t.id_shop = '50001020'
          order by time_start desc

limit將導致內容過少… ⊙﹏⊙b汗!

SELECT
            mark, id_user,type_score, time_get
            FROM score_user su
            WHERE su.id_user='519006470'
            And type_score = 6
            order by time_get desc

OK終於可以搞定,Group是個很強大的語法。

SELECT
            mark, id_user, type_score, MAX(time_get)
            FROM score_user su
            WHERE id_user='519006470'
            AND type_score = 6
            GROUP BY mark

結合以上,我們的結論是:
SELECT
            t.id_shop,
            t.id_task,
            t.is_online_task,
            t.type_task,
            t.freq,
            t.url,
            t.score,
            t.descripe,
            t.title,
            t.time_start,
            t.time_end,
            uu.last_time,
            uu.id_user
          FROM shop_task t
               LEFT JOIN (SELECT
          mark, id_user, type_score, MAX(time_get) AS last_time
          FROM score_user su
          WHERE id_user='519006470'
          AND type_score = 6
          GROUP BY mark) uu
              ON t.id_task = uu.mark
          WHERE t.id_shop = '50001020'
          ORDER BY time_start DESC



總結:

1. Left Joion即增加一個表

2. 去掉笛卡爾常量的方法, 加限定詞:  max, group by等







發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章