1. 程式人生 > >使用位運算,處理資料庫中的"多選狀態標識"

使用位運算,處理資料庫中的"多選狀態標識"

  • 引言【摘自其他文章】:   

     最近在對公司以前的一個專案進行調整時發現,資料庫中有很多表示“多選狀態標識”的欄位。“多選狀態標識”可能描述的並不十分準確,在這裡用我們專案中的幾個例子進行說明一下。
      例一:表示某個商家是否支援多種會員卡打折(如有金卡、銀卡、其他卡等),專案中的以往的做法是:在每條商家記錄中為每種會員卡建立一個標誌位欄位。如圖:


 
      其中藍色區域的三個整形欄位分別表示三種會員卡。當值為“1”時表示當前商家支援這種會員卡打折,反之“0”則表示不支援。
 
      例二:表示系統字典表中某種型別方式,會在哪個功能模組中呼叫。如某種“支付方式”可能在“收銀模組”中會用到,在“結算模組”中也會用到。如圖:


      用多欄位來表示“多選標識”存在一定的缺點:首先這種設定方式很明顯不符合資料庫設計第一正規化,增加了資料冗餘和儲存空間。再者,當業務發生變化時,不利於靈活調整。比如,增加了一種新的會員卡型別時,需要在資料表中增加一個新的欄位,以適應需求的變化。
 
      因此,我們在重新審視資料庫設計時,我的一位同事提出了一種代替方式:將多個狀態標識欄位合併成一個欄位,並把這個欄位改成字串型,對多選狀態值以字串陣列的方式儲存(一個以逗號分隔的字串:“1,2,3”)。表的結構變成如下:

 

     “MEMBERCARD”欄位中,當存在“1”時表示支援金卡打折,“2”時表示支援銀卡打折,“3”表示支援其他卡打折。
      這樣調整的好處,不僅消除相同欄位的冗餘,而且當增加新的會員卡類別時,不需增加新的欄位。但帶來新的問題:在資料查詢時,需要對字串進行分隔。並且字串型別的欄位在查詢效率和儲存空間上不如整型欄位。
 
      總的來說,上面調整的思路是正確的,但不夠自然。我後來考慮了一下,覺得可以用“位”來解決這個問題:二進位制的“位”本來就有表示狀態的作用。可以用下面各個位來分別表示不同種類的會員卡打折支援:


 
      這樣,“MEMBERCARD”欄位仍採用整型。當某個商家支援金卡打折時,則儲存“1(0001)”,支援銀卡時,則儲存“2(0010)”,兩種都支援,則儲存“3(0011)”。其他類似。表結構如圖:

 

