Естественный (алфавитно-цифровой человек) вид в Microsoft SQL 2005

Вам необходимо использовать «протоколы» для делегирования или предоставления данных в AsynTask.

Делегаты и источники данных

Делегат - это объект, который действует от имени, или в координации с другим объектом, когда этот объект встречает событие в программе. ( Определение Apple )

протоколы - это интерфейсы, которые определяют некоторые методы делегирования некоторых действий.

Вот полный пример !!!

44
задан ChrisF 11 March 2014 в 17:27
поделиться

7 ответов

Большинство SQL-решений, которые я видел, ломаются, когда данные становятся достаточно сложными (например, более одного-двух чисел в нем). Изначально я пытался реализовать в T-SQL функцию NaturalSort, которая удовлетворяла моим требованиям (среди прочего, обрабатывала произвольное количество чисел в строке), но производительность была way слишком медленной.

В конце концов, я написал скалярную функцию CLR на C#, чтобы обеспечить естественный вид, и даже с неоптимизированным кодом производительность, вызываемая из SQL Server, ослепительно быстра. Она обладает следующими характеристиками:

  • правильно сортирует первые 1000 символов или около того (легко модифицируется в коде или превращается в параметр)
  • корректно сортирует децималы, так что 123.333 идет раньше 123. 45
  • из-за вышесказанного, скорее всего, НЕ будет правильно сортировать такие вещи, как IP-адреса; если вы хотите иного поведения, модификация кода
  • поддерживает сортировку строки с произвольным количеством чисел внутри нее
  • будет правильно сортировать числа до 25 цифр длиной (легко модифицируется в коде или превращается в параметр)

Код здесь:

using System;
using System.Data.SqlTypes;
using System.Text;
using Microsoft.SqlServer.Server;

public class UDF
{
    [SqlFunction(DataAccess = DataAccessKind.None, IsDeterministic=true)]
    public static SqlString Naturalize(string val)
    {
        if (String.IsNullOrEmpty(val))
            return val;

        while(val.Contains("  "))
            val = val.Replace("  ", " ");

        const int maxLength = 1000;
        const int padLength = 25;

        bool inNumber = false;
        bool isDecimal = false;
        int numStart = 0;
        int numLength = 0;
        int length = val.Length < maxLength ? val.Length : maxLength;

        //TODO: optimize this so that we exit for loop once sb.ToString() >= maxLength
        var sb = new StringBuilder();
        for (var i = 0; i < length; i++)
        {
            int charCode = (int)val[i];
            if (charCode >= 48 && charCode <= 57)
            {
                if (!inNumber)
                {
                    numStart = i;
                    numLength = 1;
                    inNumber = true;
                    continue;
                }
                numLength++;
                continue;
            }
            if (inNumber)
            {
                sb.Append(PadNumber(val.Substring(numStart, numLength), isDecimal, padLength));
                inNumber = false;
            }
            isDecimal = (charCode == 46);
            sb.Append(val[i]);
        }
        if (inNumber)
            sb.Append(PadNumber(val.Substring(numStart, numLength), isDecimal, padLength));

        var ret = sb.ToString();
        if (ret.Length > maxLength)
            return ret.Substring(0, maxLength);

        return ret;
    }

    static string PadNumber(string num, bool isDecimal, int padLength)
    {
        return isDecimal ? num.PadRight(padLength, '0') : num.PadLeft(padLength, '0');
    }
}

Чтобы зарегистрировать это так, чтобы вы могли вызвать это с SQL-сервера, запустите следующие команды в Query Analyzer:

CREATE ASSEMBLY SqlServerClr FROM 'SqlServerClr.dll' --put the full path to DLL here
go
CREATE FUNCTION Naturalize(@val as nvarchar(max)) RETURNS nvarchar(1000) 
EXTERNAL NAME SqlServerClr.UDF.Naturalize
go

Затем, вы можете использовать это так:

select *
from MyTable
order by dbo.Naturalize(MyTextField)

Примечание: Если вы получите ошибку в SQL Server по строке Выполнение пользовательского кода в .NET Framework отключено. Включите опцию конфигурации "clr enabled". , следуйте инструкциям здесь , чтобы включить ее. Прежде чем это сделать, убедитесь в том, что Вы учитываете возможные последствия для безопасности. Если вы не являетесь администратором db, убедитесь, что вы обсудили это со своим администратором, прежде чем вносить какие-либо изменения в конфигурацию сервера.

