如何使用mysql代码动态将16的整数英寸转换为小数英寸?

时间:2017-08-20 18:07:22

标签: mysql

我将size的值存储为代表16英寸的整数。

示例:

1 = 1/16"
4 = 1/4" 
8 = 1/2"
16 = 1"
24 = 1 1/2"
32 = 2"

我目前使用两列表来查找整数值并返回已计算的英寸分数。我更喜欢使它更具动态性,并且 mysql选择代码 mysql函数即时进行转换,而不需要为每个可能的整数值存储静态转换值

This solution似乎接近我需要它的反向,它处理小数与整数,所以它不是完全相反的。

目标是整数值作为输入,字符串输出是除法,但也是小数英寸的正确表示(即12应为3/4“,不是12/16”,28应为1 3/4“,而不是28 / 16“)

转换后的值不会在任何where子句中使用或索引,因为它不是可搜索的值。它仅用于输出结果。

关于如何处理这种数学和转换的专家意见,或者某处是否存在现有解决方案?

更新我实施的解决方案使用下面的选定答案:

CONCAT(
  IF(sixteenths > 15,       /* The integer part, if any */
   FLOOR(sixteenths/16),
   ''
  ),
  IF(sixteenths % 16 = 0,   /* The fractional part, if any */
   '',
  CONCAT(
    IF(sixteenths > 15, ' ', ''),  /* A space between 1 and 1/2" */
    SUBSTRING_INDEX(
     SUBSTRING_INDEX(              /* Use correct fractions from set */
     '1/16,1/8,3/16,1/4,5/16,3/8,7/16,1/2,9/16,5/8,11/16,3/4,13/16,7/8,15/16',
     ',', 
     sixteenths % 16
     ),
   ',', -1
  ))
  ),
  '"'            /* Inches symbol */
);

我现在在一个函数中使用了这个代码,当从多个表中查询数据时,可以调用这些函数,这些表在数据库中都有大数据集,所有这些都需要在执行大型结果集时将此转换作为输出(不用作搜索条件)。

由此产生的好处是动态的,可重用的,对预先创建的数据集没有限制(即它可以用于以前未考虑的任何值的整数),并且不需要在数据库级别执行的表所需的解决方案而不是应用程序级别,因此在处理大型数据结果集时速度非常快!

谢谢!

2 个答案:

答案 0 :(得分:2)

最简单的方法是使用SUBSTRING_INDEX重新实现查找表。不幸的是,由于此函数从指定的开始返回项目,因此只需要一个元素,您需要在complicated way中调用它:

  

首先调用SUBSTRING_INDEX以获取包含前n个值的字符串部分,然后再调用第二个调用以获取子集中的最后一个值!

     

在这个例子中,我们从包含的字符串中提取第4个值   动物:

mysql> SET @values = 'cat#dog#horse#parrot#gecko';
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(@values,'#',4),'#',-1);
+--------------------------------------------------------+
| SUBSTRING_INDEX(SUBSTRING_INDEX(@values,'#',4),'#',-1) |
+--------------------------------------------------------+
| parrot                                                 |
+--------------------------------------------------------+
     

通常,要从字符串VALUES中选择第N个值   包含由分隔符DELIM分隔的值,您必须使用:

SUBSTRING_INDEX( SUBSTRING_INDEX( VALUES, DELIM, N ), DELIM, -1 )

这并不比数学公式显着或多或少有效,因为例如,如果在WHERE中使用它们,它们都将阻止 16th 列的任何优化。也就是说,如果您搜索“1 3/4”级别的部分,服务器将在两种情况下执行全表扫描。这样的搜索最好处理反向翻译查询在将其插入查询之前将值转换为十六分之一。

或者你可以将它倒入文字查找(我看你已经考虑过了):

CREATE TABLE trans16(six integer, inch varchar(16));

SELECT (SELECT inch FROM trans16 WHERE six = sixteenths) AS textual, ...

第一个选项对于最后一步选择最有效,而第二个选项对于更大,更复杂的查询更有效(“反向翻译”将由MySQL处理)。

或者,您可以先使用IF()

提取“整数”部分
IF(sixteenths >= 16, FLOOR(sixteenths/16), '')

对于低于一英寸的值,这将不会是任何值,或者它将是整数英寸。然后,值

`sixteenths % 16`

将为零或从1到15的数字,所以

IF(sixteenths % 16 = 0, 
   '',
   CONCAT(' ', {FORMULA_ABOVE_USING_SUBSTRING_INDEX}  )
)

