Конфликты collation в SQL Server: исправляем сравнения
Проверьте collation столбцов, базы и tempdb, сохранив смысл сравнений, уникальность ключей и эффективное использование существующих индексов.
Соединение таблиц может работать на одном SQL Server и перестать работать после восстановления базы на другом экземпляре: сравниваемые тексты получили разные collation. Добавление COLLATE до исчезновения ошибки иногда меняет и то, какие строки считаются совпадающими. Регистр, акценты и порядок сортировки являются частью контракта данных.
Сначала определите смысл идентификатора. Коды abc и ABC обозначают одного клиента или разных? Должен ли поиск имени игнорировать акценты, сохраняя исходное написание для отображения? Без такого решения технический конфликт нельзя исправить содержательно правильно.
Проверяем участвующие уровни
Настройки сервера, базы и конкретного столбца связаны, но не взаимозаменяемы.
SELECT SERVERPROPERTY('Collation') AS ServerCollation,
DATABASEPROPERTYEX(DB_NAME(), 'Collation') AS DatabaseCollation,
DATABASEPROPERTYEX(N'tempdb', 'Collation') AS TempdbCollation;
SELECT name AS ColumnName, collation_name
FROM sys.columns
WHERE object_id = OBJECT_ID(N'dbo.Customers')
AND collation_name IS NOT NULL;
Замените dbo.Customers на таблицу проблемного запроса. Текстовый столбец может отличаться от настройки базы по умолчанию. Восстановленная база сохраняет свои правила, а обычные временные столбцы на классическом SQL Server часто наследуют стандарт tempdb. Поэтому процедура способна сломаться только после переноса на другой сервер.
Unicode не отменяет collation. nvarchar меняет представление символов, но сравнение всё равно требует правил. Пример демонстрирует разные результаты.
SELECT
CASE WHEN N'Cafe' COLLATE Latin1_General_100_CI_AI = N'café'
THEN 1 ELSE 0 END AS InsensitiveMatch,
CASE WHEN N'Cafe' COLLATE Latin1_General_100_CS_AS = N'café'
THEN 1 ELSE 0 END AS SensitiveMatch;
InsensitiveMatch равен 1, SensitiveMatch равен 0. Первый вариант игнорирует регистр и акценты, второй различает оба свойства. Ни один результат не универсально верен. Поиск товара и ограничение уникальности могут обоснованно использовать разные требования.
Для многоязычного ввода используйте Unicode-литералы и правильно типизированные параметры. Поздний COLLATE не восстановит символы, потерянные при преобразовании через неподходящую не-Unicode кодовую страницу. Сначала проверьте входные преобразования и параметры.
Согласуем промежуточные данные
Если постоянный целевой столбец использует стандарт текущей базы, временный столбец может явно принять тот же стандарт.
-- Suitable when the target column uses the current database default.
CREATE TABLE #Incoming (
CustomerCode nvarchar(50) COLLATE DATABASE_DEFAULT NOT NULL
);
CREATE INDEX IX_Incoming_Code ON #Incoming(CustomerCode);
Это предотвращает случайное наследование другой настройки tempdb. Однако решение не универсально: если целевой столбец имеет собственную явную collation, промежуточный должен соответствовать именно ей. Важно также проверить контекст базы при создании временного объекта.
Для редкого межбазового запроса явный COLLATE у выражения может быть разумным. Выбирайте правило осознанно и смотрите фактический план. Другая collation на большом индексированном столбце может потребовать преобразования и затруднить использование существующего порядка. Приведение небольшого промежуточного набора с последующим индексированием иногда даёт более удобную постоянную границу.
LOWER или UPPER вокруг каждого сравнения не заменяют проектирование. Это добавляет вычисления для строк, усложняет индексный доступ и не обязательно правильно описывает акценты и языковые особенности. Если нужны нормализованные поисковые ключи, формируйте их по единому явному правилу.
Смена правил является миграцией
Изменение настройки базы по умолчанию автоматически не переписывает collation существующих пользовательских столбцов. Миграция должна учитывать столбцы, индексы, ограничения, вычисляемые выражения и межбазовых потребителей. Скрипты развёртывания и новые объекты тоже должны соответствовать выбранному результату.
До перестроения уникального индекса найдите значения, которые станут равными. Коды, различающиеся только регистром или акцентами, способны столкнуться. Нужна согласованная таблица соответствий, а не произвольное сохранение первой строки с потерей отношений второго клиента.
Сортировка влияет не только на равенство, но и на страницы выдачи и экспорт. Используйте уникальный дополнительный ключ и проверяйте реальные многоязычные значения вместо одних ASCII-примеров. Включайте разный регистр, акценты, пустые строки и принятые форматы идентификаторов. При интеграции отдельно сравните правила приложения: его проверка уникальности может не совпадать с правилами базы.
В завершение проверяйте результат и стоимость. Сопоставьте связанные идентификаторы, ненайденные промежуточные строки и дубликаты, затем логические чтения и план. Исчезновение ошибки доказывает только возможность выполнить запрос. Правильность бизнес-связей и сохранение приемлемого доступа требуют самостоятельной проверки.
Техническая документация: Microsoft Learn: Collation and Unicode · Microsoft Learn: COLLATE.