{"id":330,"date":"2007-12-10T00:00:00","date_gmt":"2007-12-10T00:00:00","guid":{"rendered":"https:\/\/test.simple-talk.com\/uncategorized\/numeral-systems-and-numbers-conversion-in-sql\/"},"modified":"2021-09-29T16:22:14","modified_gmt":"2021-09-29T16:22:14","slug":"numeral-systems-and-numbers-conversion-in-sql","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/databases\/sql-server\/t-sql-programming-sql-server\/numeral-systems-and-numbers-conversion-in-sql\/","title":{"rendered":"Numeral Systems and Numbers Conversion in SQL"},"content":{"rendered":"<div id=\"pretty\">\n<p>My fascination with\u00a0numbers started\u00a0when I was about two years old.<\/p>\n<p>One of my parents used to bend my fingers, saying &#8220;One, Two, Three&#8230;&#8221; and all our guests smiled, when I\u00a0 tried to repeat &#8220;Four, Five, Six&#8230;&#8221;<\/p>\n<p>At that time, I believed that people need the numbers in order to count their fingers and to make their parents and relatives laugh.<\/p>\n<p>When I grew up, I discovered that numbers could be helpful in a few more situations, for example to identify time and count money. However, I did not pay much attention to the fact that the counting rules for time and money are different.<\/p>\n<p>In one day, among the old documents, stored in our family, I found my grandfather&#8217;s watch. The watch had a beautiful watch face with strange symbols on it, instead of numbers. My mother told me that these symbols are the Roman numbers.<\/p>\n<p>That fact, however, did not make me curious about the Roman numbers. In my mind, they were associated with the old, broken watch &#8211; both, the numbers and the watch were not in use.<\/p>\n<p>I got my first hints of other numeral system\u00a0at university.<\/p>\n<p>The computers were built of transistors &#8211; small electronic devices with two physical states: opened and closed. These states, being coded as 0 and 1, perfectly fitted into binary numeral system. Based on that system and supported by the powerful mathematical apparatus, the computers changed human life.<\/p>\n<p>If you carefully look around, you will find many signs of different numeral systems. Some of them are not relevant anymore; the other ones we still use and develop. Time, and angles, for example, are still\u00a0based on sexagesimal systems.<\/p>\n<p>This article is about the numeral systems. It will also demonstrate interesting SQL techniques that can be used, when you need to convert the numbers from one numeral system to another.<\/p>\n<h3>A Brief History of Numeral Systems<\/h3>\n<p>The numbers and numeral systems are very old. The simple counting systems appeared when people started to develop speech, but even before, the first primitive people had notion of counting and could enumerate similar objects, using their fingers, pabbles, knotted roups or notches on sticks or bones.<\/p>\n<p>When alphabets and written languages appeared, the simple counting systems transformed into quite complicated ways of writing numbers.<\/p>\n<p>About 3000 &#8211; 3500 B.C,. number systems have developed spontaneously in different isolated cultures and so almost each civilization created its own language and numeral system.<\/p>\n<p>There is no an official classification of the numeral systems. However, many researchers (especially a French mathematician Genevi\u00e8ve Guitel in her &#8220;Compared History of written numerations&#8221;, 1975) agree that written numeral systems should be divided into two main groups &#8211; additive and positional.<\/p>\n<p>Georges Ifrah in his important work &#8220;The Universal History of Numbers: From Prehistory to the Invention of the Computer&#8221; gives more detailed classification of the numeral systems:<\/p>\n<ul>\n<li>Additive systems<\/li>\n<li>Hybrid systems<\/li>\n<li>Positional systems<\/li>\n<\/ul>\n<p>Let us take a closer look at these numeral systems.<\/p>\n<p><b>1. Additive numeral systems<\/b><\/p>\n<p>Additive numeral systems use principle of addition.<\/p>\n<p>Any number in that system can be represented by the combination of symbols, where each symbol has its own value independent of position. The sum of the values of all the symbols gives the value of whole number.<\/p>\n<p>There are three types of additive numeral systems.<\/p>\n<p><b><u>The additive systems of Type 1<\/u><\/b> have separate symbol for 1 and for each power of 10 (or 20). The example of such a system would be Egyptian hieroglyphic system (see Fig.1):<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/458-Egyptian1.jpg\" alt=\"458-Egyptian1.jpg\" width=\"280\" height=\"98\" \/><\/p>\n<p><b>Fig.1 Egyptian Hieroglyphic System (Additive numeral systems of Type 1)<\/b><\/p>\n<p><b>Example:<\/b><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/458-Egyptian2.jpg\" alt=\"458-Egyptian2.jpg\" width=\"400\" height=\"90\" \/><\/p>\n<p><b><u>The additive systems of Type 2<\/u><\/b> have special symbols for 1, 10, 100, 1000&#8230;. In addition, they have special symbols for 5, 50, 500&#8230;. The Roman numerals belong to additive systems of Type 2 (see Fig.2):<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/458-roman.jpg\" alt=\"458-roman.jpg\" \/><\/p>\n<p><b><u>The additive systems of Type 3<\/u><\/b> use alphabets to represent the numbers.<\/p>\n<p>The example of such a system would be Greek alphabetic number system (see Fig.3):<b> <\/b><\/p>\n<p>&nbsp;<\/p>\n<p><b>Fig.3 Greek Alphabetic Numeral System (Additive numeral systems of Type 3)<\/b><\/p>\n<p><strong><img decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/458-AKozakImage1.jpg\" alt=\"458-AKozakImage1.jpg\" \/><\/strong><\/p>\n<p>&nbsp;<\/p>\n<p>In alphabetic numeral system, each letter has a numeric value.<\/p>\n<p>Then, any number can be represented by the set of letters, using the additive principle.<\/p>\n<p>For instance,<\/p>\n<p>12 = ?\u00c3<\/p>\n<p>543 = f\u00c2\u00b5?<\/p>\n<p>There is special notation for the numbers greater than 999.<\/p>\n<p>Note that alphabetic numeral systems could appear only when the alphabets and the writing systems came to the scene. Before that, many civilizations, including Greeks had other numeral systems, mostly the additive systems of Type 1 or 2.<\/p>\n<p><b>2. Hybrid numeral systems<\/b><\/p>\n<p>&nbsp;<\/p>\n<p>The hybrid numeral systems are the systems that use the principles of addition and multiplication.<\/p>\n<p>There are few types of hybrid numeral systems. The example is a common Chinese number system (see Fig.4):<\/p>\n<p><b>Fig.4 Common Chinese Numeral System (Hybrid numeral system)<\/b><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/458-chinese2.jpg\" alt=\"458-chinese2.jpg\" width=\"480\" height=\"265\" \/><\/p>\n<p>Common Chinese numeral system has symbols for the numbers from 1 to 9 and for 10, 100, 1000 and 10000. It didn&#8217;t have a zero, but then later the symbol for zero was added.<\/p>\n<p><b>3. Positional numeral systems<\/b><\/p>\n<p>The difficulties of ancient additive and hybrid numeral systems are obvious:<\/p>\n<p>&#8211; They didn&#8217;t have clear intuitive notation for the numbers.<\/p>\n<p>&#8211; Representation of the big numbers usually required a lot of space<\/p>\n<p>&#8211; Demand for the numbers greater than already existed in the system, required development of the new symbols or conventions.<\/p>\n<p>&#8211; The additive and hybrid numeral systems were mostly static. Their number-symbols looked more like abbreviations and could appear only in the group of similar symbols or(and) in a certain position. That made the ancient numeral systems unsuitable for written arithmetic and requested auxiliary tools, like abacus, special tables or system-specific rules to do the calculations.<\/p>\n<p>Therefore, the invention of positional numeral system was very important step for the human civilization.<\/p>\n<p>In the positional system, the value of each symbol depends on position of that symbol in the number representation.<\/p>\n<p>Except of our modern positional system, there were three positional systems in the history of civilization. They are systems of Babylonian scholars, Chinese scholars and Mayan astronomers.<\/p>\n<p>The Babylonians used sexagesimal (base-60) positional numeral system, written in cuneiform (see Fig.5):<\/p>\n<p><b>Fig.5 Babylonian sexagesimal positional numeral system<\/b><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/458-babylonian.jpg\" alt=\"458-babylonian.jpg\" width=\"522\" height=\"302\" \/><\/p>\n<p>The first positional systems had one significant drawback. They were not really dynamic.<\/p>\n<p>Indeed, in order to be dynamic the positional system needs to have only one symbol (from available in that system) in each position. In Babylonian system, a digit in each position could be composed of a few repeated cuneiform symbols (in Chinese and Mayan numeral systems a digit could be composed of a few bars or points).<\/p>\n<p>May be because of that drawback they couldn&#8217;t compete with the more advanced Hindu-Arabic positional numeral system.<\/p>\n<p>Our modern decimal system, also called &#8220;Arabic&#8221; or &#8220;Hindu-Arabic&#8221;, has been invented in India; developed by Arabic mathematicians and then came to Europe.)<\/p>\n<p>Today, the decimal system is widely accepted. It became an official numeral system in practically all countries.<\/p>\n<p>Three more positional systems &#8211; binary, octal and hexadecimal became very important in the last 40-50 years with the appearance of computers and information technology.<\/p>\n<p>The positional numeral systems have following main characteristics:<\/p>\n<p>&#8211; Can represent practically any number<\/p>\n<p>&#8211; Truly dynamic (have one distinct number-sign in each position)<\/p>\n<p>&#8211; Have special symbol zero that indicates the absence of the value (empty value) in the specific position<\/p>\n<p>&#8211; The most suitable for the mathematical calculations among all numeral systems<\/p>\n<p>&#8211; Provide the highest level of abstraction<\/p>\n<h3>Numbers&#8217; Conversion in Positional Numeral Systems<\/h3>\n<p>The positional systems have base (radix).<\/p>\n<p>The base is the amount of unique symbols that positional numeral system uses for the numbers&#8217; representation. For instance, base-10 (decimal) numeral system has ten symbols 0,1,2 ,3,4,5,6,7,8,9,10; base-2 (binary) numeral system has two symbols 0,1.<\/p>\n<p>It is obvious that numeral systems with the higher base provide more compact notation for the numbers.<\/p>\n<p>Indeed, the same number 25510 = 111111112 = FF16 will occupy 3 positions in decimal numeral system, 8 positions in binary numeral system and 2 positions in hexadecimal numeral system.<\/p>\n<p>However, it doesn&#8217;t mean that we need to switch to base-100 or base-1000 numeral system. It is much easier for us to recognize and operate with 10 distinct symbols (may be because human being has 10 fingers), than with 100 or 1000.<\/p>\n<p>At the same time for the computers, it is easier to operate with two figures, even though it may produce a long sequence of binary symbols for the very large numbers.<\/p>\n<p>Theoretically, the amount of the positional numeral systems can be unlimited.<\/p>\n<p>In practice, there is a few dozens of different positional numeral systems and often we need to convert the numbers from one system to another.<\/p>\n<p>In this paragraph, we will discuss SQL techniques that can be used for the numbers conversion.<\/p>\n<p>Let us start with the number conversion from base-n numeral system to base-10 numeral system, where radix n can be any radix different than 10.<\/p>\n<p>As an example, let us convert the binary numbers into decimal ones.<\/p>\n<p>First, create and load an auxiliary table that will store the sequence of whole numbers (see Listing1):<\/p>\n<p><b>Listing1.<\/b> <b>Create and load an auxiliary table<\/b><\/p>\n<div class=\"code\">SET\u00a0NOCOUNT\u00a0ON; <br \/>\nDECLARE\u00a0@n\u00a0INT; <br \/>\nSET\u00a0@n\u00a0=\u00a0100000; <\/p>\n<p>IF\u00a0EXISTS(SELECT\u00a0*\u00a0FROM\u00a0sysobjects\u00a0 <br \/>\n\u00a0\u00a0\u00a0WHERE\u00a0ID\u00a0=\u00a0(OBJECT_ID(&#8216;sequence&#8217;))\u00a0AND\u00a0xtype\u00a0=\u00a0&#8216;U&#8217;)\u00a0 <br \/>\nDROP\u00a0TABLE\u00a0sequence; <br \/>\nCREATE\u00a0TABLE\u00a0sequence(num\u00a0bigint\u00a0NOT\u00a0NULL\u00a0PRIMARY\u00a0KEY); <\/p>\n<p>WITH\u00a0numbers\u00a0AS <br \/>\n( <br \/>\n\u00a0SELECT\u00a01\u00a0AS\u00a0num <br \/>\n\u00a0UNION\u00a0ALL <br \/>\n\u00a0SELECT\u00a0num\u00a0+\u00a01\u00a0FROM\u00a0numbers\u00a0WHERE\u00a0num\u00a0&lt;\u00a0@n <br \/>\n) <br \/>\nINSERT\u00a0INTO\u00a0sequence <br \/>\nSELECT\u00a0num\u00a0FROM\u00a0numbers\u00a0 <br \/>\nOPTION\u00a0(MAXRECURSION\u00a00); <\/div>\n<p><strong>Technique 1<\/strong><\/p>\n<p>Create and load test table (see Listing2):<\/p>\n<p><strong>Listing2. Create and load test table<\/strong><\/p>\n<div class=\"code\">SET\u00a0NOCOUNT\u00a0ON; <br \/>\nIF\u00a0EXISTS(SELECT\u00a0*\u00a0FROM\u00a0sysobjects\u00a0 <br \/>\n\u00a0\u00a0\u00a0WHERE\u00a0ID\u00a0=\u00a0(OBJECT_ID(&#8216;baseN_Values&#8217;))\u00a0AND\u00a0xtype\u00a0=\u00a0&#8216;U&#8217;)\u00a0 <br \/>\nDROP\u00a0TABLE\u00a0baseN_Values; <\/p>\n<p>CREATE\u00a0TABLE\u00a0baseN_Values\u00a0(baseN_Val\u00a0VARCHAR(100)); <\/p>\n<p>INSERT\u00a0INTO\u00a0baseN_Values\u00a0VALUES\u00a0(&#8216;10101&#8217;); <br \/>\nINSERT\u00a0INTO\u00a0baseN_Values\u00a0VALUES\u00a0(&#8216;101010&#8217;); <br \/>\nINSERT\u00a0INTO\u00a0baseN_Values\u00a0VALUES\u00a0(&#8216;10101000000000000001&#8217;); <br \/>\nINSERT\u00a0INTO\u00a0baseN_Values\u00a0VALUES\u00a0(&#8216;101&#8217;); <br \/>\nINSERT\u00a0INTO\u00a0baseN_Values\u00a0VALUES\u00a0(&#8216;1010&#8217;); <br \/>\nINSERT\u00a0INTO\u00a0baseN_Values\u00a0VALUES\u00a0(&#8216;1010101&#8217;); <br \/>\nINSERT\u00a0INTO\u00a0baseN_Values\u00a0VALUES\u00a0(&#8216;111111111&#8217;); <br \/>\nINSERT\u00a0INTO\u00a0baseN_Values\u00a0VALUES\u00a0(&#8216;101011000100010001000100010010&#8217;); <br \/>\nINSERT\u00a0INTO\u00a0baseN_Values\u00a0VALUES\u00a0(&#8216;1010101111111111&#8217;); <br \/>\nINSERT\u00a0INTO\u00a0baseN_Values\u00a0VALUES(&#8216;10101011111111111111111111111111111111111111111110&#8217;); <br \/>\nINSERT\u00a0INTO\u00a0baseN_Values\u00a0VALUES\u00a0(&#8216;101010000000000000000000011&#8217;); <br \/>\nINSERT\u00a0INTO\u00a0baseN_Values\u00a0VALUES\u00a0(&#8216;10101001010101010101&#8217;); <br \/>\nINSERT\u00a0INTO\u00a0baseN_Values\u00a0VALUES\u00a0(&#8216;101010010101010101011111000&#8217;); <br \/>\nINSERT\u00a0INTO\u00a0baseN_Values\u00a0VALUES\u00a0(&#8216;1010101000&#8217;); <br \/>\nINSERT\u00a0INTO\u00a0baseN_Values\u00a0VALUES\u00a0(&#8216;101010000000000&#8217;); <br \/>\nINSERT\u00a0INTO\u00a0baseN_Values\u00a0VALUES\u00a0(&#8216;10000000101010&#8217;); <br \/>\nINSERT\u00a0INTO\u00a0baseN_Values\u00a0 <br \/>\nVALUES\u00a0(&#8216;1000000000100000000000100000000000&#8217;); <\/div>\n<p>Now, you need only one SELECT statement to convert the numbers (see Listing3):<\/p>\n<p><strong>Listing3. Convert numbers from base-n numeral system to decimal one<\/strong><\/p>\n<div class=\"code\">DECLARE\u00a0@base\u00a0bigint; <br \/>\nSET\u00a0@base\u00a0=\u00a02; <\/p>\n<p>SELECT\u00a0t1.baseN_Val,\u00a0 <br \/>\n(SELECT\u00a0SUM(SUBSTRING(\u00a0t2.baseN_Val,\u00a0LEN(t2.baseN_Val)-num\u00a0+\u00a01,\u00a01)*\u00a0POWER(@base,\u00a0num\u00a0-1)) <br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0FROM\u00a0sequence\u00a0CROSS\u00a0JOIN\u00a0baseN_Values\u00a0t2\u00a0 <br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0WHERE\u00a0t1.baseN_Val\u00a0=\u00a0t2.baseN_Val\u00a0 <br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0AND\u00a0num\u00a0&lt;=\u00a0LEN(t1.baseN_Val))\u00a0dec_Val <br \/>\nFROM\u00a0baseN_Values\u00a0t1; <\/p>\n<\/div>\n<pre>Results:baseN_Val\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 dec_Val--------------------------------------------------\u00a0\u00a0\u00a0 ---------------10101\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 21101010\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 4210101000000000000001\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 688129101\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 51010\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 101010101\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 85111111111\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 511101011000100010001000100010010\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 7225387701010101111111111\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 4403110101011111111111111111111111111111111111111111110\u00a0\u00a0\u00a0 756463999909886101010000000000000000000011\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 8808038710101001010101010101\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 693589101010010101010101011111000\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 887795121010101000\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 680101010000000000\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 2150410000000101010\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 82341000000000100000000000100000000000\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 8598325248<\/pre>\n<p>In fact, SELECT statement from the Listing3 is a SQL notation of well-known formula that represents a real number X in the positional base-r numeral system:<\/p>\n<p><strong>X = cnRn + cn &#8211; 1Rn &#8211; 1 +&#8230;+ ciRi +&#8230; + c1R1 + c0R0 + c-1R-1 + &#8230; + c-(n-1)R-(n-1) + c-nR-n<\/strong><\/p>\n<p>&nbsp;<\/p>\n<p>, where coefficient-multiplier ci can be any symbol from the base-r numbers&#8217; set and R0, R1, &#8230; Ri are the radix in the power of the position-number minus 1.<\/p>\n<p>Pay attention to data type of variable @base. That data type is bigint and defines data type of the result of the expression POWER(@base, num -1).<\/p>\n<p>It is sufficient to have bigint in order to convert a 50-digits binary number<\/p>\n<pre><\/pre>\n<p>101010111111111111111111111111111111111111111111102<\/p>\n<p>into decimal number<\/p>\n<pre><\/pre>\n<p class=\"MsoNormal\">75646399990988610.<\/p>\n<p>However, if you set variable @base to 8, assuming that table <b>baseN_Values<\/b> stores octal values, the script from the Listing3 will give you an error: <b>Arithmetic overflow error converting expression to data type bigint.<\/b><\/p>\n<p>That means bigint data type doesn&#8217;t have enough capacity to convert 50-digits octal number into decimal one. In order to convert a long octal number, you will need to make a change in the Listing3: you need to replace bigint data type of variable @base by float data type.<\/p>\n<p>Using script from the Listing3, you can convert the numbers from any positional numeral system to decimal one.<\/p>\n<p><b>Technique 2<\/b><\/p>\n<p>Another approach to the numbers&#8217; conversion is to build tables that specify the correspondence between the numbers in different numeral systems.<\/p>\n<p>This approach can be easily implemented in SQL, using the following idea:<\/p>\n<ol>\n<li>Load <b>n<\/b> unique symbols of the base-n numeral system into the table<\/li>\n<li>Join that table to itself as many times, as the maximum number of digits you want to get.<\/li>\n<\/ol>\n<p>For example, if you want to get 6-digits binary numbers, you can do this (see Listing4):<\/p>\n<p><b>Listing4.<\/b> <b>Build sequence of 6-digits binary numbers<\/b><\/p>\n<div class=\"code\">IF\u00a0EXISTS(SELECT\u00a0*\u00a0FROM\u00a0sysobjects\u00a0 <br \/>\n\u00a0\u00a0\u00a0WHERE\u00a0ID\u00a0=\u00a0(OBJECT_ID(&#8216;Bin&#8217;))\u00a0AND\u00a0xtype\u00a0=\u00a0&#8216;U&#8217;)\u00a0 <br \/>\nDROP\u00a0TABLE\u00a0Bin; <\/p>\n<p>CREATE\u00a0TABLE\u00a0bin(binNum\u00a0VARCHAR(100)); <br \/>\nINSERT\u00a0INTO\u00a0bin\u00a0VALUES(&#8216;0&#8217;); <br \/>\nINSERT\u00a0INTO\u00a0bin\u00a0VALUES(&#8216;1&#8217;); <\/p>\n<p>SELECT\u00a0(b1.binNum\u00a0+\u00a0b2.binNum\u00a0+\u00a0b3.binNum\u00a0+\u00a0 <br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0b4.binNum\u00a0+\u00a0b5.binNum\u00a0+\u00a0b6.binNum)\u00a0AS\u00a0binValue <br \/>\n\u00a0\u00a0\u00a0FROM\u00a0bin\u00a0b1\u00a0CROSS\u00a0JOIN\u00a0bin\u00a0b2\u00a0CROSS\u00a0JOIN\u00a0bin\u00a0b3\u00a0 <br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0CROSS\u00a0JOIN\u00a0bin\u00a0b4\u00a0CROSS\u00a0JOIN\u00a0bin\u00a0b5\u00a0CROSS\u00a0JOIN\u00a0bin\u00a0b6 <br \/>\n\u00a0\u00a0\u00a0ORDER\u00a0\u00a0BY\u00a01<\/div>\n<pre>Results:binValue-----------000000000001000010000011000100000101000110000111001000001001. . . .111101111110111111(64 row(s) affected)<\/pre>\n<p>&nbsp;<\/p>\n<p>The query from the Listing4, however, is very inconvenient. The problem is in its static nature.<\/p>\n<p>Indeed, for 6-digits binary numbers you need 6 joins and 6 addends in the SELECT list. For 10-digits binary numbers you would need 10 joins and 10 addends in the SELECT list.<\/p>\n<p>Each time when you need a specific length of the numbers, you need to rewrite the query.<\/p>\n<p>You can solve that problem using dynamic SQL, but in SQL Server 2005 you can do something more elegant (see Listing5):<\/p>\n<p><strong>Listing5. Build sequence of 10-digits binary numbers using CTE<\/strong><\/p>\n<div class=\"code\">IF\u00a0EXISTS(SELECT\u00a0*\u00a0FROM\u00a0sysobjects\u00a0 <br \/>\n\u00a0\u00a0\u00a0WHERE\u00a0ID\u00a0=\u00a0(OBJECT_ID(&#8216;Bin&#8217;))\u00a0AND\u00a0xtype\u00a0=\u00a0&#8216;U&#8217;)\u00a0 <br \/>\nDROP\u00a0TABLE\u00a0Bin; <\/p>\n<p>CREATE\u00a0TABLE\u00a0bin(binNum\u00a0VARCHAR(100)); <br \/>\nINSERT\u00a0INTO\u00a0bin\u00a0VALUES(&#8216;0&#8217;); <br \/>\nINSERT\u00a0INTO\u00a0bin\u00a0VALUES(&#8216;1&#8217;); <\/p>\n<p>DECLARE\u00a0@lenght\u00a0INT; <br \/>\nSELECT\u00a0@lenght\u00a0=\u00a010; <\/p>\n<p>WITH\u00a0numbers\u00a0AS\u00a0 <br \/>\n(\u00a0 <br \/>\nSELECT\u00a0CAST(binNum\u00a0AS\u00a0VARCHAR(100))\u00a0AS\u00a0base2\u00a0FROM\u00a0bin <br \/>\nUNION\u00a0ALL\u00a0 <br \/>\nSELECT\u00a0CAST((t2.binNum\u00a0+\u00a0base2)\u00a0AS\u00a0VARCHAR(100))\u00a0 <br \/>\n\u00a0\u00a0\u00a0FROM\u00a0numbers\u00a0CROSS\u00a0JOIN\u00a0bin\u00a0t2\u00a0 <br \/>\n\u00a0\u00a0\u00a0WHERE\u00a0LEN(base2)\u00a0&lt;\u00a0@lenght\u00a0 <br \/>\n)\u00a0 <br \/>\nSELECT\u00a0ROW_NUMBER()\u00a0OVER\u00a0(ORDER\u00a0BY\u00a0base2)\u00a0&#8211;\u00a01\u00a0AS\u00a0base10,\u00a0base2\u00a0\u00a0\u00a0 <br \/>\n\u00a0\u00a0\u00a0FROM\u00a0numbers\u00a0 <br \/>\n\u00a0\u00a0\u00a0WHERE\u00a0LEN(base2)\u00a0&gt;\u00a0@lenght\u00a0&#8211;\u00a01 <br \/>\nOPTION\u00a0(MAXRECURSION\u00a00);\u00a0 <\/div>\n<pre>Results:base10\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 base2------ \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0----------0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 00000000001\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 00000000012\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 00000000103\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 00000000114\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 00000001005\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 0000000101. . . . . . . . . . . . . . . .1018\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 11111110101019\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 11111110111020\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 11111111001021\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 11111111011022\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 11111111101023\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 1111111111(1024 row(s) affected)<\/pre>\n<p>&nbsp;<\/p>\n<p>This solution will change the query dynamically, but it works only for binary numbers.<\/p>\n<p>If you want your solution to work with any base (well, almost any), you need to use the approach, shown in the Listing6:<\/p>\n<p><b>Listing6.<\/b> <b>Almost universal solution with user-defined function<\/b><\/p>\n<div class=\"code\">IF\u00a0OBJECT_ID\u00a0(N&#8217;dbo.udf_GetNumbers&#8217;,\u00a0N&#8217;TF&#8217;)\u00a0IS\u00a0NOT\u00a0NULL <br \/>\n\u00a0\u00a0\u00a0\u00a0DROP\u00a0FUNCTION\u00a0dbo.udf_GetNumbers; <br \/>\nGO <\/p>\n<p>CREATE\u00a0FUNCTION\u00a0dbo.udf_GetNumbers\u00a0(@base\u00a0INT,\u00a0@lenght\u00a0INT) <br \/>\nRETURNS\u00a0@baseN_numbers\u00a0TABLE\u00a0 <br \/>\n( <br \/>\n\u00a0\u00a0\u00a0\u00a0decNum\u00a0INT\u00a0PRIMARY\u00a0KEY\u00a0NOT\u00a0NULL, <br \/>\n\u00a0\u00a0\u00a0\u00a0baseN_Num\u00a0VARCHAR(50)\u00a0NOT\u00a0NULL <br \/>\n) <br \/>\nAS <br \/>\nBEGIN <br \/>\n\u00a0\u00a0\u00a0WITH\u00a0tblBase\u00a0AS\u00a0 <br \/>\n\u00a0\u00a0\u00a0(\u00a0 <br \/>\n\u00a0\u00a0\u00a0SELECT\u00a0CAST(0\u00a0AS\u00a0VARCHAR(50))\u00a0AS\u00a0baseNum <br \/>\n\u00a0\u00a0\u00a0\u00a0UNION\u00a0ALL <br \/>\n\u00a0\u00a0\u00a0\u00a0SELECT\u00a0CAST((baseNum\u00a0+\u00a01)\u00a0AS\u00a0VARCHAR(50))\u00a0 <br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0FROM\u00a0tblBase\u00a0WHERE\u00a0baseNum\u00a0&lt;\u00a0@base-1 <br \/>\n\u00a0\u00a0\u00a0), <br \/>\n\u00a0\u00a0\u00a0numbers\u00a0AS\u00a0 <br \/>\n\u00a0\u00a0\u00a0( <br \/>\n\u00a0\u00a0\u00a0SELECT\u00a0CAST(baseNum\u00a0AS\u00a0VARCHAR(50))\u00a0AS\u00a0num\u00a0FROM\u00a0tblBase <br \/>\n\u00a0\u00a0\u00a0UNION\u00a0ALL\u00a0 <br \/>\nSELECT\u00a0CAST((t2.baseNum\u00a0+\u00a0num)\u00a0AS\u00a0VARCHAR(50))\u00a0FROM\u00a0numbers\u00a0CROSS\u00a0JOIN\u00a0tblBase\u00a0t2\u00a0 <br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0WHERE\u00a0LEN(NUM)\u00a0&lt;\u00a0@lenght\u00a0 <br \/>\n\u00a0\u00a0\u00a0)\u00a0 <br \/>\n\u00a0\u00a0\u00a0INSERT\u00a0INTO\u00a0@baseN_numbers <br \/>\n\u00a0\u00a0\u00a0SELECT\u00a0ROW_NUMBER()\u00a0OVER\u00a0(ORDER\u00a0BY\u00a0NUM)\u00a0-1\u00a0AS\u00a0rowID,\u00a0NUM\u00a0 <br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0FROM\u00a0numbers\u00a0WHERE\u00a0LEN(NUM)\u00a0&gt;\u00a0@lenght\u00a0&#8211;\u00a01 <br \/>\n\u00a0\u00a0\u00a0OPTION\u00a0(MAXRECURSION\u00a00);\u00a0 <br \/>\n\u00a0\u00a0\u00a0RETURN <br \/>\nEND <\/div>\n<p>From here, everything becomes easy. If you need, for example to build a table with decimal and corresponding binary, ternary and octal numbers, you can run the next query (see Listing7):<\/p>\n<p><strong>Listing7. Example with decimal, binary, ternary and octal numbers<\/strong><\/p>\n<div class=\"code\">SELECT\u00a0U1.decNum\u00a0base10,\u00a0 <br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0U1.baseN_Num\u00a0base2,\u00a0 <br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0U2.baseN_Num\u00a0base3, <br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0U3.baseN_Num\u00a0base8\u00a0 <br \/>\nFROM\u00a0dbo.udf_GetNumbers(2,\u00a010)\u00a0U1\u00a0 <br \/>\nINNER\u00a0JOIN\u00a0dbo.udf_GetNumbers(3,\u00a07)\u00a0U2\u00a0ON\u00a0u1.decNum\u00a0=\u00a0u2.decNum <br \/>\nINNER\u00a0JOIN\u00a0dbo.udf_GetNumbers(8,\u00a04)\u00a0U3\u00a0ON\u00a0u2.decNum\u00a0=\u00a0u3.decNum <\/div>\n<pre>Results:base10\u00a0\u00a0 base2\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0 base3 \u00a0\u00a0\u00a0\u00a0\u00a0 base8------\u00a0\u00a0 ----------\u00a0 \u00a0\u00a0\u00a0-------\u00a0\u00a0\u00a0\u00a0 -----0\u00a0\u00a0\u00a0\u00a0 \u00a0\u00a0 0000000000\u00a0\u00a0\u00a0\u00a0 0000000\u00a0\u00a0\u00a0\u00a0 00001\u00a0\u00a0\u00a0\u00a0 \u00a0\u00a0 0000000001\u00a0\u00a0\u00a0\u00a0 0000001\u00a0\u00a0\u00a0\u00a0 00012\u00a0\u00a0\u00a0\u00a0 \u00a0\u00a0 0000000010\u00a0\u00a0\u00a0\u00a0 0000002\u00a0\u00a0\u00a0\u00a0 00023\u00a0\u00a0\u00a0\u00a0 \u00a0\u00a0 0000000011\u00a0\u00a0\u00a0\u00a0 0000010\u00a0\u00a0\u00a0\u00a0 00034\u00a0\u00a0\u00a0\u00a0 \u00a0\u00a0 0000000100\u00a0\u00a0\u00a0\u00a0 0000011\u00a0\u00a0\u00a0\u00a0 00045\u00a0\u00a0\u00a0\u00a0 \u00a0\u00a0 0000000101\u00a0\u00a0\u00a0\u00a0 0000012\u00a0\u00a0\u00a0\u00a0 00056\u00a0\u00a0\u00a0\u00a0 \u00a0\u00a0 0000000110\u00a0\u00a0\u00a0\u00a0 0000020\u00a0\u00a0\u00a0\u00a0 00067\u00a0\u00a0\u00a0\u00a0 \u00a0\u00a0 0000000111\u00a0\u00a0\u00a0\u00a0 0000021\u00a0\u00a0\u00a0\u00a0 00078\u00a0\u00a0\u00a0\u00a0 \u00a0\u00a0 0000001000\u00a0\u00a0\u00a0\u00a0 0000022\u00a0\u00a0\u00a0\u00a0 0010. . . . . . . . . . . . . . . . . . . . 1016\u00a0 \u00a0\u00a0 1111111000\u00a0\u00a0\u00a0\u00a0 1101122\u00a0\u00a0\u00a0\u00a0 17701017\u00a0 \u00a0\u00a0 1111111001\u00a0\u00a0\u00a0\u00a0 1101200\u00a0\u00a0\u00a0\u00a0 17711018\u00a0 \u00a0\u00a0 1111111010\u00a0\u00a0\u00a0\u00a0 1101201\u00a0\u00a0\u00a0\u00a0 17721019\u00a0 \u00a0\u00a0 1111111011\u00a0\u00a0\u00a0\u00a0 1101202\u00a0\u00a0\u00a0\u00a0 17731020\u00a0 \u00a0\u00a0 1111111100\u00a0\u00a0\u00a0\u00a0 1101210\u00a0\u00a0\u00a0\u00a0 17741021\u00a0 \u00a0\u00a0 1111111101\u00a0\u00a0\u00a0\u00a0 1101211\u00a0\u00a0\u00a0\u00a0 17751022\u00a0 \u00a0\u00a0 1111111110\u00a0\u00a0\u00a0\u00a0 1101212\u00a0\u00a0\u00a0\u00a0 17761023\u00a0 \u00a0\u00a0 1111111111\u00a0\u00a0\u00a0\u00a0 1101220\u00a0\u00a0\u00a0\u00a0 1777<\/pre>\n<p>&nbsp;<\/p>\n<p class=\"MsoNormal\">\u00a0<\/p>\n<p>As I mentioned earlier, the solution from the Listing6 is almost universal. It will work fine for all the bases lower than 10.<\/p>\n<p>However, for any numeral system, that has special symbols (like A and B in duodecimal numeral system) you will need explicitly load table with all the symbols of that <b>base-n<\/b> system and then run the query from the Listing5.<\/p>\n<h3>Conversion from Decimal to Roman Numbers in SQL<\/h3>\n<p>Roman numeral system (adapted from Etruscans numeral system) was in use in ancient Rome and Roman Empire for more than thousand years.<\/p>\n<p>That system was the main numeral system in Europe until 14th century and then gradually, during the centuries was supplanted by the Hindu-Arabic decimals.<\/p>\n<p>Today, Roman numerals are still in use. They can be found in clocks and calendars; in books and media; in art, antique shops and museums; in chemistry; as the list numbers (you can enumerate pages of the Word document, using the roman numerals) and more.<\/p>\n<p>As we saw earlier, the Roman numerals belong to additive numeral systems (see Fig2). Decimal numbers in turn represent positional numeral systems.<\/p>\n<p>Both systems are governed by different rules and that makes the numbers&#8217; conversion between Roman and decimal systems quite tricky.<\/p>\n<p>However, there is a simple way to do such a conversion in SQL.<\/p>\n<p>First, create auxiliary tables with Roman numbers (see Listing8):<\/p>\n<p><b>Listing8.<\/b> <b>Create auxiliary tables with <\/b><b>Roman numbers<\/b><\/p>\n<div class=\"code\">\/*\u00a0Basic\u00a0symbols\u00a0of\u00a0Roman\u00a0numerals <\/p>\n<p>I\u00a0\u00a0V\u00a0\u00a0\u00a0X\u00a0\u00a0\u00a0L\u00a0\u00a0\u00a0C\u00a0\u00a0\u00a0D\u00a0\u00a0\u00a0M <br \/>\n1\u00a0\u00a05\u00a0\u00a0\u00a010\u00a0\u00a050\u00a0\u00a0100\u00a0500\u00a01000 <\/p>\n<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;*\/ <\/p>\n<p>IF\u00a0EXISTS(SELECT\u00a0*\u00a0FROM\u00a0sysobjects\u00a0 <br \/>\n\u00a0\u00a0\u00a0WHERE\u00a0ID\u00a0=\u00a0(OBJECT_ID(&#8216;dec_rom1_9&#8217;))\u00a0AND\u00a0xtype\u00a0=\u00a0&#8216;U&#8217;)\u00a0 <br \/>\nDROP\u00a0TABLE\u00a0dec_rom1_9; <br \/>\nGO <br \/>\nSELECT\u00a0t1.decNum,\u00a0t1.romaNum\u00a0INTO\u00a0dec_rom1_9 <br \/>\nFROM\u00a0 <br \/>\n(SELECT\u00a00\u00a0AS\u00a0decNum,\u00a0&#8221;\u00a0AS\u00a0romaNum\u00a0 <br \/>\nUNION\u00a0ALL\u00a0 <br \/>\nSELECT\u00a01,\u00a0&#8216;I&#8217; <br \/>\nUNION\u00a0ALL <br \/>\nSELECT\u00a02,\u00a0&#8216;II&#8217; <br \/>\nUNION\u00a0ALL <br \/>\nSELECT\u00a03,\u00a0&#8216;III&#8217; <br \/>\nUNION\u00a0ALL <br \/>\nSELECT\u00a04,\u00a0&#8216;IV&#8217; <br \/>\nUNION\u00a0ALL <br \/>\nSELECT\u00a05,\u00a0&#8216;V&#8217; <br \/>\nUNION\u00a0ALL <br \/>\nSELECT\u00a06,\u00a0&#8216;VI&#8217; <br \/>\nUNION\u00a0ALL <br \/>\nSELECT\u00a07,\u00a0&#8216;VII&#8217; <br \/>\nUNION\u00a0ALL <br \/>\nSELECT\u00a08,\u00a0&#8216;VIII&#8217; <br \/>\nUNION\u00a0ALL <br \/>\nSELECT\u00a09,\u00a0&#8216;IX&#8217; <br \/>\n)\u00a0t1 <br \/>\n&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211; <\/p>\n<p>IF\u00a0EXISTS(SELECT\u00a0*\u00a0FROM\u00a0sysobjects\u00a0 <br \/>\n\u00a0\u00a0\u00a0WHERE\u00a0ID\u00a0=\u00a0(OBJECT_ID(&#8216;dec_romX_XC&#8217;))\u00a0AND\u00a0xtype\u00a0=\u00a0&#8216;U&#8217;)\u00a0 <br \/>\nDROP\u00a0TABLE\u00a0dec_romX_XC; <br \/>\nGO <br \/>\nSELECT\u00a0t1.decNum,\u00a0t1.romaNum\u00a0INTO\u00a0dec_romX_XC <br \/>\nFROM\u00a0 <br \/>\n(SELECT\u00a00\u00a0AS\u00a0decNum,\u00a0&#8221;\u00a0AS\u00a0romaNum\u00a0 <br \/>\nUNION\u00a0ALL <br \/>\nSELECT\u00a010,\u00a0&#8216;X&#8217;\u00a0 <br \/>\nUNION\u00a0ALL <br \/>\nSELECT\u00a020,\u00a0&#8216;XX&#8217; <br \/>\nUNION\u00a0ALL <br \/>\nSELECT\u00a030,\u00a0&#8216;XXX&#8217; <br \/>\nUNION\u00a0ALL <br \/>\nSELECT\u00a040,\u00a0&#8216;XL&#8217; <br \/>\nUNION\u00a0ALL <br \/>\nSELECT\u00a090,\u00a0&#8216;XC&#8217; <br \/>\n)\u00a0t1 <br \/>\n&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211; <\/p>\n<p>IF\u00a0EXISTS(SELECT\u00a0*\u00a0FROM\u00a0sysobjects\u00a0 <br \/>\n\u00a0\u00a0\u00a0WHERE\u00a0ID\u00a0=\u00a0(OBJECT_ID(&#8216;dec_romC_CM&#8217;))\u00a0AND\u00a0xtype\u00a0=\u00a0&#8216;U&#8217;)\u00a0 <br \/>\nDROP\u00a0TABLE\u00a0dec_romC_CM; <br \/>\nGO <br \/>\nSELECT\u00a0t1.decNum,\u00a0t1.romaNum\u00a0INTO\u00a0dec_romC_CM <br \/>\nFROM\u00a0 <br \/>\n(SELECT\u00a00\u00a0\u00a0AS\u00a0decNum,\u00a0&#8221;\u00a0AS\u00a0romaNum\u00a0 <br \/>\nUNION\u00a0ALL <br \/>\nSELECT\u00a0100,\u00a0&#8216;C&#8217; <br \/>\nUNION\u00a0ALL <br \/>\nSELECT\u00a0200,\u00a0&#8216;CC&#8217; <br \/>\nUNION\u00a0ALL <br \/>\nSELECT\u00a0300,\u00a0&#8216;CCC&#8217; <br \/>\nUNION\u00a0ALL <br \/>\nSELECT\u00a0400,\u00a0&#8216;CD&#8217; <br \/>\nUNION\u00a0ALL <br \/>\nSELECT\u00a0900,\u00a0&#8216;CM&#8217; <br \/>\n)\u00a0t1 <\/p>\n<p>IF\u00a0EXISTS(SELECT\u00a0*\u00a0FROM\u00a0sysobjects\u00a0 <br \/>\n\u00a0\u00a0\u00a0WHERE\u00a0ID\u00a0=\u00a0(OBJECT_ID(&#8216;dec_romM&#8217;))\u00a0AND\u00a0xtype\u00a0=\u00a0&#8216;U&#8217;)\u00a0 <br \/>\nDROP\u00a0TABLE\u00a0dec_romM; <br \/>\nGO <br \/>\nSELECT\u00a0t1.decNum,\u00a0t1.romaNum\u00a0INTO\u00a0dec_romM <br \/>\nFROM <br \/>\n(SELECT\u00a00\u00a0\u00a0AS\u00a0decNum,\u00a0&#8221;\u00a0AS\u00a0romaNum\u00a0 <br \/>\nUNION\u00a0ALL <br \/>\nSELECT\u00a01000,\u00a0&#8216;M&#8217; <br \/>\nUNION\u00a0ALL <br \/>\nSELECT\u00a02000,\u00a0&#8216;MM&#8217; <br \/>\nUNION\u00a0ALL <br \/>\nSELECT\u00a03000,\u00a0&#8216;MMM&#8217;)\u00a0t1 <\/p>\n<\/div>\n<p>Now you can get the decimal numbers with the corresponding Roman numbers in one query (see Listing9):<\/p>\n<p><b>Listing9.<\/b> <b>Get decimal and corresponding <\/b><b>Roman numbers<\/b><\/p>\n<div class=\"code\">SELECT\u00a0(t1.decNum\u00a0+\u00a0t2.decNum)\u00a0AS\u00a0decNum,\u00a0 <br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0(t1.romaNum\u00a0+\u00a0t2.romaNum)\u00a0AS\u00a0romaNum <br \/>\nFROM\u00a0dec_romM\u00a0t1\u00a0CROSS\u00a0JOIN\u00a0 <br \/>\n(SELECT\u00a0(t1.decNum\u00a0+\u00a0t2.decNum)\u00a0AS\u00a0decNum, <br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0(t1.romaNum\u00a0+\u00a0t2.romaNum)\u00a0AS\u00a0romaNum <br \/>\nFROM\u00a0(SELECT\u00a00\u00a0AS\u00a0decNum,\u00a0&#8221;\u00a0AS\u00a0romaNum\u00a0 <br \/>\nUNION\u00a0ALL\u00a0SELECT\u00a0500,\u00a0&#8216;D&#8217;)\u00a0t1\u00a0 <br \/>\nCROSS\u00a0JOIN\u00a0 <br \/>\n(SELECT\u00a0(t1.decNum\u00a0+\u00a0t2.decNum)\u00a0AS\u00a0decNum, <br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0(t1.romaNum\u00a0+\u00a0t2.romaNum)\u00a0AS\u00a0romaNum <br \/>\nFROM\u00a0dec_romC_CM\u00a0t1\u00a0CROSS\u00a0JOIN\u00a0 <br \/>\n(SELECT\u00a0(t1.decNum\u00a0+\u00a0t2.decNum)\u00a0AS\u00a0decNum,\u00a0 <br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0(t1.romaNum\u00a0+\u00a0t2.romaNum)\u00a0AS\u00a0romaNum\u00a0 <br \/>\nFROM\u00a0(SELECT\u00a00\u00a0AS\u00a0decNum,\u00a0&#8221;\u00a0AS\u00a0romaNum\u00a0 <br \/>\nUNION\u00a0ALL\u00a0SELECT\u00a050,\u00a0&#8216;L&#8217;)\u00a0t1\u00a0 <br \/>\nCROSS\u00a0JOIN\u00a0 <br \/>\n(SELECT\u00a0(t1.decNum\u00a0+\u00a0t2.decNum)\u00a0AS\u00a0decNum,\u00a0 <br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0(t1.romaNum\u00a0+\u00a0t2.romaNum)\u00a0AS\u00a0romaNum <br \/>\nFROM\u00a0dec_romX_XC\u00a0t1\u00a0CROSS\u00a0JOIN\u00a0dec_rom1_9\u00a0t2)\u00a0t2 <br \/>\nWHERE\u00a0NOT\u00a0(t1.romaNum\u00a0=\u00a0&#8216;L&#8217;\u00a0AND\u00a0t2.romaNum\u00a0LIKE\u00a0(&#8216;%[LC]%&#8217;)))\u00a0t2)\u00a0t2 <br \/>\nWHERE\u00a0NOT\u00a0(t1.romaNum\u00a0=\u00a0&#8216;D&#8217;\u00a0AND\u00a0t2.romaNum\u00a0LIKE\u00a0(&#8216;%[DM]%&#8217;)))\u00a0t2 <br \/>\nORDER\u00a0BY\u00a01\u00a0<\/div>\n<pre>Results:decNum\u00a0\u00a0\u00a0\u00a0\u00a0 romaNum0\u00a0\u00a0\u00a0\u00a0 1\u00a0\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0 I2\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 II3\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 III4\u00a0\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0 IV5\u00a0\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0 V6\u00a0\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0 VI7\u00a0\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0 VII8\u00a0\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0 VIII9\u00a0\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0 IX10\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0 X. . . . . . . . . . . . . . 1947\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0 MCMXLVII1948\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0 MCMXLVIII1949\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0 MCMXLIX1950\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0 MCML1951\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0 MCMLI1952\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0 MCMLII1953\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0 MCMLIII1954\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0 MCMLIV1955\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0 MCMLV1956\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0 MCMLVI. . . . . . . . . . . . . . . . . . . . . . . . . .3989\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0 MMMCMLXXXIX3990\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0 MMMCMXC3991\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0 MMMCMXCI3992\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 MMMCMXCII3993\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0 MMMCMXCIII3994\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0 MMMCMXCIV3995\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0 MMMCMXCV3996\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0 MMMCMXCVI3997\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0 MMMCMXCVII3998\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0 MMMCMXCVIII3999\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0 MMMCMXCIX<\/pre>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>For the basic symbols equal or greater than 4000, the horizontal bar should be placed on top of that symbol. That horizontal bar indicates multiplication by 1000. However, ASCII doesn&#8217;t have the Roman symbols with horizontal bar on top. This is why the solution from the Listing9 shows the Roman numbers up to 4000 only.<\/p>\n<p>Practically, you can convert the numbers from almost any numeral system to modern one, using SQL. However, to do that, you need to find the character set with the required basic symbols of that numeral system.<\/p>\n<h3>Historical Puzzle<\/h3>\n<p>It is widely accepted as an axiom that Hindu\/Arabic numeral system is much better and more advanced than Roman numeral system.<\/p>\n<p>The main arguments are:<\/p>\n<ul>\n<li>Roman numerals don&#8217;t have zero.<\/li>\n<li>Roman numbers occupy more space than decimal numbers.<\/li>\n<li>The arithmetic calculations with Roman numbers are very complicated or even impossible.<\/li>\n<li>Roman numbers cannot be used in abstract mathematics.<\/li>\n<\/ul>\n<p>Indeed, Romans don&#8217;t have as many achievements in pure mathematics as ancient Greeks. They were more interested in practical mathematics in order to build the roads, bridges and other constructions. They developed a special abacus (tabula) to facilitate the mathematical calculations.<\/p>\n<p>However, even though Hindu\/Arabic numeral system was accepted in Islamic Spain in 9th century, it took another 600 &#8211; 700 years to make it dominant number system in whole Europe.<\/p>\n<p>During those 600-700 years all the disputes between Abacists (devotees of Roman numeral system) and Algorists (supporters of decimal numeral system) ended with the same result &#8211; nobody could prove the advantage of their system.<\/p>\n<p>There are a few explanations why Hindu\/Arabic positional system finally won:<\/p>\n<ul>\n<li>It was much more convenient and faster for merchants and bookkeepers to use decimal numbers.<\/li>\n<li>Hindu\/Arabic system was more suitable for printing.<\/li>\n<li>The book &#8220;<i><a href=\"http:\/\/en.wikipedia.org\/wiki\/Liber_Abaci\">Liber Abaci<\/a><\/i>&#8220;of Leonardo Fibonacci helped to spread decimal positional system in Europe.<\/li>\n<li>Roman numeral system restricted progress of mathematics and so development of civilization.<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<p>However, even now some people wondering whether it is possible to do the arithmetic calculations with roman numerals without converting them to an Arabic\/Hindu notation.<\/p>\n<p>If you know such a method, I&#8217;d be fascinated to know how it was done, especially in TSQL.<\/p>\n<p>The editor will give a prize for the best SQL program that makes possible the addition (subtraction) operations with Roman numerals without conversion.<\/p>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Numeral systems can be fascinating. In everyday programming, we are now becoming quite insulated from the need to convert between binary numbers and their representation, so it is a novelty to try out ways of doing it in SQL, and experiment with other number systems from the past.&hellip;<\/p>\n","protected":false},"author":221828,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[143531],"tags":[4178,4179,4150,4252],"coauthors":[11311],"class_list":["post-330","post","type-post","status-publish","format-standard","hentry","category-t-sql-programming-sql-server","tag-bi","tag-source-control","tag-sql","tag-t-sql-programming"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/330","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/221828"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=330"}],"version-history":[{"count":4,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/330\/revisions"}],"predecessor-version":[{"id":73989,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/330\/revisions\/73989"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=330"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=330"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=330"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=330"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}