Вам необходимо использовать «протоколы» для делегирования или предоставления данных в AsynTask
.
Делегаты и источники данных
Делегат - это объект, который действует от имени, или в координации с другим объектом, когда этот объект встречает событие в программе. ( Определение Apple )
протоколы - это интерфейсы, которые определяют некоторые методы делегирования некоторых действий.
Большинство SQL-решений, которые я видел, ломаются, когда данные становятся достаточно сложными (например, более одного-двух чисел в нем). Изначально я пытался реализовать в T-SQL функцию NaturalSort, которая удовлетворяла моим требованиям (среди прочего, обрабатывала произвольное количество чисел в строке), но производительность была way слишком медленной.
В конце концов, я написал скалярную функцию CLR на C#, чтобы обеспечить естественный вид, и даже с неоптимизированным кодом производительность, вызываемая из SQL Server, ослепительно быстра. Она обладает следующими характеристиками:
Код здесь:
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, так как она не выполняет никакой реальной сортировки.
Я все еще не понимаю (вероятно, из-за моего плохого английского языка).
Вы могли попробовать:
ROW_NUMBER() OVER (ORDER BY dbo.human_sort(field_name) ASC)
, Но это не будет работать на миллионы записей.
Это, почему я предложил использовать триггер который заливки отдельный столбец с человеческая ценность .
, Кроме того:
Если Вы испытываете затруднения при загрузке данных от DB до вида в C#, то я уверен, что Вы будете разочарованы любым подходом при выполнении его программно в DB. Когда сервер собирается отсортировать, это получено для вычисления "воспринятого" порядка, как Вы имели бы - каждый раз.
я предложил бы, чтобы Вы добавили дополнительный столбец для хранения предварительно обработанной поддающейся сортировке строки, с помощью некоторого метода C#, когда данные сначала вставляются. Вы могли бы попытаться преобразовать численные данные в диапазоны фиксированной ширины, например, таким образом, "xyz1" превратится в "xyz00000001". Тогда Вы могли использовать нормальную сортировку SQL Server.
Рискуя тем, чтобы сигналить мой собственный рог, я написал статью CodeProject, реализовав проблему, как изложено в статье CodingHorror. Не стесняйтесь к кража от моего кода .
Я знаю, что это немного старо в этой точке, но в моем поиске лучшего решения, я столкнулся с этим вопросом. Я в настоящее время использую функцию для упорядочивания. Это хорошо работает для моей цели отсортировать записи, которые называют со смешанной числовой альфой ('объект 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)
, Это легко утраивает время обработки для простого чтения данных, таким образом, это не может быть идеальное решение.
order by LEN(value), value
Не прекрасный, но работает хорошо в большом количестве случаев.
Вы можете использовать следующий код для решения проблемы:
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
Я только что где-то читал статью на эту тему. Ключевой момент: вам нужно только целочисленное значение для сортировки данных, в то время как строка 'rec' принадлежит UI. Вы можете разделить информацию на два поля, скажем, alpha и num, отсортировать по alpha и num (отдельно) и затем показать строку, составленную из alpha + num. Вы можете использовать вычисляемый столбец для составления строки или представления. Надеюсь, это поможет