我們在編寫SQL語句時,只需要通過“位”的與運算,就能簡單的查詢出想要資料:

  1. //查詢支援金卡打折的商家資訊:
  2. select * from factory where MEMBERCARD & b'0001'
  3. 或者:  
  4. select * from factory where MEMBERCARD & 1
  5. //查詢支援銀卡打折的商家資訊:
  6. select * from factory where MEMBERCARD & b'0010'
  7. 或者:  
  8. Select * from factory where MEMBERCARD & 2

      通過這樣的處理方式既節省儲存空間,查詢時又簡單方便。以上sql語句為MySQL的語法,其他資料庫方法類似。並且“b'0010'”二進位制的表示方式的語法是在5.0以後的版本才有。

  • 實際操作【實戰一把】: 
  1. CREATE TABLE `news`(
  2. `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主鍵ID',
  3. `title` varchar(20) NOT NULL COMMENT '文章標題',
  4. `status` int(2) NOT NULL COMMENT '狀態 1:是否置頂;2:是否點贊;4:是否推薦',
  5. PRIMARY KEY (`id`)
  6. ) ENGINE=MyISAM AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;


資料表的原始資料: 

  1. 【更新】status =置頂;
  2. update news set status = status |1 where id =1
  3. 【更新】status =點贊; update news set status = status | 2 where id = 1
  4. 【更新】status =推薦; update news set status = status | 4 where id = 2


  1. 【選擇】status =推薦;
  2. select *from news where status &4=4

  1. 【選擇】status =置頂&推薦&點贊;;
  2. select *from news where status &7=7
  3. 【選擇】status =置頂&推薦;
  4. select *from news where status &3=3
  5. 【選擇】status =不置頂&不推薦;
  6. select *from news where status &1!=1and status &4!=4
  1. 【選擇】status =不置頂|不點贊;
  2. select *from news where status &1!=1or status &2!=2


  1. 【更新某記錄】status =推薦,為不推薦;
  2. update news set status = status ^4 where id =1
更新前:
更新後:

 
  • 後記【位運算】:

按位與運算

  1. 按位與運算子"&"是雙目運算子。
  2. 其功能是參與運算的兩數各對應的二進位相與。只有對應的兩個二進位均為1時,結果位才為1,否則為0
  3. 參與運算的數以補碼方式出現。
  4. 例如:9&5可寫算式如下:
  5. 00001001(9的二進位制補碼)
  6. &00000101(5的二進位制補碼)
  7. 00000001(1的二進位制補碼)
  8. 可見9&5=1
  9. 按位與運算通常用來對某些位清0或保留某些位。
  10. 例如把a 的高八位清0,保留低八位,可作a&255運算(255的二進位制數為0000000011111111)。

按位或運算

  1. 按位或運算子“|”是雙目運算子。其功能是參與運算的兩數各對應的二進位相或。
  2. 只要對應的二個二進位有一個為1時,結果位就為1。參與運算的兩個數均以補碼出現。
  3. 例如:9|5可寫算式如下:
  4. 00001001
  5. |00000101
  6. 00001101(十進位制為13)
  7. 可見9|5=13

按位異或運算

  1. 按位異或運算子“^”是雙目運算子。其功能是參與運算的兩數各對應的二進位相異或,當兩對應的二進位相異時,結果為1
  2. 參與運算數仍以補碼出現,
  3. 例如9^5可寫成算式如下:
  4. 00001001
  5. ^00000101
  6. 00001100(十進位制為12)

求反運算

  1. 求反運算子~為單目運算子,具有右結合性。
  2. 其功能是對參與運算的數的各二進位按位求反。
  3. 例如~9的運算為:
  4. ~(0000000000001001)
  5. 結果為:1111111111110110

左移運算

  1. 左移運算子“<<”是雙目運算子。其功能把“<<”左邊的運算數的各二進位全部左移若干位,由“<<”右邊的數指定移動的位數,高位丟棄,低位補0
  2. 例如:
  3. a<<4
  4. 指把a的各二進位向左移動4位。
  5. a=00000011(十進位制3),左移4位後為00110000(十進位制48)。

右移運算

  1. 右移運算子“>>”是雙目運算子。
  2. 其功能是把“>>”左邊的運算數的各二進位全部右移若干位,“>>”右邊的數指定移動的位數。
  3. 例如:
  4. a=15
  5. a>>2
  6. 表示把000001111右移為00000011(十進位制3)。



注意:對於有符號數,在右移時,符號位將隨同移動。當為正數時,最高位補0,而為負數時,符號位為1,

         最高位是補0或是補1 取決於編譯系統的規定。Turbo C和很多系統規定為補1

相關推薦

使用運算處理資料庫的"狀態標識"

引言【摘自其他文章】:         最近在對公司以前的一個專案進行調整時發現,資料庫中有很多表示“多選狀態標識”的欄位。“多選狀態標識”可能描述的並不十分準確,在這裡用我們專案中的幾個例子進行說明一下。       例一:表示某個商家是否支援多種會員卡打折(如有金卡

運算處理前臺

scrip sin 分隔 sel 但是 接下來 條件 記錄 讀書 前言: 本周,公司有個需求,需要對前臺一個多選值進行存儲,實現過程中,想過三種方案,在這裏記錄下。 方案一(使用多個布爾值):   在最開始,多選值只有兩個,就打算用兩個布爾值分開存儲的,實現和使用都很

SQL 一個使用者表有一個積分欄假如資料庫有100萬個使用者若要在每年第一天凌晨將積分清零你將考慮什麼你將想什麼辦法解決?

                    alter table drop column score;                   alter table add colunm score int;                   可能會很快,但是需要試驗,試驗

iOS藍牙通信數據處理運算數據的大小端轉換

make 位數 存儲 大小端模式 計算 取出 sign nsstring nta 目的 轉載自:http://blog.csdn.net/remember_17/article/details/77337534?locationNum=10&fps=1 在藍牙項目的

http協議阻塞IO,非阻塞IO,IO路複用運算select方法

HTTP請求   Request 請求格式: 請求行       GET          /         HTTP/1.1  請求種類  

python讀取xml資料庫中表內所有資料獲取資料庫所有表的欄名稱

工作中需要讀取指定xml資料庫中的資料以及 表所需欄位名,所以在已有例子中改進實現: xml 資料庫 xmldabase.xml: <database> <manifest> <pair key="schema_major_vsn" v

【小家java】Java二進位制與運算(“^,&,>>,>>>”)使用移位演算法寫一個流水號生成器(訂單號生成器)

相關閱讀 每篇一句 高樓大廈,都是平地起的。 整個java體系,其實就是一本祕籍,那就是:java基礎! (基礎如果打的紮實,在實際開發工作中會帶來極大的助益) 二進位制 二進位制是計算技術中廣泛採用的一種數制。二進位制資料是用0和1兩個數碼來表示的

使用github作為maven倉庫存放發布自己的jar包依賴 實現個項目公共部分代碼的集中避免團隊個項目之間代碼的復制粘貼

地址 oba post 直接 bubuko http tps hub 之間 使用github作為maven倉庫存放發布自己的jar包依賴 實現多個項目公共部分代碼的集中,避免團隊中多個項目之間代碼的復制粘貼。 1、首先在本地maven位置的配置文件setting.xml(沒

zabbix監控添加主機添加模板處理圖形的亂碼自動發現

zabbix添加主機 添加模板 處理圖形中亂碼 自動發現 添加主機 優先添加主機群組,配置-添加主機群組主機-添加主機-群組-選擇剛剛創建的 群組,ip地址填寫客戶端IP, 添加自定義模板, 模板-添加-創建主機名-添加到組添加一個模板名稱aming 在模板下選擇一個想要監控的的項目,復制過來

主動模式和被動模式添加監控主機添加自定義模板處理圖形的亂碼自動發現

zabbix主動模式和被動模式 主動或者被動是相對客戶端來講的被動模式,服務端會主動連接客戶端獲取監控項目數據,客戶端被動地接受連接,並把監控信息傳遞給服務端主動模式,客戶端會主動把監控數據匯報給服務端,服務端只負責接收即可。當客戶端數量非常多時,建議使用主動模式,這樣可以降低服務端的壓力。服務端有公網ip,

VS2013 c++連結資料庫應用儲存過程資料庫寫入資料

// ConsoleApplication1.cpp : 定義控制檯應用程式的入口點。 // #include "stdafx.h" #include "iomanip" using namespace std; #import "c:\Program Files\Common Files\S

JDBC上關於資料庫表操作一對關係和關係的實現方法--轉

  原文地址---- https://www.cnblogs.com/pangguoming/p/7028322.html 黑馬程式設計師 我們知道,在設計一個Java bean的時候,要把這些BEAN 的資料存放在資料庫中的表結構,然而這些資料庫中的表直接又有些特殊

C# WPF DataGrid使用包括隔行

C# WPF DataGrid使用,包括隔行多選 xaml cs xaml <ScrollViewer VerticalAlignment="Stretch" x:Name="scro

以單例模式為例在Idea執行緒debug

我們以單例模式的懶漢式在idea中進行多執行緒debug 一是可以學習多執行緒debug,二是可以瞭解懶漢式的執行緒不安全的原因 首先我們建立一個單例懶漢式,然後建立兩個執行緒 程式碼如下:   然後 進行多執行緒debug,來干預懶漢式的執行順序

運算自低(右)向高(左)逐個地將數位1轉置為0

對任意整數n,不妨設其最低(右)的數位對應2^k,於是n的二進位制展開應該如下:           x   x   ...   x  1 0 0 ...  0  其中最右邊第一次1出現時,數位x可能是0或1,而最低的k+1位必然是“1 0 0  ... 0” ,即數位1

SQL的where條件資料庫提取與應用淺析

1        問題描述 一條SQL,在資料庫中是如何執行的呢?相信很多人都會對這個問題比較感興趣。當然,要完整描述一條SQL在資料庫中的生命週期,這是一個非常巨大的問題,涵蓋了SQL的詞法解析、語法解析、許可權檢查、查詢優化、SQL執行等一系列的步驟,簡短的篇幅是絕對無

關於c語言的運算&|^(看懂漢字的都能看懂)

其中|,&可以當作邏輯運算子,當|,&當成邏輯運算子時,與||,&&的用法基本相似,&&,||運算時會當前面的表示式能夠決定整個表示式,則不進行對後面的判斷,如:1&&1,1||0,當表示式前面的已經決定了整個表

轉: SQL的where條件資料庫提取與應用淺析

SQL中的where條件,在資料庫中提取與應用淺析 http://hedengcheng.com/?p=577 1問題描述   一條SQL,在資料庫中是如何執行的呢?相信很多人都會對這個問題比較感興趣。當然,要完整描述一條SQL在資料庫中的生命週期,這是一個非常巨大的問題, 涵蓋了SQL的詞法解析、語

bzoj3832[Poi2014]Rally(setbitset運算拓撲排序線段樹)

傳送門:https://www.lydsy.com/JudgeOnline/problem.php?id=3832 Description 給定一個N個點M條邊的有向無環圖,每條邊長度都是1。 請找到一個點,使得刪掉這個點後剩餘的圖中的最長路徑最短。 Input 第一行包含兩個正

Codeforces Round #312 (Div. 2) (第三題是運算好題)

分析:從0座標分開,負半軸一個數組,正半軸一個數組,來記錄果樹的左邊和數量,可以用結構體陣列來儲存資料,其中少的一個半軸上的果樹肯定會全被採光,而多的一邊樹上會多采一棵樹。 struct p{ int num,x; } p neg[105],pos[105];這樣表