Header RSS-подписка на обновления сайта eMail-подписка на обновления сайта

Понимаете ли вы коллейшены? Часть 2/8.

Коллейшен уровня базы данных.


366bef3a

Итак, мы спускаемся на уровень ниже. Тут надо сказать, что коллейшен предыдущий, «от инстанса», становится коллейшеном по умолчанию для всех, без исключения, объектов этого инстанса. Если при создании новой базы нас это устраивает (т.е. мы согласны «принять в наследство» значение коллейшена от экземпляра) — отлично, делать вообще ничего не надо. Однако база может «постановить», что в ее контексте коллейшен будет свой, отличный от экземплярного. Если это наш случай, то кое-какие шаги описанные ниже (впрочем, совсем несложные) предпринять придется.

Имейте, кстати, в виду, что идея «а сменю-ка я коллейшен у системной базы model — тогда все новые базы будут с этим новым коллейшеном!» выглядит заманчиво и вполне логично (ведь обсуждаемая опция уровня базы, а значит должна наследоваться от model!), но совершенно не реализуема. Потому как если вы попробуете дать команду

1
2
3
4
USE [master]
GO
ALTER DATABASE model COLLATE [collation_name]
GO

то получите в ответ вот это:

 Msg 3708, Level 16, State 5, Line 1
Cannot alter the database 'model' because it is a system database.
Set_collation_for_new_base

Иными словами, нужная нам опция несменяема у любой системной базы. У model в том числе. Так что придется или работать с каждой пользовательской базой индивидуально, или обратиться к предыдущему разделу.

Как установить значение для новой базы.

Если база создается через интерфейс студии — см. иллюстрацию справа. Если скриптом, то:

1
CREATE DATABASE [имя_базы] COLLATE [collation_name]
Как проверить текущее значение.

Если хотите воспользоваться интерфейсом студии: в окне Object Explorer вызываете окно свойств той базы данных чей коллейшен требуется проверить. На первой же странице открывшегося окна видите примерно такую информацию как на картинке ниже и левее. Если же значение текущего коллейшена требуется программно, в резалт-сете, то:

1
SELECT DATABASEPROPERTYEX('[имя_проверяемой_базы]', 'Collation')

Вам вернется резалт-сет из единственной ячейки в которой и будет требуемое значение.

Check_collation_on_base
Как изменить значение для существующей базы.

Сразу хочу успокоить — нет, тут сносить сервера не придется. :roll: К смене значения коллейшена у базы движок сервера относится куда лояльнее, чем к тому же процессу, но на уровень выше. Если вы хотите выполнить эту процедуру в студии: вызываете окно свойств базы (снова см. левый рисунок), переключаетесь там на закладку Options, и попадаете в совершенно тот же диалог который позволял вам установить коллейшен для новой базы (см. правую иллюстрацию). Выбираете новое значение из выпадающего списка и OK. Если тоже самое, но скриптом, то:

1
ALTER DATABASE [имя_базы] COLLATE [collation_name]

где [collation_name] есть имя нового коллейшена.

Коллейшен уровня колонки таблицы.

Спускаемся еще ниже и представим себе такой сценарий: коллейшен всего сервера у нас французский, коллейшен текущей базы русский. Тогда в ее контексте применяется русская же кодовая страница (если только мы работаем не с юникодом) и, безусловно, так же применяются правила сопоставления строк ожидаемые человеком у которого родной язык — русский. Но в той же базе есть одна таблица для наших японских клиентов. Русская кодовая страница и русские же правила — не совсем то, что они ожидают, надо полагать. Можем ли мы для этой таблицы установить свой, персональный коллейшен? Ну прямо вот для всей таблицы целиком — все же нет, не можем. А вот для отдельных ее колонок (от одной до всех составляющих эту таблицу) — вполне. И тогда только для этих колонок коллейшен будет не серверный, не БД-шный, а тот что мы назначим.

Как установить значение для новой колонки.

Понятно, что возникновение новой колонки как отдельное событие невозможно, а возможно лишь как составная часть события более общего, возникновения новой таблицы. Соответственно, если вы «ваяете» вашу новую таблицу в дизайнере студии, то сначала в нем нужно выбрать ту колонку, чей коллейшен мы намерены изменить:

New_table_designer

Далее опускаем глаза вниз, к панели Column Properties и находим в последней строчку свойства Collation:

Column_properties

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

Set_collation_for_new_column

Этот диалог несколько ближе к тому, что использовался при назначении коллейшена новому экземпляру сервера, нежели диалогу назначения коллейшена для БД. Однако суть всех трех диалогов, их функционал, совпадает на 100%: из всего множества коллейшенов в принципе доступных как альтернативы позволить нам выбрать единственный. Когда мы будем удовлетворены сделанным выбором — OK и цель достигнута, колонка имеет коллейшен отличный от базового. Наконец, обратите внимание, что дизайнер таблиц достаточно интеллектуален, что бы не позволить вам назначить коллейшен для колонки ошибочного типа (кстати, проверьте себя: можете ли вы назвать все 6 типов данных чье поведение и, возможно, визуальное представление зависит от выбранного коллейшена?). Для подобных колонок кнопки вызова последнего диалога просто не будет.

Если вы (как и я) сторонник создания новых объектов скриптами и дизайнер недолюбливаете, то, в данном случае, все еще проще:

1
2
3
CREATE TABLE MyTable
(PK int NOT NULL,
MyCol char(30) COLLATE [collation_name] NULL)

Имейте в виду интересный студийный баг (который на самом деле окажется «фичей») связанный с генерацией скриптов тех таблиц, что имеют колонки с «принудительным» коллейшеном. Заключается он в том, что если вы после создания таблицы вроде MyTable в последнем скрипте (причем способ создания такой таблицы роли не играет, важно что она есть и содержит колонки с назначенным им коллейшеном) захотите ее заскриптовать (пункты Script Table As→CREATE To→New Query Editor Window в контекстном меню этой таблицы), то скрипт не учтет все и любые коллейшены назначенные для отдельных колонок. Т.е. попросту их проигнорирует. Проверили? Игнорирует? А теперь идем в студийное меню Tools→Options:

Tools_Options_include_collation

После выставления указанной опции в указанное значение все нормализуется, коллейшен колонок учитывается. Кому потребовалось ставить эту опцию в false по умолчанию — ума не приложу. Враги? Диверсия? :idea: Правда — да, имейте в виду небольшой такой (с моей скромной точки зрения) «drawback» после перевода указанной опции в true: коллейшен при генерации скриптов будет добавлен всем строковым колонкам, не важно совпадает он с коллейшеном базы данных или является «индивидуальным». В первом случае значение коллейшена будет браться именно «из базы». Ну да, объем скриптов несколько возрастет, это факт. Но как представляется автору такая плата вполне «подъемна», с учетом что будет решен вопрос куда как более важный: поддержания синхронизированных коллейшенов таблиц на, допустим, сервере разработки, тестовом сервере и «продакшен»-сервере. Впрочем выбор, как и всегда, за вами.

Как проверить текущее значение.
Check_collation_on_column

Если вы, опять же, сторонник студии и ее интерфейсов — открывайте окно свойств той колонки чье текущее значение коллейшена вызывает у вас вопрос. На первой же странице, как показывает правая иллюстрация, находится искомое. Обратите внимание, что для всех не символьных колонок эта строка свойств будет просто пуста, а для всех символьных — заполнена в обязательном порядке. Для колонок которым были назначены персональные коллейшены здесь будут указаны именно они, для тех же кто такой чести не удостоился будет показан коллейшен «от базы данных». Ну а для извлечения той же информации программным способом вполне годится скрипт:

1
2
3
4
USE [имя_базы]
GO
SELECT name, collation_name FROM sys.columns
WHERE OBJECT_ID=OBJECT_ID('[схема].[таблица]') AND name = '[имя_колонки]'
Как изменить значение для существующей колонки.

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

1
ALTER TABLE MyTable ALTER COLUMN MyCol varchar(30) COLLATE [collation_name] NULL