הבלוג של גרי רשף

06/02/2011

המרה בין ערכים דצימליים והקסדצימלים ומיון ערכים מספריים

Filed under: Uncategorized — תגיות: , , , , , , , — גרי רשף @ 17:10

מעולם לא הזדקקתי לבסיס הספירה ההקסדצימלי בסופרמרקט או בחדר הכושר, אבל יוצא לי להיתקל בו פה ושם בטבלאות מערכת, ומכיוון שאין לדעת אל נכון מתי אזדקק לשירותיו- אני כבר מקדים רפואה למכה..

להלן דוגמה מדורגת כיצד מתרגמים 500 לערך הקס דצימלי:

With T As

(Select 500 [Decimal],

        Cast(500 As Varbinary(Max)) [Hexadecimal As Varbinary],

        master.dbo.FN_VarbinToHexStr(Cast(500 As Varbinary(Max))) [Hexadecimal As Varchar],

        Stuff(master.dbo.FN_VarbinToHexStr(Cast(500 As Varbinary(Max))),1,2,'')

        [Hexadecimal without 0x])

Select  *,

        Stuff([Hexadecimal without 0x],1,PatIndex('%[^0]%',[Hexadecimal without 0x])-1,'') [Hexadecimal without leading '0']

From T;

clip_image002

העמודה הראשונה משמאל מציגה את הערך 500,

השניה את התרגום שלו ל-Varbinary המהווה הצגה הקסדצימלית,

השלישית מעבר ל-Varchar רגיל שניתן לנקות ולסדר בעזרת FN_VarbinToHexStr (פונקציית מערכת לא מתועדת),

הרביעית ללא ה-"0x" שבהתחלה,

והחמישית ללא האפסים המובילים (PatIndex מוצאת את התו הראשון שאינו 0, ואת כל האפסים שלפניו מנקים בעזרת Stuff).

לבדיקה- התוצאה 1f4 שווה:

1*162+15*161+4*160=500

השליפה הנ"ל מעט מורכבת כי ניקוי האפסים המובילים מצריך פניה כפולה לערך שלפניו והיה מיותר "לשתול" פעמיים את הביטוי המורכב של העמודה הרביעית בתוך החישוב של ה-PatIndex & Stuff.

לתרגול- נשלוף את מספרי האובייקטים מתוך sys.objects ונתרגם אותם להקסדצימלית:

With T As

(Select object_id,

        Stuff(master.dbo.FN_VarbinToHexStr(Cast(object_id As Varbinary(Max))),1,2,'') oi_hex

From sys.objects),

T1 As

(Select object_id,

        Stuff(oi_hex,1,PatIndex('%[^0]%',oi_hex)-1,'') Hx

From T)

Select *

From T1;

clip_image004

מה בכיוון ההפוך?

קצת יותר מורכב מכיוון שלא מצאתי פונקציה קיימת שעושה זאת, ולכן אין ברירה אלא לכתוב פונקציה כזו שעוברת בלולאה על כל התווים וסוכמת את מכפלתם בחזקה המתאימה של 16 (כפי שעשיתי בבדיקה של 1f4), או להשתמש בטבלת מספרים שמאפשרת גישה לכל אחד מהתווים וביצוע Group By & Sum.

נשלח לטבלה זמנית את הערכים ההקסדצימליים שהתקבלו קודם, ונשלוף אותם תוך תרגומם לערכים דצימליים כפי שתיארתי:

With N As

(Select 1 I

Union All

Select  I+1

From    N

Where   I<100)

Select  Hx,

        Sum(Case Substring(Reverse(Hx),I,1) When 'a' Then 10

                                            When 'b' Then 11

                                            When 'c' Then 12

                                            When 'd' Then 13

                                            When 'e' Then 14

                                            When 'f' Then 15

                                            Else Cast(Substring(Reverse(Hx),I,1) As Int)

                                            End*Power(16,I-1)) [Int]

From    #T

Inner Join N

        On N.I<=Len(#T.Hx)

Group By Hx

Order By Int;

clip_image006

לסיום- כיצד ממיינים את הערכים?

בדוגמה הנ"ל מיינתי את הערכים המתורגמים, אלא שנשאלת השאלה אם ניתן למיינם ללא תירגום: הרי "סתם" מיון יהיה טקסטואלי ושגוי:

Select  *

From    #T

Order By Hx;

clip_image008

אפשר לראות שהערך 19 מופיע אחרי 18d6a699 שגדול ממנו בהרבה בדיוק כשם שהמלה "שי" מופיעה במילון אחרי "אקליפטוס", וזו בעייה שנתקלים בה לא פעם עם ערכים מספריים הנשמרים בעמודות טקסט (למשל- תעודות זהות).

פתרון פשוט לבעייה יכול להיות מיון ראשוני לפי אורך המחרוזת, ומשני לפי המחרוזת עצמה; וכך המחרוזות הקצרות יופיעו ראשונות והארוכות בסוף:

Select  *

From    #T

Order By Len(Hx),

        Hx;

clip_image010

מודעות פרסומת

להגיב »

עדיין אין תגובות.

RSS feed for comments on this post. TrackBack URI

להשאיר תגובה

הזינו את פרטיכם בטופס, או לחצו על אחד מהאייקונים כדי להשתמש בחשבון קיים:

הלוגו של WordPress.com

אתה מגיב באמצעות חשבון WordPress.com שלך. לצאת מהמערכת / לשנות )

תמונת Twitter

אתה מגיב באמצעות חשבון Twitter שלך. לצאת מהמערכת / לשנות )

תמונת Facebook

אתה מגיב באמצעות חשבון Facebook שלך. לצאת מהמערכת / לשנות )

תמונת גוגל פלוס

אתה מגיב באמצעות חשבון Google+ שלך. לצאת מהמערכת / לשנות )

מתחבר ל-%s

יצירה של אתר חינמי או בלוג ב־WordPress.com.

%d בלוגרים אהבו את זה: