订购分数列表和混合数字

时间:2012-07-18 14:12:45

标签: c# sql sql-server sql-server-2008 fractions

我正在寻找一种方法,允许我有一个列,我只需手动输入一个数字,然后列表将根据此列表排序自己,这将使用c#作为列表的语言,它是ms SQL

我没有太多信息,但如果有人想知道其他任何事情,请随时提出,我会尽力回答我的最佳能力。

它们目前存储为字符串。

导致它被抛出的东西是因为有些列表包含范围但有些包含分数,两者都显示相同的IE 1/2可以表示1-2或1/2(一半)

所有SQL连接都是使用NHibernate完成的。

不是简单地正常排序的原因是列表是使用当前的分数排序并且列表工作正常,但是当它超过1时,它似乎打破并将它们全部抛到列表IE的底部:

Image List

我希望如何工作的示例:

我的数据库中会有一个名为“DisplayOrder”的列或者其他类似的列。

数据库行显示“1”,这将是要显示的列表中的第一个项目。 数据库行显示“8”,这将是列表中的第8个项目。

3 个答案:

答案 0 :(得分:0)

排序结果似乎完全正常,因为我真的认为数据库不理解“1 1/4”的含义。 您的数据库字段是哪种类型的?文本/ varchar / string我猜?

也许您应该创建一个存储过程来将分数值转换为数字值,然后调用

SELECT field1, field2, ParseAndConvertProc(DisplayOrder) as disp_order ORDER by disp_order

答案 1 :(得分:0)

我已经整理了一个快速函数来解析你的分数并将它们转换成浮点数,然后可以用它们进行比较和排序。您可能在“卫生”步骤中需要更多,可能正常化空格,删除其他字符等,并且可能必须检查除数为零(只有您知道您的数据)。

create function dbo.FractionToFloat(@fraction varchar(100))
returns float
as
begin
    declare @input varchar(100)
        , @output float
        , @whole int
        , @dividend int
        , @divisor int

    -- Sanitize input
    select @input = ltrim(rtrim(replace(replace(@fraction, '''', ''), '"', '')))

    select @whole = cast(case
        when charindex('/', @input) = 0 then @input
        when charindex(' ', @input) = 0 then '0'
        else left(@input, charindex(' ', @input) - 1)
        end as int)

    select @dividend = cast(case
        when charindex('/', @input) = 0 then '0'
        when charindex(' ', @input) = 0 then left(@input, charindex('/', @input) - 1)
        else substring(@input, charindex(' ', @input) + 1, charindex('/', @input) - charindex(' ', @input) - 1)
        end as int)

    select @divisor = cast(case
        when charindex('/', @input) = 0 then '1'
        else right(@input, charindex('/', reverse(@input)) - 1)
        end as int)

    select @output = cast(@whole as float) + (cast(@dividend as float) / cast(@divisor as float))

    return @output
end

这样,你可以按函数的输出顺序排序:

select *
from MyTable
order by dbo.FractionToFloat(MyFractionColumn)

我通常不会建议您在数据更改时滚动自己必须维护的解析器,但这在表面上看起来很简单,并且可能比手动维护序数列更好。此外,如果你必须比较各种单位(英尺到英寸,分钟到几秒),那么这会变得更加复杂。我正在删除演示数据中看似单元的任何内容。

答案 2 :(得分:0)

忽略1/2可能意味着between 1 and 2的那一刻,你可以处理这种疯狂并尝试从中获得一些订单。

CREATE TABLE #Fractions (
   Frac varchar(15)
);

INSERT #Fractions VALUES
   ('1 1/2'), ('1 1/4'), ('1"'), ('1/2'), ('1/4'), ('1/8'),
   ('2 1/2'), ('2"'), ('3"'), ('3/4'), ('3/8'), ('4"');

WITH Canonical AS (
   SELECT
      Frac,
      F,
      CharIndex(' ', F) S,
      CharIndex('/', F) D
   FROM
      (SELECT Frac, Replace(Frac, '"', '') F FROM #Fractions) F
   WHERE
      F NOT LIKE '%[^0-9 /]%'
), Parts AS (
   SELECT
      Frac,
      Convert(int, Left(F, CASE WHEN D = 0 THEN Len(F) ELSE S END)) W,
      Convert(int, CASE WHEN D > 0 THEN Substring(F, S + 1, D - S - 1) ELSE '' END) N,
      Convert(int, CASE WHEN D > 0 THEN Substring(F, D + 1, 2147483647) ELSE '1' END) D
   FROM Canonical
)
SELECT
   Frac,
   W + N * 1.0 / D Calc
FROM Parts
ORDER BY Calc;

DROP TABLE #Fractions;

但我不推荐这个。使用我的查询作为基础来获取正确的值,并切换到使用小数值。

请注意,您还必须在数据中搜索此代码未考虑的字符,使用上面的模式匹配LIKE而不是NOT LIKE。然后删除它们或以某种方式解释它们。

如果你说的是1/2可能意味着两件事,并且你能说出它们之间的区别,那么你可以对此做些什么。将范围存储在两列中。如果它们相同则没有范围。

如果你无法区分这两种含义,那么你只是搞砸了,也可能放弃你的工作,去阿拉斯加的雪橇犬。