亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 數(shù)據(jù)庫 > PostgreSQL > 正文

PostgreSQL實(shí)現(xiàn)一個(gè)通用標(biāo)簽系統(tǒng)

2020-01-31 15:20:54
字體:
供稿:網(wǎng)友

前言

對資源打標(biāo)簽在建站過程中是很常見的需求,有些時(shí)候我們需要給文章打標(biāo)簽,有些時(shí)候我們需要給用戶打標(biāo)簽。實(shí)現(xiàn)一個(gè)標(biāo)簽系統(tǒng)其實(shí)并不難,其本質(zhì)就是一個(gè)多對多的關(guān)系-我可以對同一篇博客打多個(gè)標(biāo)簽,同時(shí)也可以把一個(gè)標(biāo)簽打到不同的博客身上。這篇文章主要通過分析標(biāo)簽系統(tǒng)的原理,并用PostgreSQL來實(shí)現(xiàn)一個(gè)能夠?yàn)槎喾N資源打標(biāo)簽的標(biāo)簽系統(tǒng)。

1. 單一資源標(biāo)簽系統(tǒng)

先從單一資源開始,所謂單一資源便是,我們只給一種數(shù)據(jù)資源打標(biāo)簽。假設(shè)我們需要給博客文章打標(biāo)簽,那么我們需要構(gòu)建以下幾個(gè)表:

  • 文章表posts,用于存儲(chǔ)文章的基本信息。
  • 標(biāo)簽表tags,用于存儲(chǔ)標(biāo)簽的基本信息。
  • 標(biāo)簽-文章表tags_posts,存儲(chǔ)雙方的id并形成多對多的關(guān)系。

表設(shè)計(jì)圖大概是

先進(jìn)入數(shù)據(jù)庫引擎并創(chuàng)建對應(yīng)的數(shù)據(jù)庫

postgres=# create database blog;CREATE DATABASEpostgres=# /c blog;blog=#

通過SQL語句創(chuàng)建上面所提到的數(shù)據(jù)表

CREATE TABLE posts ( id    SERIAL, body   text, title   varchar(80));CREATE TABLE tags ( id    SERIAL, name   varchar(80));CREATE TABLE tags_posts ( id    SERIAL, tag_id   integer, post_id   integer);

每個(gè)表都只是包含了該資源最基礎(chǔ)的字段, 到這一步為止其實(shí)已經(jīng)構(gòu)建好了一個(gè)最簡單的標(biāo)簽系統(tǒng)了。接下來則是填充數(shù)據(jù),我的策略是添加兩篇文章,五個(gè)標(biāo)簽,給標(biāo)題為Ruby的文章打上language標(biāo)簽,給標(biāo)題為Docker的文章打上container的標(biāo)簽,兩篇文章都要打上tech標(biāo)簽

-- 填充文章數(shù)據(jù)INSERT INTO posts (body, title) VALUES ('Hello Ruby', 'Ruby');INSERT INTO posts (body, title) VALUES ('Hello Docker', 'Docker');-- 填充標(biāo)簽數(shù)據(jù)INSERT INTO tags (name) VALUES ('language');INSERT INTO tags (name) VALUES ('container');INSERT INTO tags (name) VALUES ('tech');-- 為相關(guān)資源打上標(biāo)簽INSERT INTO tags_posts (tag_id, post_id) VALUES ((SELECT id FROM tags WHERE name = 'container'), (SELECT id FROM posts WHERE title = 'Docker'));INSERT INTO tags_posts (tag_id, post_id) VALUES ((SELECT id FROM tags WHERE name = 'tech'), (SELECT id FROM posts WHERE title = 'Docker'));INSERT INTO tags_posts (tag_id, post_id) VALUES ((SELECT id FROM tags WHERE name = 'tech'), (SELECT id FROM posts WHERE title = 'Ruby'));INSERT INTO tags_posts (tag_id, post_id) VALUES ((SELECT id FROM tags WHERE name = 'language'), (SELECT id FROM posts WHERE title = 'Ruby'));

然后分別查詢兩篇文章都被打上了什么標(biāo)簽。

blog=# SELECT tags.name FROM tags, posts, tags_posts WHERE tags.id = tags_posts.tag_id AND posts.id = tags_posts.post_id AND posts.title = 'Ruby'; name---------- language tech(2 rows)blog=# SELECT tags.name FROM tags, posts, tags_posts WHERE tags.id = tags_posts.tag_id AND posts.id = tags_posts.post_id AND posts.title = 'Docker'; name----------- container tech(2 rows)

