SQL Сервер - Использование функции ROW_NUMBER () OVER PARTITION для установки значения - PullRequest
0 голосов
/ 10 февраля 2020

Привет всем, спасибо, что нашли время, чтобы разобраться в моем вопросе,

Фон

Я использую функцию ROW_NUMER () вместе с PARTITION BY. Инструкция .ORDER BY для установки значения varchar с возрастающим значением int в конце его для каждого значения в одной из моих таблиц.

SELECT  component_module_id as component_module_id,
        component_property_id,
        'cf' + CAST(ROW_NUMBER() OVER (PARTITION BY component_module_id ORDER BY component_module_id) as VARCHAR) AS cf
FROM component_property

Здесь значение 'cf' происходит от cf1-cfX для каждого component_module_id

Sample Query Output

Мой вопрос

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

После вставки запроса выше во временную таблицу #t -

SELECT * FROM #t ORDER BY cf

I получить значения 'cf', которые начинаются с cf1 и переходят к cf10, а затем к cf100, с диапазоном значений cf от cf1 до cf900 ... Я должен получать только значения в диапазоне от c1 до cf29.

Мой вопрос здесь - почему значения в этом столбце обрабатываются иначе, чем любое другое нормальное значение? Почему вычисление ROW_NUMBER () OVER (PARTITION BY ....)) передается для дальнейших запросов в дальнейшем? (если это на самом деле то, что происходит). И наконец, как я могу обрабатывать эти значения 'cf' как обычные значения VARCHAR и не позволять им изменяться на меня всякий раз, когда я пытаюсь сгруппировать их или упорядочить по ним.

Спасибо за любую помощь!

Обновление

Я принял предложение от Ларну,

"Похоже, вам будет лучше просто сохранить значение int и использовать (PERSISTED) вычисляемый столбец для объединения вашего префикса и значения ROW_NUMBER. "

и мои значения 'cf' теперь отображаются правильно после сортировки. Спасибо всем, отметившим, как решено.

Ответы [ 4 ]

0 голосов
/ 10 февраля 2020

Обновление

Я принял предложение от Ларну,

"Похоже, вам будет лучше просто сохранить значение int и использовать вычисляемый столбец (PERSISTED) для объедините ваш префикс и значение ROW_NUMBER. "

и мои значения 'cf' теперь отображаются правильно после сортировки. Спасибо всем, отметившим, как решено.

0 голосов
/ 10 февраля 2020

Если вы сделаете это таким образом, это будет работать

SELECT * FROM #t ORDER BY component_module_id, cast(replace(cf, 'cf', '') as int)
0 голосов
/ 10 февраля 2020

Проблема в том, что вы оба делите на и , а на component_module_id. Внутри каждого раздела ключи заказа имеют одинаковое значение.

Почему это важно? Сортировка в SQL НЕ стабильна. Это означает, что связи могут быть решены в любом случае. Запустите запрос еще раз, и вы можете получить другой порядок (среди связей).

Простое решение состоит в том, чтобы изменить порядок на стабильный, и у вас есть только столбец, чтобы сделать это component_property_id , Я бы также порекомендовал использовать CONCAT(), чтобы вам не требовалось никаких преобразований типов:

SELECT component_module_id as component_module_id,
       component_property_id,
       CONCAT('cf',
              ROW_NUMBER() OVER (PARTITION BY component_module_id ORDER BY component_property_id)
             0 AS cf
FROM component_property

Следует также отметить, что ваш код использует VARCHAR без длины. Это действительно плохая идея на SQL сервере. Длина по умолчанию варьируется в зависимости от контекста и может быть недостаточно большой для определенных значений (хотя у вас нет такой проблемы в этом случае).

0 голосов
/ 10 февраля 2020

Попробуйте это

SELECT  component_module_id,
        component_property_id,
        'cf' + CAST(cf) AS VARCHAR(10)
FROM    (
            SELECT  component_module_id,
                    component_property_id,
                    ROW_NUMBER() OVER (PARTITION BY component_module_id ORDER BY component_module_id) AS cf
            FROM    component_property
        ) a
ORDER BY component_module_id

Вы испытываете такое поведение, потому что VARCHAR упорядочивает числа, выполняя сортировку по алфавиту

Вам необходимо выполнить упорядочение с помощью INT, а затем выполните конкатенацию в конце (обернув исходный запрос в подзапрос

. Однако в комментариях было предложено лучшее решение, заключающееся в том, чтобы хранить только числа как INT и добавлять префикс, используя вычисленный столбец (или на уровне запроса)

...