【问题标题】:How to get first n numbers from float如何从浮点数中获取前n个数字
【发布时间】:2015-02-11 12:03:33
【问题描述】:

我有两列 id(int)f_value(float) 的表 A。现在我想选择f_value 从'123' 开始的所有行。所以对于下表:

id | f_value
------------
1  | 12
2  | 123
3  | 1234

我想要第二排和第三排。我尝试将 LEFT 与演员一起使用,但那是一场灾难。对于以下查询:

select f_value, str(f_value) as_string, LEFT(str(f_value), 2) left_2,
       LEFT(floor(f_value), 5) flor_5, LEFT('abcdef', 5) test
   from A

我明白了:

f_value  | as_string | left_2 | flor_5 | test
------------------------------------------------
40456510 | 40456510  |        | 4.045  |  abcde
40454010 | 40454010  |        | 4.045  |  abcde
404020   | 404020    |        | 40402  |  abcde
40452080 | 40452080  |        | 4.045  |  abcde
101020   | 101020    |        | 10102  |  abcde
404020   | 404020    |        | 40402  |  abcde

问题是为什么 left 对于 'test' 可以正常工作,但对于其他返回却如此奇怪的结果?

编辑:

我又做了一个测试,现在我更加困惑了。查询:

Declare @f as float
set @f = 40456510.

select LEFT(cast(@f as float), LEN(4045.)), LEFT(404565., LEN(4045.))

我明白了:

     |
------------ 
4.04 | 4045

是否存在导致这种情况的默认强制转换? Fiddle SQL

【问题讨论】:

  • 左边(f_value, 3) = '123'
  • 如果值为 12.3 或 .123 怎么办?
  • @GordonLinoff 你可能是对的,所以根据这个假设回答
  • 请接受您认为最好的答案

标签: sql sql-server


【解决方案1】:

您的查询似乎有点错误。 LEFT 部分应该放在 WHERE-Clause 中,而不是 SELECT-part 中。

另外,只需使用 LIKE 就可以了:

SELECT f_value, str(f_value) as_string, LEFT(str(f_value), 2) left_2,
       LEFT(floor(f_value), 5) flor_5
WHERE f_value LIKE '123%'

【讨论】:

  • 不工作。对于我的示例,这将只返回第二行。
  • @orim:你确定你在末尾添加了百分号吗?
  • 是的,我知道为什么。问题是浮点数以错误的方式转换为 varchar。
【解决方案2】:
CREATE TABLE #TestTable(ID INT, f_value FLOAT)
INSERT INTO #TestTable
VALUES  (1,22),
        (2,123),
        (3,1234)

SELECT *
FROM #TestTable
WHERE LEFT(f_value,3)='123'

DROP TABLE #TestTable

我希望这会有所帮助。

【讨论】:

    【解决方案3】:

    替换去掉float中的句号,乘以1前面的任何0都会被去掉。

    SELECT f_value
    FROM your_table
    WHERE replace(f_value, '.', '') * 1 like '123%'
    

    【讨论】:

      【解决方案4】:

      我找到了解决方案。问题是 SQL Server 使用浮点数的指数表示。要解决它,您需要先将 float 转换为 BigInt,然后在其上使用 Left。

      例子:

      Select * from A where Left(Cast(float_value as BigInt), 4) = xxxx 
      

      【讨论】:

      • 这不适用于所有浮点值。不过,对于您的情况,这似乎不是问题,但对于尝试此操作的其他人来说值得注意。
      【解决方案5】:
      /*
      returns significant digits from @f (a float) as an integer
      negative sign is stripped off
      */
      declare @num_digits int = 3; /* needs to be positive; accuracy diminishes with larger values */
      with samples(num, f) as (
          select 1, cast(123.45 as float) union
          select 2, 123456700 union
          select 3, -1.234567 union
          select 4, 0.0000001234
      )
      select num, f,
          case when f = 0 or @num_digits < 1 then 0 else
              floor(
                  case sign(log10(abs(f)))
                      when -1 then abs(f) * power(10e0,  -floor(log10(abs(f))) + @num_digits - 1)
                      when  1 then abs(f) / power(10e0, ceiling(log10(abs(f))) - @num_digits)
                  end
              )
          end as significant_digits
      from samples
      order by num;
      

      sqlfiddle

      【讨论】:

        【解决方案6】:

        使用CASTFLOAT 值转换为DECIMAL,然后再转换为VARCHAR 并使用LIKE 选择以4045 开头的值。

        查询

        SELECT * FROM tbl
        WHERE CAST(CAST(f_value AS DECIMAL(20,12)) AS VARCHAR(MAX)) LIKE '4045%';
        

        Fiddle demo for reference

        【讨论】:

        • 不工作。对于我的示例,这将只返回第二行。
        • 请查看小提琴演示。它在那里返回第二行和第三行。
        • @orim:我已经更新了答案。请参阅随附的小提琴。
        猜你喜欢
        • 1970-01-01
        • 2019-09-05
        • 1970-01-01
        • 2021-04-12
        • 2011-06-07
        • 1970-01-01
        • 2023-04-09
        • 2016-04-25
        相关资源
        最近更新 更多