兩篇文章都被打上期望的標(biāo)簽了,相關(guān)的語句有點(diǎn)長,一般生產(chǎn)線上不會(huì)這樣直接操作數(shù)據(jù)庫。各種編程語言的社區(qū)一般都對這種數(shù)據(jù)庫操作進(jìn)行了封裝,這為編寫業(yè)務(wù)代碼帶來了不少的便利性。

2. 為多種資源打標(biāo)簽

如果只需要對一個(gè)數(shù)據(jù)表打標(biāo)簽的話,依照上面的邏輯來設(shè)計(jì)表已經(jīng)足夠了。但是現(xiàn)實(shí)世界往往沒那么簡單,假設(shè)除了要給博客文章打標(biāo)簽之外,還需要給用戶表打標(biāo)簽?zāi)??我們需要把表設(shè)計(jì)得更靈活一些。如果繼續(xù)用tags表來存標(biāo)簽數(shù)據(jù),為了給用戶打標(biāo)簽還得另外建一個(gè)名為tags_users的表來存儲(chǔ)標(biāo)簽與用戶數(shù)據(jù)之間的關(guān)系。

但更好的做法應(yīng)該是采用名為多態(tài)的設(shè)計(jì)。創(chuàng)建關(guān)聯(lián)表taggings,這個(gè)關(guān)聯(lián)表除了會(huì)存儲(chǔ)關(guān)聯(lián)的兩個(gè)id之外,還會(huì)存儲(chǔ)被打上標(biāo)簽的資源類型,我們根據(jù)類型來區(qū)分被打標(biāo)簽的到底是哪種資源,這會(huì)在每條記錄上多存了類型數(shù)據(jù),不過好處就是可以少建表,所有的標(biāo)簽關(guān)系都通過一個(gè)表來存儲(chǔ)。

Ruby比較流行的標(biāo)簽系統(tǒng)ActsAsTaggableOn 就沿用了這個(gè)設(shè)計(jì),不過它的類型字段直接存的是對應(yīng)資源的類名,或許是為了更方便編程吧,數(shù)據(jù)大概如下:

naive_development=# select id, tag_id, taggable_type, taggable_id from taggings; id | tag_id | taggable_type  | taggable_id----+--------+----------------------+------------- 1 |  1 | Refinery::Blog::Post |   1 2 |  2 | Refinery::Blog::Post |   1 3 |  3 | Refinery::Blog::Post |   1

先通過taggable_type獲取類名,然后再利用taggable_id的數(shù)據(jù)就能準(zhǔn)確獲取相關(guān)的資源了。

a. 修改原表

表設(shè)計(jì)圖大概如下

這里我不重新建表了,而直接修改原有的表,并進(jìn)行數(shù)據(jù)遷移

  • 增加type字段用于存儲(chǔ)資源類型。
  • 把原來的數(shù)據(jù)表改名為更通用的名字taggings。
  • 把原來的post_id字段改成更通用的名字taggable_id。
  • 給原有的資源填充數(shù)據(jù),type字段統(tǒng)一填數(shù)據(jù)post。
ALTER TABLE tags_posts ADD COLUMN type varchar(80);ALTER TABLE tags_posts RENAME TO taggings;ALTER TABLE taggings RENAME COLUMN post_id TO taggable_id;UPDATE taggings SET type='post';

b. 添加用戶

在給用戶打標(biāo)簽之前先創(chuàng)建用戶表,并填充數(shù)據(jù)

-- 創(chuàng)建簡單的用戶表CREATE TABLE users ( id    SERIAL, username  varchar(80), age    integer);-- 添加一個(gè)名為lan的用戶,并添加兩個(gè)相關(guān)的標(biāo)簽INSERT INTO users (username, age) values ('lan', 26);INSERT INTO tags (name) VALUES ('student');INSERT INTO tags (name) VALUES ('programmer');

c. 給用戶打標(biāo)簽

接下來需要給用戶lan打上標(biāo)簽,對原有的SQL語句做一些調(diào)整,并在打標(biāo)簽的時(shí)候把type字段填充為user。

INSERT INTO taggings (tag_id, taggable_id, type) VALUES ((SELECT id FROM tags WHERE name = 'student'), (SELECT id FROM users WHERE username = 'lan'), 'user');INSERT INTO taggings (tag_id, taggable_id, type) VALUES ((SELECT id FROM tags WHERE name = 'programmer'), (SELECT id FROM users WHERE username = 'lan'), 'user');

上述的SQL語句為用戶打上了student以及programmer兩個(gè)標(biāo)簽。

d. 查看標(biāo)簽情況

為了完成這個(gè)任務(wù)我們依然要聯(lián)合三張表進(jìn)行查詢,同時(shí)還要約束type的類型

用戶名為lan的用戶被打上的所有標(biāo)簽

blog=# SELECT tags.name FROM tags, users, taggings WHERE tags.id = taggings.tag_id AND users.id = taggings.taggable_id AND taggings.type = 'user' AND users.username = 'lan'; name------------ student programmer(2 rows)

標(biāo)題為Ruby的文章被打上的所有標(biāo)簽

blog=# SELECT tags.name FROM tags, posts, taggings WHERE tags.id = taggings.tag_id AND posts.id = taggings.taggable_id AND taggings.type = 'post' AND posts.title = 'Ruby'; name---------- language tech

OK,都跟預(yù)期一樣,現(xiàn)在的標(biāo)簽系統(tǒng)就比較通用了。

總結(jié)

本文通過PostgreSQL的基礎(chǔ)語句來構(gòu)建了一個(gè)標(biāo)簽系統(tǒng)。實(shí)現(xiàn)了一個(gè)標(biāo)簽系統(tǒng)其實(shí)并不難,各個(gè)語言的社區(qū)應(yīng)該都有相關(guān)的集成。本人也就是想拋開編程語言,從數(shù)據(jù)庫層面來剖析一個(gè)標(biāo)簽系統(tǒng)的基本原理。

PS: 另外推薦一個(gè)比較好用的Model Design工具dbdiagram,可以用文本的方式對數(shù)據(jù)表進(jìn)行設(shè)計(jì),邊設(shè)計(jì)邊預(yù)覽。最后還能以PNG,PDF甚至SQL源文件的形式導(dǎo)出。本文的數(shù)據(jù)表配圖均由用該軟件制作。

好了,以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問大家可以留言交流,謝謝大家對武林網(wǎng)的支持。

發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表

圖片精選

91在线地址| 久色视频在线观看| 日韩精品视频免费在线观看| 亚洲色图二区| 亚洲美洲欧洲综合国产一区| 国产成人avxxxxx在线看| 国产九九精品视频| 久久―日本道色综合久久| 中文乱码字幕高清一区二区| 韩日精品视频| 欧美视频完全免费看| 国产一区二区三区影视| 丁香一区二区| ady日本映画久久精品一区二区| 亚洲精品一区二区三| 精品999视频| 精品久久久久久久久久久国产字幕| 成人动漫中文字幕| 国产精欧美一区二区三区蓝颜男同| 亚洲欧美综合一区| 亚洲国产精品网站| 日韩av免费网址| 国产高清一区日本| 国产欧美婷婷中文| 国产欧美在线一区| 天天躁日日躁狠狠躁av| 亚洲成人精品女人久久久| 伊人午夜电影| 波多野结衣中文字幕一区| 天天做天天爱天天高潮| 国产精品成人无码免费| 国产精品久久久久三级| 国产中文字幕91| 黄色资源在线看| 国产网友自拍电影在线| аⅴ资源天堂资源库在线| 欧美最猛性xxxx高清| 国产精品边吃奶边做爽| 国产视频第一区| 欧美a级理论片| 奇米影视首页 狠狠色丁香婷婷久久综合| **孕交吃奶水一级毛片| 亚洲自拍小视频| 午夜久久免费观看| 国产午夜精品全部视频在线播放| 亚洲熟女综合色一区二区三区| 国产精品一区二区三区高清在线| 波多野结衣中文字幕在线播放| 免费黄色片在线观看| 成人免费视频caoporn| 国产精品久久久久精k8| 97视频热人人精品免费| 美女撒尿一区二区三区| 日本在线视频中文字幕| 亚洲精品国产精品国自| 中文字幕资源网在线观看免费| 日韩不卡在线播放| 成人影院在线视频| 一区二区三区四区视频在线| 国产成人精品国内自产拍免费看| 色婷婷国产精品久久包臀| 毛片在线导航| 亚洲香肠在线观看| 亚洲制服在线观看| 亚洲国产一区二区精品专区| 国产亚洲一区二区手机在线观看| 欧美日韩在线免费| 九九热这里只有精品6| 亚洲国产一区二区三区青草影视| 在线日韩三级| 高清av中文在线字幕观看1| www91在线观看| 最新成人av网站| 成人免费视频在线观看超级碰| 久久国产精品露脸对白| 懂色一区二区三区| 国产精品白丝jk喷水视频一区| 欧美丰满片xxx777| 亚洲污视频在线观看| 日韩av电影免费在线观看| 国产不卡的av| 中文字幕中文字幕一区| zjzjzjzjzj亚洲女人| 亚洲精品福利免费在线观看| 高潮毛片又色又爽免费| 天天干天天色天天| 久久久久久久久久久9不雅视频| 国产porn在线| 日日夜夜精品视频免费观看| 欧美激情一区二区三区四区| 青草青草久热精品视频在线网站| 2019日韩中文字幕mv| 日韩成人视屏| 亚洲免费观看高清完整| 国产无色aaa| 久久精品香蕉视频| 欧美欧美黄在线二区| 成年男人的天堂| 2025国产精品自拍| 日本中文字幕在线2020| 亚洲男女性事视频| 婷婷在线视频| 一区二区三区在线视频观看58| 国产wwwxx| 欧美精品一区在线| 成人资源在线| 熟妇人妻一区二区三区四区| 99鲁鲁精品一区二区三区| 年轻的保姆91精品| 中文字幕一区二| 日一区二区三区| 青青艹视频在线| 亚洲直播在线一区| 麻豆久久久久久久| 成av人免费青青久| 欧美日韩高清一区二区不卡| 在线观看h网址| www.日本少妇| 国产成人免费看| 欧美视频亚洲视频| 国产精品色婷婷视频| 日韩中文字幕亚洲一区二区va在线| 日本麻豆一区二区三区视频| 欧美性猛交丰臀xxxxx网站| 国产精品久久久久久久久| 亚洲欧美一区二区精品久久久| 日韩啪啪网站| 午夜精品久久久久久久久久久久久| 灌醉mj刚成年的大学平面模特| 久久九九99| 久久综合成人网| 视频一区日韩| 韩国成人一区| 午夜精品久久| 免费看日批视频| 国产传媒一区在线| 亚洲第一网中文字幕| 青青一区二区| 国产免费一区二区三区在线观看| 中文字幕国产精品| 国产精品免费无遮挡无码永久视频| 欧美一级欧美三级在线| 亚洲xxx视频| av在线播放网| 成人午夜免费av| 国产成人在线免费观看| av免费在线播放| 影音先锋中文字幕在线| 欧美黄污视频| 麻豆免费在线观看| 高清福利在线观看| 欧美亚洲动漫制服丝袜| 亚洲欧美丝袜中文综合| 欧美一区二区三区四区在线| 97在线观看免费高清视频| 不卡在线视频中文字幕| 无遮挡又爽又刺激的视频| 黑人巨大精品欧美一区二区免费| 国产精品538一区二区在线| 成人h动漫精品一区| 日韩欧美高清在线观看| 五月天亚洲综合情| 亚洲伦片免费看| www.九色在线| 色天使久久综合网天天| 99国产精品久久久久久久久久| 古装做爰无遮挡三级聊斋艳谭| 欧美精品电影在线播放| 国产极品嫩模在线观看91精品| 国产一级特黄a大片免费| 精品999在线观看| 99riav1国产精品视频| 久久久噜噜噜久噜久久综合| 国产一级特黄a大片免费| 国产精品456| 视频一区二区不卡| 中文字幕一区二区三区精彩视频| 91大神在线观看线路一区| 国产精品久久综合av爱欲tv| 免费看的av网站| 亚洲精品久久久久久久久久久| 日本中文字幕网址| 国产自产在线视频| 波多结衣在线观看| 拔插拔插海外华人免费| 黄色免费在线网站| 一卡二卡三卡在线| 狠狠狠狠狠狠狠| 中文字幕在线观看高清| 综合精品久久久| 成人永久在线| 激情欧美一区二区三区| 欧美一级午夜免费电影| 国产bdsm视频| 日漫免费在线观看网站| 97在线观看免费| 欧美高清视频在线观看| 日韩69视频在线观看| 国产精品va在线播放我和闺蜜| 国产精选第一页| 中文字幕av一区 二区| 亚洲国产aⅴ天堂久久| 国产z一区二区三区| 久久99这里只有精品| 久久久一二三| 中文字幕乱码中文乱码51精品| 国产成人99久久亚洲综合精品| 亚洲国产精品精华液网站| avav成人| 成人免费看片39| 欧美变态凌虐bdsm| 国产精品国产三级国产专区51| 欧美一区二区福利在线| 亚洲欧美日韩网站| 黄动漫在线免费观看| 久久99精品一区二区三区三区| 亚洲区综合中文字幕日日| 奇米影视狠888| 国产成人香蕉在线视频fuz| 日本精品免费| 人人澡人人添人人爽一区二区| 久久久无码中文字幕久...| 午夜在线视频免费观看| 国产精品久久免费| 国精品产品一区| 综合另类专区| 中文字幕乱码中文乱码51精品| 亚洲一区国产| 欧美极品一区二区三区| 91网址在线播放| 天天做天天摸天天爽天天爱| 亚洲va天堂va欧美ⅴa在线| 亚洲资源在线网| 伊人国产视频| 久久久久久久久久久久久久久久久久| 久久久久久久久久久一区| 操操操综合网| 天堂av网在线| 免费在线观看成人| 福利精品视频在线| 国产免费一区二区三区最新不卡| 亚洲福利视频三区| 欧美午夜在线播放| 78色国产精品| 国产精品视频成人| 成人黄动漫网站免费| 精品视频在线观看| 群体交乱之放荡娇妻一区二区| 一区二区三区四区免费视频| 国产欧美精品日韩精品| 久久免费手机视频| 亚洲先锋成人| 久久久久久久久影院| 岛国av在线| 青青青草原在线| 成 人 免费 黄 色| 美女把腿扒开让男人桶免费| 亚洲不卡1区| 可以在线看的av网站| 午夜av中文字幕| 久久九九国产精品怡红院| av色综合久久天堂av色综合在| 美女视频在线免费| 国产欧美日韩综合精品一区二区三区| 五月天精品在线| 亚洲第一在线播放| 青青影院一区二区三区四区| 18岁成年人网站| 大桥未久一区二区| 国产蜜臀av在线播放| 成人免费午夜电影| 久久久久亚洲av片无码v| 国产三级伦理在线| 日韩黄色中文字幕| 亚洲一区亚洲二区| 一区二区三区| 亚洲国产av一区二区| 久久精品一区二区三区中文字幕| 欧美日韩中文国产一区发布| 国产精品免费视频一区一| 欧美激情亚洲一区| av一本久道久久波多野结衣| 一本岛在免费一二三区| 精品久久中文| 日本午夜精品视频在线观看| 欧美a视频在线| 少妇激情av一区二区三区| 日韩成人免费在线观看| 成人少妇影院yyyy| 曰本色欧美视频在线| 日韩精品一二| 亚洲最新在线| 欧美日韩五月天| 99国产成+人+综合+亚洲欧美| 日韩av网址在线观看| 国产精品久久久久久久久久久久久久久久| 国产亚洲va综合人人澡精品| 中国女人一级毛片| 日韩av免费网址| 欧美一区二区三区成人| 狠狠人妻久久久久久| 亚洲第一福利专区| 搡的我好爽在线观看免费视频| 韩国一区二区电影| 黑粗硬大欧美视频| 国产亚洲欧美日韩俺去了| 精精国产xxxx视频在线中文版| av手机在线播放| 黄色日韩网站| 91国拍精品国产粉嫩亚洲一区| 国产精品中文字幕一区二区三区| 在线观看成人影院| 国外成人在线视频网站| 97精品视频在线| 疯狂蹂躏欧美一区二区精品| 国产一区二区福利视频| 伊是香蕉大人久久| 蜜桃视频网站在线| 91福利入口| 国产精品入口麻豆原神| 国产精品国产三级在线观看| 色先锋影音av| 波多一区二区| 欧美丰满高潮xxxx喷水动漫| а√在线中文网新版地址在线| 先锋在线亚洲| 一二三四在线观看视频| 久久免费精品日本久久中文字幕|