SQL Server - Order By Ascend, похоже, не работает - PullRequest
1 голос
/ 11 декабря 2019

У меня есть БД, которая создает записи для пользователей, и они могут создавать новые версии этих записей. Я отслеживаю старые записи, поэтому дифференцирую их, добавив столбец (VARCHAR (20)) в моей БД, в котором хранится версия данных. Я создал хранимую процедуру, которая принимает строки, соответствующие идентификатору пользователя, и упорядочивает версии в строке с версиями, разделенными '|'. Это работало некоторое время, но недавно пользователь создал 10-ую версию, и почему-то этот поток, кажется, нарушается. Ниже приведен SP:

DECLARE @IN_vsId VARCHAR(100)

SET @IN_vsId='user1'
SELECT @Version_str = COALESCE(@Version_str + '|', '') + VSN_NO 
FROM (
SELECT TOP 100 VSN_NO
FROM table1 myTable
WHERE myTable.ID = @IN_vsId
ORDER BY myTable.VSN_NO ASC
)VERSION_TBL

PRINT @Version_str

Когда у пользователя было <9 версий, строка выглядела бы как <code>1|2|3|4|5|6|7|8|9. Однако после создания 10-й версии она выглядит как 1|10|2|3|4|5|6|7|8|9. Я в недоумении здесь. Мой бэкэнд полагается на получение длины списка (я конвертирую его в список, как только я вернусь с моего SP) и выбор последнего индекса, который в этом случае всегда будет равен 9. Я могу изменить это в бэкэнде, просто получив max int из списка, но я хочу посмотреть, смогу ли я сначала изменить свою БД.

EDIT Ответы пока работают хорошо,за исключением того, что у меня было несколько версий с буквой «P» перед определенными типами пользовательских данных. Я добавил оператор if else для определения, будет ли строка иметь версию 'P', а затем сделал:

DECLARE @Version_str VARCHAR(100)
DECLARE @IN_vsId VARCHAR(100)
DECLARE @IN_vsType VARCHAR(100)

SET @IN_vsId='user1'

IF @IN_vsType='DRAFT'
BEGIN
    SELECT @Version_str = COALESCE(@Version_str + '|', '') + VSN_NO 
    FROM (
    SELECT TOP 100 VSN_NO
    FROM table1 myTable
    WHERE myTable.ID = @IN_vsId
    AND myTable.TYPE_NM = @IN_vsType
    )VERSION_TBL ORDER BY TRY_CAST(VSN_NO AS INT) ASC
END
IF @IN_vsType='PUBLISH'
BEGIN
SELECT @Version_str = COALESCE(@Version_str + '|', '') + VSN_NO 
    FROM (
    SELECT TOP 100 VSN_NO
    FROM table1 myTable
    WHERE myTable.ID = @IN_vsId
    AND myTable.TYPE_NM = @IN_vsType
    )VERSION_TBL ORDER BY TRY_CAST(SUBSTRING(VSN_NO, 2, LEN(VSN_NO)) AS INT) ASC 
END

PRINT @Version_str

В случае P я создаю подстроку, которая удаляет P, и приведучисла как int, как я их заказываю

Ответы [ 2 ]

1 голос
/ 11 декабря 2019

Проблема в том, что версия varchar, а не числовая какого-либо типа. В этом случае значения добавляются как «1», «2», «10» и т. Д.

При сортировке строки сначала сравниваются первые символы, затем вторые и т. Д. при сортировке в алфавитном порядке это правильно:

1
10
2
20

Вам необходимо, чтобы эти значения были либо дополнены нулями:

01
02
10
20

или для использования числового поля (int, numeric и т. д.)если вы хотите, чтобы они сортировались правильно.

Теперь, учитывая вашу новую информацию выше (некоторые коды начинаются с буквы), задача становится более сложной, но не управляемой. Попробуйте это для своего оператора ORDER BY (предполагается, что перед цифрами стоит только один буквенный символ, не предполагается, что у чего-то не может быть кодов как с буквенным, так и с цифровым):

ORDER BY CASE
    When IsNumeric(VSN_NO) = 1
        THEN RIGHT('000000' + VSN_NO, 6) -- assumes a max of six characters
    ELSE Left(VSN_NO, 1) + RIGHT('00000' + SUBSTRING(VSN_NO, 2, LEN(VSN_NO)), 5)
END ASC
1 голос
/ 11 декабря 2019

В SQL таблица представляет собой неупорядоченные наборы строк. Вам нужно предложение order by, чтобы упорядочить ваши данные. Неважно, что вы заказали результаты внутреннего запроса. С точки зрения внешнего запроса набор данных, который возвращается внутренним запросом, является просто неупорядоченным набором строк. Вам нужно сделать порядок во внешнем запросе.

Другая проблема заключается в том, что вы, похоже, храните числа в виде строк. Правила упорядочения строк не такие, как для числовых типов данных (обычно для строк '2 больше '10'). Вы можете привести к числовому типу данных перед сортировкой:

SET @IN_vsId='user1'
SELECT @Version_str = COALESCE(@Version_str + '|', '') + VSN_NO 
FROM (
    SELECT TOP 100 VSN_NO
    FROM table1 myTable
    WHERE myTable.ID = @IN_vsId
    ORDER BY CAST(VSN_NO AS INT) ASC
) VERSION_TBL
ORDER BY CAST(VSN_NO AS INT) ASC

Если существует риск того, что некоторые значения не могут быть преобразованы в число, вы можете использовать:

ORDER BY TRY_CAST(VSN_NO AS INT) ASC
...