将产生空字符串或适当的小数部分。您可以通过在设置字符串的所有字符串中放置十五次空格来保存CONCAT。

最终公式如下:

CONCAT(
    IF(sixteenths > 15,       /* The integer part, if any */
       FLOOR(sixteenths/16),
       ''
    ),
    IF(sixteenths % 16 = 0,   /* The fractional part, if any */
       '',
       CONCAT(
         IF(sixteenths > 15, ' ', ''),  /* A space between 1 and 1/2" */
         SUBSTRING_INDEX(
             SUBSTRING_INDEX(
               '1/16,1/8,3/16,1/4,5/16,3/8,7/16,1/2,9/16,5/8,11/16,3/4,13/16,7/8,15/16',
               ',',
               sixteenths%16
             ),
             ',', -1
         )
       )
    ),
    '"'
);

您将无法以3/2"这种方式 - 它将被表示为1 1/2"

相同的逻辑可用于用户定义的函数。获取整数部分,然后获取十六分之一的查找表。

您也可以将这种方法用于查找表,但现在它可能不值得麻烦。

最后,你可以不用查找表:

                  %4   %2
1       1/16      1    0
2       1/8       2    1
3       3/16      3    0
4       1/4       0    1
5       5/16      1
6       3/8       2
7       7/16      3
8       1/2       0
9       9/16
10      5/8
11      11/16
12      3/4
13      13/16
14      7/8
15      15/16

所以你可以拥有/ 2,/ 4,/ 8和/ 16'。你什么时候有的?当模8为0时,你有一半;当模4为0时你有四分之一;当模2为0时,你有八分之一;否则它是十六分之一。

查找表变为

IF((s%16)%8,
    IF((s%16)%4,
        IF((s%16)%2,
            CONCAT(s%16, '/16"')
        ,CONCAT(FLOOR((s%16)/2), '/8"'))
    ,CONCAT(FLOOR((s%16)/4), '/4"'))
,CONCAT(FLOOR((s%16)/8), '/2"'))

和没有索引的最终公式,使用表来测试:

SELECT sixteenths, CONCAT(        
    IF(sixteenths > 15,
        FLOOR(sixteenths/16),
        ''
     ),
     IF(sixteenths % 16 = 0,
        '',
        CONCAT(
          IF(sixteenths > 15, ' ', ''),
            IF((sixteenths%16)%8,
              IF((sixteenths%16)%4,
                 IF((sixteenths%16)%2,
                    CONCAT(FLOOR(sixteenths%16), '/16')
                      ,CONCAT(FLOOR((sixteenths%16)/2), '/8'))
                  ,CONCAT(FLOOR((sixteenths%16)/4), '/4'))
              ,CONCAT(FLOOR((sixteenths%16)/8), '/2'))
        )
     ),
     '"'
 ) AS `text` FROM ttt;

的产率:

+------------+----------+
| sixteenths | text     |
+------------+----------+
|          1 | 1/16"    |
|          2 | 1/8"     |
|          3 | 3/16"    |
|          4 | 1/4"     |
|          5 | 5/16"    |
|          6 | 3/8"     |
|          7 | 7/16"    |
|          8 | 1/2"     |
|          9 | 9/16"    |
|         10 | 5/8"     |
|         11 | 11/16"   |
|         12 | 3/4"     |
|         13 | 13/16"   |
|         14 | 7/8"     |
|         15 | 15/16"   |
|         16 | 1"       |
|         17 | 1 1/16"  |
|         18 | 1 1/8"   |
|         19 | 1 3/16"  |
|         20 | 1 1/4"   |
|         21 | 1 5/16"  |
|         22 | 1 3/8"   |
|         23 | 1 7/16"  |
|         24 | 1 1/2"   |
|         25 | 1 9/16"  |
|         26 | 1 5/8"   |
|         27 | 1 11/16" |
|         28 | 1 3/4"   |
|         29 | 1 13/16" |
|         30 | 1 7/8"   |
|         31 | 1 15/16" |
|         32 | 2"       |

答案 1 :(得分:0)

你有一个代码,你想要一个字符串表示。一种方法是用户定义的功能。我认为一个更简单的方法只是一个查找表:

create table SixteenthsToString (
    num int primary key;
    representation varchar(255)
);

insert into SixteenthsToString
    values (0, '0"'),
           (1, '1/16"'),
           (2, '1/8"'),
           . . .

除非你有一个可笑的大范围,否则创建和填充这样的表可能比尝试其他方法更快。然后你将其用作:

select t.*, t16.representation
from t left join
     SixteenthsToString t16
     on t.code = t16.num;