Note2: Этот код не поддерживает должным образом интернационализацию (например, предполагает, что десятичный знак ".", не оптимизирован для скорости и т.д. Предложения по его улучшению приветствуются!

Редактирование: Переименование функции в Натурализация вместо NaturalSort, так как она не выполняет никакой реальной сортировки.

29
ответ дан 26 November 2019 в 21:51
поделиться

Я все еще не понимаю (вероятно, из-за моего плохого английского языка).

Вы могли попробовать:

ROW_NUMBER() OVER (ORDER BY dbo.human_sort(field_name) ASC)

, Но это не будет работать на миллионы записей.

Это, почему я предложил использовать триггер который заливки отдельный столбец с человеческая ценность .

, Кроме того:

  • встроенные функции T-SQL являются действительно медленными, и Microsoft предлагают использовать функции.NET вместо этого.
  • человеческая ценность является постоянной, таким образом, нет никакого смысла вычисляющего ее каждый раз, когда запрос работает.
-1
ответ дан Grzegorz Gierlik 26 November 2019 в 21:51
поделиться

Если Вы испытываете затруднения при загрузке данных от DB до вида в C#, то я уверен, что Вы будете разочарованы любым подходом при выполнении его программно в DB. Когда сервер собирается отсортировать, это получено для вычисления "воспринятого" порядка, как Вы имели бы - каждый раз.

я предложил бы, чтобы Вы добавили дополнительный столбец для хранения предварительно обработанной поддающейся сортировке строки, с помощью некоторого метода C#, когда данные сначала вставляются. Вы могли бы попытаться преобразовать численные данные в диапазоны фиксированной ширины, например, таким образом, "xyz1" превратится в "xyz00000001". Тогда Вы могли использовать нормальную сортировку SQL Server.

Рискуя тем, чтобы сигналить мой собственный рог, я написал статью CodeProject, реализовав проблему, как изложено в статье CodingHorror. Не стесняйтесь к кража от моего кода .

1
ответ дан Chris Wuestefeld 26 November 2019 в 21:51
поделиться

Я знаю, что это немного старо в этой точке, но в моем поиске лучшего решения, я столкнулся с этим вопросом. Я в настоящее время использую функцию для упорядочивания. Это хорошо работает для моей цели отсортировать записи, которые называют со смешанной числовой альфой ('объект 1', 'объект 10', 'объект 2', и т.д.)

CREATE FUNCTION [dbo].[fnMixSort]
(
    @ColValue NVARCHAR(255)
)
RETURNS NVARCHAR(1000)
AS

BEGIN
    DECLARE @p1 NVARCHAR(255),
        @p2 NVARCHAR(255),
        @p3 NVARCHAR(255),
        @p4 NVARCHAR(255),
        @Index TINYINT

    IF @ColValue LIKE '[a-z]%'
        SELECT  @Index = PATINDEX('%[0-9]%', @ColValue),
            @p1 = LEFT(CASE WHEN @Index = 0 THEN @ColValue ELSE LEFT(@ColValue, @Index - 1) END + REPLICATE(' ', 255), 255),
            @ColValue = CASE WHEN @Index = 0 THEN '' ELSE SUBSTRING(@ColValue, @Index, 255) END
    ELSE
        SELECT  @p1 = REPLICATE(' ', 255)

    SELECT  @Index = PATINDEX('%[^0-9]%', @ColValue)

    IF @Index = 0
        SELECT  @p2 = RIGHT(REPLICATE(' ', 255) + @ColValue, 255),
            @ColValue = ''
    ELSE
        SELECT  @p2 = RIGHT(REPLICATE(' ', 255) + LEFT(@ColValue, @Index - 1), 255),
            @ColValue = SUBSTRING(@ColValue, @Index, 255)

    SELECT  @Index = PATINDEX('%[0-9,a-z]%', @ColValue)

    IF @Index = 0
        SELECT  @p3 = REPLICATE(' ', 255)
    ELSE
        SELECT  @p3 = LEFT(REPLICATE(' ', 255) + LEFT(@ColValue, @Index - 1), 255),
            @ColValue = SUBSTRING(@ColValue, @Index, 255)

    IF PATINDEX('%[^0-9]%', @ColValue) = 0
        SELECT  @p4 = RIGHT(REPLICATE(' ', 255) + @ColValue, 255)
    ELSE
        SELECT  @p4 = LEFT(@ColValue + REPLICATE(' ', 255), 255)

    RETURN  @p1 + @p2 + @p3 + @p4

END

Затем вызов

select item_name from my_table order by fnMixSort(item_name)

, Это легко утраивает время обработки для простого чтения данных, таким образом, это не может быть идеальное решение.

6
ответ дан JazzHands 26 November 2019 в 21:51
поделиться
order by LEN(value), value

Не прекрасный, но работает хорошо в большом количестве случаев.

43
ответ дан Jeff Atwood 26 November 2019 в 21:51
поделиться

Вы можете использовать следующий код для решения проблемы:

Select *, 
    substring(Cote,1,len(Cote) - Len(RIGHT(Cote, LEN(Cote) - PATINDEX('%[0-9]%', Cote)+1)))alpha,
    CAST(RIGHT(Cote, LEN(Cote) - PATINDEX('%[0-9]%', Cote)+1) AS INT)intv 
FROM Documents 
   left outer join Sites ON Sites.IDSite = Documents.IDSite 
Order BY alpha, intv

С уважением, rabihkahaleh@hotmail.com

0
ответ дан Ian Boyd 26 November 2019 в 21:51
поделиться

Я только что где-то читал статью на эту тему. Ключевой момент: вам нужно только целочисленное значение для сортировки данных, в то время как строка 'rec' принадлежит UI. Вы можете разделить информацию на два поля, скажем, alpha и num, отсортировать по alpha и num (отдельно) и затем показать строку, составленную из alpha + num. Вы можете использовать вычисляемый столбец для составления строки или представления. Надеюсь, это поможет

0
ответ дан 26 November 2019 в 21:51
поделиться
Другие вопросы по тегам:

Похожие вопросы: