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

标签 mysql

我将尺寸值存储为代表 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 */
);

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

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

谢谢!

最佳答案

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

First one call SUBSTRING_INDEX to get the portion of the string that contain the first n values, and then a second call to get the last value from the subset!

In this example we extract the 4th value from a string containing animals:

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                                                 |
+--------------------------------------------------------+

In general, to select the N-th value from a string VALUES that contains values separated by delimiter DELIM, you have to use:

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

这并不比数学公式效率高或低,因为,例如,如果在 WHERE 中使用,它们都会阻止对 sixteenths 列进行任何优化。也就是说,如果您搜索“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"       |

关于mysql - 如何使用 mysql 代码动态地将整数 16 英寸转换为小数英寸?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45785326/

相关文章:

mysql - 远程更新 Drupal 站点上的数据库?

MySQL:SELECT Like 和 char_length

mysql 在另一个选择组中选择 : how many people in downline?

mysql - 更新分区/组中最新记录中的列

mysql - SQL查询以获取具有最高销售组的产品

mysql - 在 MySQL 的 varchar 字段中搜索整数值

mysql - 如何将 time_t 字段存储到 MySQL 日期时间?

php - 通过PHP解析字典对象并创建MySQL表

php - 获取不同日期的数据

php - Laravel 多对多急切加载总是返回空结果