ASTRO Camp 7th
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • Write
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Versions and GitHub Sync Note Insights Sharing URL Help
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Owners
  • Owners
  • Signed-in users
  • Everyone
Owners Signed-in users Everyone
Write
Owners
  • Owners
  • Signed-in users
  • Everyone
Owners Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       owned this note    owned this note      
    Published Linked with GitHub
    Subscribed
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    Subscribe
    # 0409 Database、SQL ###### tags: `Ruby / Rails` `SQL` <!-- ## * DB Browser 使用--> - 資料庫與 rails 的關係 - 在 model 上的驗證屬於軟體層的 ( 可視為前端驗證 ) - 資料庫上的驗證屬於硬體層的 ( 可視為後段驗證 ) - 資料庫為真正寫入的地方,以管理資料庫的職位的人的意見為主,因應他的要求去 migration 處理。 - 資料庫的資料不會跟 migration 作連動,所以要 CRUD 都在 migration 裡執行 - migration 處理的是結構,而非資料 ## 資料庫簡介 [0329 資料庫簡介](https://hackmd.io/PqieyNqYQtSc4d8x-6H0vQ?view#%E8%B3%87%E6%96%99%E5%BA%AB-database) [WIKI 中文簡介](https://zh.wikipedia.org/wiki/SQL) * 一個資料庫有很多資料表 * ![](https://i.imgur.com/hCuKkqA.png =200x) * 是個框架 - 建立資料庫要指定的數據: - 欄位名稱 - 型態:[常用資料型態](http://www.eion.com.tw/Blogger/?Pid=1155) - 選項:e.g. `auto increment`、`NOT NULL`、`primary key`、`unique` - 說明 ### 資料型態 (Data Type) * VARCHAR(n) = ==VAR==iable ==CHAR==acter * 可變動的字元 #### VARCHAR vs CHAR * 兩者都是 1字元 1 位元組 (Byte) * [範例見後方題外話解釋](https://hackmd.io/19RGr-SwTOaMUmlsWYNx0g?both#CHAR-VS-VARCHAR) * 兩種型態在超過設定大小時會出錯 * VARCHAR(n) * 可變動 * 在指定的 n 個 Byte 內,依使用者輸入的內容調整儲存的大小 * 存入內容資訊後,再額外用 1 Byte 存放長度資訊 * CHAR(n) * 固定長度,不足會補空白 * 固定儲存為 n 個 Byte,輸入少於 n 的話一樣會被補到儲存大小為 n * 例: | | CHAR(10) | VARCHAR(10) | | -------- | -------- | -------- | | 存 abc |存 3 個字元+剩下 7 個字元填空白 | 只存 3 個字元+1 Byte 長度 | |存 abcdefg|存 7 個字元+3 空白|存 7 個字元+1 Byte| |較適用時機|確定長度|不確定長度| --- ### SQLite 欄位 * NN = Not Null 不能空白 * PK = Primary Key ( 主鍵 ) 識別資料用 * AI = Auto Increment 自動遞增 * U = Unique 不能允許重複值 ### Primary Key 主鍵 * 是一種 index,PK 會自動建立 index * 不能為空值(NULL) * 每個 table 只能有一個 Primary Key * 但是 primary key 可以包含多個欄位 * 每組數據有一個獨特的 primary key * 語法為 CREATETABLE tablename ( […], PRIMARY KEY (列的列表) ); * 在 Rails 裡面,默認 id 為 primary key ### Foreign Key 外部鍵 * 與其他資料表有連結的內容欄位 * 用來確認該資料表的紀錄跟被對照到的表格資料式可對應的 * 不須為獨特的存在,可以重複,也可以是 NULL - 為了資料完整性(data integrity)而建立 ### 資料表關聯 (ER model) ## SQL:結構查詢語言 Structured Query Language * SQL 不是程式語言,只是專門拿來管理資料庫用的特定語言 * 關連式資料庫 RDBMS (Relational Database Management System) * 目前常見的RDBMS有:Oracle, MSSQL, MySQL, PostgreSQL * SQLite / MSSQL為微軟專用 / MySQL / PostgreSQL * pg & SQLite 出自開源圈 * 建議在書寫時指令部分用全大寫 * 在資料庫系統中使用 `SELECT` --- ### 寫入資料: ```sql= INSERT INTO heroes (name, hero_level) VALUES ('kk','S'); ``` >輸入的內容含有單引號的話,可以加反斜線這個跳脫字元表示他是單純的字串 >```'kk\'kkkk' => 實際得到 kk'kkkk 的字串``` * Rails 指令(通常在 migration 裡執行): ```ruby= Hero.create(name: 'kk', hero_level: 'S') ``` * 寫入資料時是否按照順序?(一個蘿蔔一個坑) * 在指令中有寫欄位名稱 => 只要欄位名稱跟值有對到就好,不一定要按原始順序 * 在指令中沒指定欄位名稱 => 一定要按照原始順序,不然會出錯 --- ### 查詢資料: 1. 查詢所有資料 ```sql= SELECT * FROM heroes; --查詢 heroes 資料表中所有資料(同時顯示所有欄位) ``` - Rails 指令(通常在 controller 裡面執行): ```ruby= Hero.all ``` 2. 篩選特定欄位查詢資料 ```sql= SELECT * FROM heroes WHERE hero_level = 'S'; -- 查詢 heroes 資料表中所有 hero_level 是 S 的資料(同時顯示所有欄位) ``` - Rails 指令(通常在 controller 裡面執行): ```ruby= Hero.where(hero_level: 'S') ``` 3. 篩選特定欄位查詢資料 ```sql= SELECT * FROM heroes WHERE hero_level = 'S' AND gender = 'F'; -- 查詢 heroes 資料表中所有 hero_level 是 S 且 gender 為 F 的資料(同時顯示所有欄位) ``` - Rails 指令(通常在 controller 裡面執行): ```ruby= Hero.where(hero_level: 'S', gender: 'F') ``` ![](https://i.imgur.com/Rx8NbVS.png =x60) 4. 篩選特定欄位查詢資料 ```sql= SELECT hero_level, gender FROM heroes WHERE hero_level = 'S'; -- 查詢 heroes 資料表中 hero_level 是 S 的資料 -- 但只顯示 hero_level 跟 gender 欄位 ``` ![](https://i.imgur.com/xSHqnZ5.png =x60) - Rails 指令(通常在 controller 裡面執行): ```ruby= Hero.where(hero_level: 'S').select(:name, :gender) ``` 5. 查詢數值為 NULL 的資料 ```sql= SELECT * FROM heroes WHERE name IS NULL; ``` 6. 查詢夾帶關鍵字的資料 [0408 SQL-LIKE 語法說明](https://hackmd.io/-fgcjJmnRPioD8T76JfafA#SQL-%E8%AA%9E%E6%B3%95) ```sql= SELECT * FROM heroes WHERE name LIKE '%關鍵字%'; -- Rails 無 LIKE 寫法 ``` 7. 查詢特定數值範圍的資料 - 列出 10 到 25 歲的英雄 ```sql= SELECT * FROM heroes WHERE age >= 10 AND age <=25; -- 或是 SELECT * FROM heroes WHERE age BETWEEN 10 AND 25; ``` 8. 查詢多個條件的資料(不用同時符合) - 列出 S 級跟 A 級的英雄 ```sql= SELECT * FROM heroes WHERE hero_level = 'S' OR hero_level = 'A'; -- 寫法2 SELECT * FROM heroes WHERE hero_level IN ('S', 'A'); ``` 9. 查詢排除條件外的資料 - 列出不是 S 級的英雄 ```sql= SELECT * FROM heroes WHERE hero_level != 'S'; --寫法2 SELECT * FROM heroes WHERE hero_level <> 'S'; --寫法3 SELECT * FROM heroes WHERE NOT hero_level = 'S'; ``` - Ruby 指令 ```ruby= Hero.where.not(hero_level: 'S'); ``` 10. 查詢排除多個條件外的資料且須同時符合條件(負面表示) - 列出不是 A 級也不是 S 級的英雄 ```sql= SELECT * FROM heroes WHERE NOT hero_level = 'A' AND NOT hero_level = 'S'; ---寫法2 FROM heroes WHERE NOT hero_level NOT INT ('S', 'A'); ``` 11. 查詢符合條件數據的數量 ```sql= SELECT count(*) FROM heroes WHERE hero_level = 'S'; ``` - Rails ```ruby= Hero.where(hero_level: 'S').count Hero.count(hero_level: 'S') ``` 12. 查詢特定條件下加總的結果 - 把所有 S 級英雄的年齡加總 ```sql= SELECT SUM(age) FROM heroes WHERE hero_level = 'S'; ``` - Rails ```ruby= Hero.where(hero_level: 'S').sum(:age) ``` 13. 查詢特定條件下數值平均的結果 ```sql= SELECT AVG(age) FROM heroes WHERE hero_level = 'S'; ``` - Rails ```ruby= Hero.where(hero_level: 'S').average(:age) ``` 14. 查詢特定條件下的最小值與最大值 - 把前面的 AVG, SUM 換成 MIN, MAX 15. 混合式 分群分組 ```sql= SELECT hero_level, avg(age), max(age), min(age) -- 資料調出來的欄位名稱 FROM heroes WHERE gender = 'M' -- WHERE 放置位置很重要,放錯就錯了 GROUP BY hero_level; -- 用這個條件分門別類排 ``` 16. 挑出特定欄位不重複的資料 ```sql= SELECT DISTINCT danger_level FROM monsters; ``` 17. 排序 - 正向 ```sql= SELECT * FROM heroes WHERE hero_level ='S' ORDER BY hero_rank; ``` - 反向 ```sql= SELECT * FROM heroes WHERE hero_level ='S' ORDER BY hero_rank DESC; ``` 18. 只取特定順位的資料 ```sql= SELECT * FROM heroes WHERE hero_level ='S' ORDER BY hero_rank LIMIT 3; ``` 19. 隨機取資料 ```sql= SELECT * FROM heroes ORDER BY random() LIMIT 1; ``` 20. 子查詢 ```sql= SELECT * FROM monsters WHERE kill_by = ( SELECT id FROM heroes WHERE name = '埼玉' ); ``` 21. 子查詢外加多個條件 ```sql= SELECT * FROM monsters WHERE kill_by IN ( SELECT id FROM heroes WHERE name IN ('埼玉', '傑諾斯') ); ``` 22. 交集 Join (在結果中同時顯示兩個工作表的內容) - 用 `ON` 加條件 - inner join - 兩個都有的列出 - 把 t1 裡的資料一個一個對到 t2 裡面的資料 - 所以 John 重複執行對應到 Amy, Alice.... 之後換 Mary 一個一個對到..... - 資料會顯示在同一排中 ![](https://i.imgur.com/0a22vaN.png) ```sql= SELECT * FROM t1 INNER JOIN t2; ``` ```sql= SELECT * FROM t1 INNER JOIN t2 ON t1.username = t2.name; --加條件 ``` - left join - 左邊有的才做選取跟篩選,一筆僅對一筆 - 但左邊的東西如果對不到也會顯示出來 ![](https://i.imgur.com/Lw7LT0J.png) ```sql= SELECT * FROM t1 --左 LEFT JOIN t2 --右 ON t1.username = t2.name ``` - right join ![](https://i.imgur.com/nueTr09.png) ```sql= SELECT * FROM t1 RIGHT JOIN t2 --SQLite 沒有支援這個語法 ON t1.username = t2.name ``` - 反派是被誰打倒的 ```sql= SELECT m.name, m.danger_level, h.name FROM monsters as m LEFT JOIN heroes as h ON m.kill_by = h.id WHERE m.kill_by IS NOT NULL ``` ![](https://i.imgur.com/m5J8Zy8.png) --- ### 更新資料 1. 更新單個欄位 - 將第25號英雄的年齡改成10歲 ```sql= UPDATE heros SET age = 10 WHERE id = 25 ``` - Rails 指令(通常在 controller 裡面執行): ```ruby= Hero.find(25).update(age: 10) h = Hero.find(25) h = update(age: 10) ``` 2. 同時更新多個欄位的資料內容 ```sql= UPDATE heroes SET age = 10, hero_level = 'A', hero_rank = 5 WHERE id = 25 ``` - Rails 指令(通常在 controller 裡面執行): ```ruby= Hero.find(25).update(age: 10, hero_level: 'A', hero_rank: 5) # 寫法 2 h = Hero.find(25) h = update(age: 10, hero_level: 'A', hero_rank: 5) ``` 3. 用運算式執行更新 - 將所有英雄都加一歲! ```sql= UPDATE heroes SET age = age + 1; -- 總共找 1 次 ``` - Rails 指令(通常在 controller 裡面執行) ```ruby= Hero.all.each do |h| h.update(age: h.age + 1) end # 總共找 11 次 (包含一開始的 .all) # 或是 Hero.update_all('age = age + 1') ``` 在 rails 方法中, where 跟 update_all 後面的參數可直接書寫 SQL --- ### 刪除資料 1. 依條件刪除資料 ```sql= DELETE FROM heroes WHERE hero_level ='C' -- 將 heroes 中所有 C 級英雄都刪掉 ``` - Rails 指令(通常在 controller 裡面執行) ```ruby= Hero.where(hero_level: 'C').each do |h| h.destroy end #寫法2 Hero.destroy_all(hero_level: 'C') ``` --- ### SQLite * 檔案式資料庫 #### 建立資料庫: * 直接建立一個副檔名為 `.db` 的檔案 * 在 `DB Browser for SQLite` 程式裡面直接建立設定 * 設定時程式會自動生成資料庫語言 ### MySQL 或其他非檔案型資料庫 注意最後面的分號要加,他代表一段話的結尾 * 建立資料庫 ```sql= CREATE DATABASE name; ``` * 刪除資料庫 ```sql= DROP DATABASE awesome_name; ``` * 建立資料表語法 ```sql= CREATE TABLE heroes( id INT NOT NULL AUTO_INCREMENT, name CARCHAR(100) NOT NULL, gender CHAR(1), age INT, gero_level CHAR(1) NOT NULL, hero_rank INT, description TEXT, PRIMARY KEY (id) ) ``` --- ## 題外話 * 建立 Ruby 註解 * 在編輯器使用 `ctrl 或 command` + `/` 可以直接建立註解 * 鍵入 `=begin` (註解內容) `=end` * 不要用`"""`包住內容,這只是建立字串,Ruby 不會自動印出字串,但會執行該段原始碼 * 建議專案使用 PG 或 MySQL * 預設的資料庫為sqlite,想換其他資料庫指令輸入`rails new 檔名 -d mysql` ### database 寫入 lock 可自己找一下 ### CHAR VS. VARCHAR 範例: 建立兩個欄位 | 欄位名稱 | 資料型別 | |--------|---------| | A | VARCHAR(10)| | B | CHAR(10) | 此時 A、B 差異不大,都可以用來儲存 10 bytes 的字元; 假設 A、B 都放了 Book 字串在裡面,這時候才會可以發現差異。 對於 A 欄位來說,因為它是VARCHAR可變動字元,所以實際儲存進去只有Book四個英文字,這時候它的大小為 4 Bytes。如果字元越長,大小就會跟著變大。 但是!對於B欄位而言,CHAR 是固定字元,所以當存入 Book的字元時,它會在後面繼續補上**虛擬**的空白,把原本僅有的 4 Bytes補足到 10 Bytes。 因此在這個情境下,使用 VARCHAR 資料型比較節省空間。 所以像是龍哥舉例的欄位,由於【姓名】這樣的欄位可能放入有長有短的字串,因為有些人的姓名可能是四個字、可能更多,像是前陣子的鮭魚們。所以比較常使用VARCHAR這樣的型別,比較彈性。 另外像是【性別】欄位,我們可能可以用1=男生、2=女生、3=多元性別之類的定義,因為要存入此欄位的值是123這樣的單一數字,我們可以選擇使用CHAR型別來固定此欄位的資料大小,讓他一直都保持是1 Byte。 ### 避免發生忘記撰寫 WHERE 條件而導致資料無法挽回的情況 - 可使用以下語法 ```sql= BEGIN TRANSACTION; COMMIT; ROLLBACK; ``` 使用方式: 1. 首先執行 `BEGIN TRANSACTION` 指令,可以進入類似沙盒環境。 2. 此時可以去執行各種增刪修的動作 3. 覺得執行的動作,結果都是預期中的,那就可以執行 `COMMIT` 指令告訴資料庫,要依照剛剛下的語法執行。 4. 但發覺下錯語法的話,可以透過輸入 `ROLLBACK` 來還原所有剛剛執行的結果。 --- ### Rails 裡修改 Migration * 若執行完`$rails db:migrate`後發現有欄位名字打錯或是想刪除新增,==無法直接透過==編輯 migration 這個檔後再次執行指令`$rails db:migrate` 去覆寫,因為 `$rails db:migrate` 這個指令只會對還沒轉檔過的 Migration 檔案執行。 #### 如何判斷Migration是否執行? 專案裡`schema.rb`的檔案中,會記錄哪些 Migration 是已經被執行過的 ```ruby= ActiveRecord::Schema.define(version: 2021_04_06_131411) do create_table "books", force: :cascade do |t| t.string "title" t.text "content" t.string "contry" t.datetime "created_at", precision: 6, null: false t.datetime "updated_at", precision: 6, null: false end end ``` 也可以透過`$rails db:migrate:status`看執行狀況 ![](https://i.imgur.com/eiKnoyu.png) 其中狀態是 `up` 的表示這個 Migration 已執行過,`down` 則是尚未執行。 #### `down`的檔案修改 由於還沒有執行,可以直接在編輯器做修改,然後透過`$rails db:migrate`執行 #### `up`的檔案修改 1. 使用`$rails db:rollback`,若想一次退回 n 個步驟,使用`$rails db:rollback STEP=n` ```bash= $ rails db:rollback == 20210401061449 CreateRestaurants: reverting ================================ -- drop_table(:books) -> 0.0075s == 20210401061449 CreateRestaurants: reverted (0.0378s) ======================= ``` > ==BUT== 使用 rollback 是有風險的,因為他執行的是刪除的動作,所以那個欄位的資料也會被刪除,除非是剛建立,不然建議另外新增一個Migration 來做修正 2. 新增一個 migration `$rails g migration add_author_to_books` 並沒有強制規定命名規格,但建議命名成容易理解的方式 - 新增了一個 migration 後,進到他建立出的 migration 裡 ```=ruby class AddTitleToBook < ActiveRecord::Migration[6.1] def change add_column :books, :author, :string, default: "abc" (default為加入預設值) # add_column :資料表名稱, :要新增的欄位名稱, :資料型態, remove_column :books, :contry, :string # 刪除建議將完整的資料型態一併完成,這樣 rollback 才會知道要back的資料是什麼資料型態 end end ``` - 執行 `$rails db:migrate` 再回到`schema.rb`看就會發現,新增的欄位在底下出現,這裡的欄位順序並不影響 ```ruby= ActiveRecord::Schema.define(version: 2021_04_06_131411) do create_table "books", force: :cascade do |t| t.string "title" t.text "content" t.datetime "created_at", precision: 6, null: false t.datetime "updated_at", precision: 6, null: false t.string "author" end end ``` --- ## 示意圖 #### 查詢資料(R) - 查詢所有欄位資料 ![](https://i.imgur.com/F5NEmaP.png =400x) `*` 指所有欄位 - 加入條件:只查S級英雄 ![](https://i.imgur.com/f5USs7j.png =400x) #### 資料庫系統備份 - 在系統裡面指定固定在特定時間執行特定指令 crontab 例行性工作排程 cronjob ```shell= 分 時 日 月 星期 指令 * * * * * ls -al 1 * * * * ls -al => 每小時一分執行 10 2 * * * ls -al => 每天的 2:10 執行 10 * * * * ls -al => 每10分鐘執行 0 12 1 1,4,7,10 * ls -al =>4,7,10月的1日的12點 ``` [例行性工作排程(crontab)](http://linux.vbird.org/linux_basic/0430cron.php)

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully