Руководство по переходу с MySQL на SQL Server 2005

advertisement
Руководство по переходу с MySQL
на SQL Server 2005
Технический документ по SQL Server
Авторы: Александр Павлов, Юрий Русаков
Технические рецензенты: Ирина Балина, Дмитрий Балин
Дата публикации: март 2008 г.
Применяется к: SQL Server 2005 с пакетом обновления 2
Сводка: в данном руководстве по переходу описываются различия между СУБД MySQL
и SQL Server 2005, а также действия, необходимые для преобразования баз данных MySQL
в базы данных SQL Server.
Авторские права
Содержащиеся в документе сведения отражают текущую позицию корпорации Майкрософт
в отношении обсуждаемых вопросов на момент публикации. Поскольку корпорация Майкрософт
должна реагировать на изменение рыночных условий, данный документ не следует рассматривать как обязательство со стороны корпорации Майкрософт и корпорация Майкрософт
не гарантирует точности представленных сведений после его публикации.
Данный документ носит исключительно информационный характер. КОРПОРАЦИЯ МАЙКРОСОФТ
НЕ ПРЕДОСТАВЛЯЕТ НИКАКИХ ГАРАНТИЙ, ЯВНЫХ, ПОДРАЗУМЕВАЕМЫХ ИЛИ ПРЕДУСМОТРЕННЫХ ЗАКОНОМ, ОТНОСИТЕЛЬНО СВЕДЕНИЙ, СОДЕРЖАЩИХСЯ В ДАННОМ ДОКУМЕНТЕ.
Ответственность за соблюдение всех применимых законов об авторском праве лежит на
пользователе. Согласно законам об авторских правах никакие части этого документа нельзя
воспроизводить, хранить или использовать в поисковых системах или передавать в любой
форме (электронной, механической, в виде фотокопий, записей или иными способами) и
в любых целях без письменного разрешения корпорации Майкрософт.
Корпорация Майкрософт может являться правообладателем патентов и поданных заявок на
получение патента, товарных знаков, авторских прав и прочих объектов интеллектуальной
собственности, которые имеют отношение к содержанию данного документа. Предоставление
документа не означает передачи какой-либо лицензии на использование таких патентов, товарных
знаков, авторских прав и других объектов интеллектуальной собственности, за исключением
случаев, явно оговоренных в лицензионном соглашении корпорации Майкрософт.
© Корпорация Майкрософт (Microsoft Corporation), 2008. Все права защищены.
Microsoft, SQL Server и Visual C++ являются охраняемыми товарными знаками корпорации
Майкрософт в США и других странах.
Использованные в документе названия реальных компаний или продуктов могут быть
товарными знаками соответствующих владельцев.
Содержание
Введение ............................................................................................................................................. 3
Переход с MySQL на SQL Server 2005............................................................................................ 3
Основные действия переноса ..................................................................................................... 3
Преобразование объектов базы данных .................................................................................... 4
Перенос типов данных MySQL ....................................................................................................... 4
Сопоставление типов ................................................................................................................... 5
Проблемы переноса типов данных ............................................................................................. 8
Числовые типы данных .......................................................................................................... 8
Типы данных даты и времени ............................................................................................. 11
Строковые типы .................................................................................................................... 14
Типы данных ENUM и SET .................................................................................................. 16
Другие типы данных ............................................................................................................. 20
Неявное преобразование типов данных ............................................................................ 20
Значения типов данных по умолчанию .............................................................................. 21
Проблемы перехода с MySQL ....................................................................................................... 22
Операторы ................................................................................................................................... 22
Операторы сравнения ......................................................................................................... 22
Битовые операторы ............................................................................................................. 24
Операторы присвоения........................................................................................................ 25
Переменные ................................................................................................................................ 26
Служебные инструкции .............................................................................................................. 28
Инструкции определения данных ............................................................................................. 29
Предложения IF NOT EXISTS, IF EXISTS и REPLACE ..................................................... 29
Временные таблицы ............................................................................................................ 35
Ключевое слово SCHEMA в инструкциях DATABASE ...................................................... 39
Предложения CHARACTER SET и COLLATE в инструкциях DDL ................................... 39
Инструкция CREATE INDEX ................................................................................................ 40
Инструкция CREATE TABLE ................................................................................................ 43
Инструкция ALTER TABLE ................................................................................................... 48
Инструкция RENAME DATABASE ....................................................................................... 53
Инструкция RENAME TABLE ............................................................................................... 54
Инструкции CREATE VIEW, ALTER VIEW, DROP VIEW ................................................... 55
Инструкции CREATE EVENT, ALTER EVENT, DROP EVENT ........................................... 57
Инструкции CREATE, ALTER, DROP PROCEDURE/FUNCTION ...................................... 57
Инструкции обработки данных .................................................................................................. 62
Предложение LIMIT .............................................................................................................. 62
Инструкция DELETE ............................................................................................................. 63
Инструкция UPDATE ............................................................................................................ 65
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
2
Инструкция INSERT.............................................................................................................. 66
Инструкция REPLACE .......................................................................................................... 69
Инструкция SELECT ............................................................................................................. 70
Инструкции SELECT…INTO и LOAD DATA INFILE............................................................ 71
Предложения GROUP BY, HAVING и ORDER BY ............................................................. 72
Соединения JOIN ................................................................................................................. 75
Subqueries ............................................................................................................................. 78
Подготовленные инструкции ............................................................................................... 79
Команда DO .......................................................................................................................... 79
Обработчики ......................................................................................................................... 80
Модификаторы ..................................................................................................................... 81
Инструкции транзакций и блокировки ....................................................................................... 81
Инструкции BEGIN TRANSACTION..................................................................................... 81
Инструкции END TRANSACTION ........................................................................................ 83
Именованные инструкции SAVEPOINT транзакций .......................................................... 83
Инструкции SET AUTOCOMMIT .......................................................................................... 85
Инструкции LOCK TABLES и UNLOCK TABLES ................................................................ 86
Инструкция SET TRANSACTION ISOLATION LEVEL ........................................................ 86
Инструкции транзакций XA .................................................................................................. 86
Инструкции администрирования баз данных ........................................................................... 87
Инструкции управления учетными записями .................................................................... 87
Инструкции обслуживания таблиц ...................................................................................... 87
Инструкция SET .................................................................................................................... 87
Инструкция SHOW ................................................................................................................ 89
Другие административные инструкции .............................................................................. 90
Хранимые процедуры и функции (процедуры) ........................................................................ 90
Инструкции CALL .................................................................................................................. 90
Составные инструкции ......................................................................................................... 91
Локальные переменные ....................................................................................................... 92
Условия и обработчики ........................................................................................................ 95
Курсоры ................................................................................................................................. 96
Конструкции управления потоком ....................................................................................... 98
Процедуры .......................................................................................................................... 101
Триггеры .................................................................................................................................... 102
Режим SQL (системная переменная SQL_MODE) ................................................................ 105
Перенос системных функций MySQL ........................................................................................ 106
Эквивалентные функции .......................................................................................................... 106
Неподдерживаемые функции .................................................................................................. 106
Эмулируемые функции ............................................................................................................ 106
Заключение .................................................................................................................................... 113
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
3
Введение
В этом руководстве по переходу дается обзор процедур, проблем и решений для перехода
с MySQL 5 на Microsoft® SQL Server™ 2005.
Здесь представлены три основных раздела:
Перенос типов данных MySQL. Описывается сопоставление типов данных, и добавляются
примечания о соответствующих проблемах преобразования.
Проблемы перехода с MySQL. Дается обзор трудностей, с которыми можно столкнуться
при переходе с MySQL на SQL Server 2005, и предлагаются возможные решения.
Перенос системных функций MySQL. Рассматриваются обращения к системным функциям
MySQL, подразделяемым на эквивалентные функции, неподдерживаемые функции и
эмулируемые функции.
Переход с MySQL на SQL Server 2005
Ниже описываются основные, обобщенные действия для переноса баз данных MySQL на SQL
Server 2005, а также то, что необходимо знать о преобразовании объектов базы данных.
Основные действия переноса
Перенос баз данных MySQL
1. Решите, как будете сопоставлять базы данных MySQL с SQL Server 2005. Имеются две
основные возможности:

Сопоставить каждую базу данных MySQL с отдельной базой данных SQL Server. Например,
можно сопоставить базу данных MySQL MyDB с базой данных SQL Server MyDB.

Сопоставить каждую базу данных MySQL с единой базой данных SQL Server, но с
отдельной схемой. Например, можно сопоставить базу данных MySQL MyDB с базой
данных SQL Server MySQLDatabases и схемой MyDB.
В SQL Server схемы не обязательно привязаны к определенному пользователю или входу
в систему и на одном сервере содержится несколько баз данных.
2. Преобразуйте объекты баз данных: это таблицы, ограничения таблиц, индексы, представления,
процедуры, функции и триггеры.
3. Сопоставьте типы данных из MySQL с типами данных в SQL Server.
4. Перепишите представления, процедуры и функции в соответствии с синтаксисом SQL Server.
5. Если необходимо, измените приложения таким образом, чтобы они могли подключаться
к SQL Server 2005 и работать с данными.
После успешного преобразования базы данных перенесите данные из прежней базы данных
MySQL во вновь созданную базу данных SQL Server 2005. Для этого можно использовать,
например, службы интеграции SQL Server (SQL Server Integration Service, SSIS).
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
4
Преобразование объектов базы данных
В этом разделе приводятся некоторые соображения, которые необходимо принять во внимание
при преобразовании объектов базы данных.
Имена объектов схемы
В SQL Server 2005 имя объекта может содержать до 128 символов.
Имена идентификаторов, не заключаемых в кавычки, должны подчиняться следующим правилам:

Первым символом должны быть буква, цифра, подчеркивание (_), знак @ или знак номера (#).

В качестве последующих символов можно использовать буквы, цифры, подчеркивание, знак @,
знак номера, знак доллара.

Нельзя указывать в качестве идентификатора зарезервированное слово Transact-SQL.

Внутри имени нельзя использовать пробелы или специальные символы.
Идентификаторы, начинающиеся со знака @ или знака номера, имеют особые значения.
Со знака @ начинаются имена локальных переменных. Со знака номера начинаются имена
временных таблиц.
Для заключения в кавычки имени идентификатора в Transact-SQL необходимо использовать
квадратные скобки ([]).
Таблицы, ограничения, индексы и представления
Для преобразования таблиц используйте сопоставление типов данных столбцов
(см. раздел Сопоставление типов далее в этом руководстве).
В SQL Server 2005 поддерживаются следующие ограничения таблиц (столбцов): NOT NULL,
UNIQUE, PRIMARY KEY, FOREIGN KEY, CHECK. Преобразуйте каждый тип ограничения
в соответствии с синтаксисом Transact-SQL.
Инструкции SELECT с предложением VIEW также следует преобразовать соответственно
синтаксису Transact-SQL.
Хранимые процедуры и пользовательские функции
Преобразуйте хранимые процедуры и функции с использованием синтаксиса Transact-SQL.
SQL Server 2005 не поддерживает инструкции DML в пользовательских функциях. Это означает,
что вы не можете изменить какие-либо данные изнутри функции.
Триггеры
В SQL Server 2005 отсутствуют триггеры BEFORE.
Преобразуйте несколько триггеров BEFORE в единый триггер INSTEAD OF.
Перенос типов данных MySQL
В этом разделе описываются сопоставления типов данных MySQL и SQL Server 2005 и различия
между ними, обработка определенных типов данных, а также предлагаются решения проблем,
связанных с типами данных.
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
5
Сопоставление типов
Ниже приведено рекомендуемое сопоставление типов для преобразования столбцом таблиц,
аргументов подчиненных процедур, возвращенных значений и локальных переменных типов
данных.
Тип в MySQL
Сопоставление
в SQL Server 2005
Примечания
BIT (N)
varbinary (8)
Двоичное значение длиной
N бит. N = 1..64
TINYINT (M)
tinyint
M — количество десятичных
знаков в выходных данных
для этого значения
tinyint, smallint, int, bigint,
numeric(p,s), decimal(p,s),
float(p), double precision,
real, smallmoney, money
SMALLINT (M)
smallint
M — количество десятичных
знаков в выходных данных
для этого значения
tinyint, smallint, int, bigint,
numeric(p,s), decimal(p,s),
float(p), double precision,
real, smallmoney, money
MEDIUMINT (M)
int
M — количество десятичных
знаков в выходных данных
для этого значения
tinyint, smallint, int, bigint,
numeric(p,s), decimal(p,s),
float(p), double precision,
real, smallmoney, money
INT (M)
int
M — количество десятичных
знаков в выходных данных
для этого значения
tinyint, smallint, int, bigint,
numeric(p,s), decimal(p,s),
float(p), double precision,
real, smallmoney, money
BIGINT (M)
bigint
M — количество десятичных
знаков в выходных данных
для этого значения
tinyint, smallint, int, bigint,
numeric(p,s), decimal(p,s),
float(p), double precision,
real, smallmoney, money
FLOAT (P)
float (P)
FLOAT [(P, S)]
float (24)
DOUBLE [(P, S)]
float (53)
BOOL,
BOOLEAN =
TINYINT (1)
INTEGER (M)
DOUBLE
PRECISION [(P, S)]
REAL [(P, S)]
Возможное
сопоставление
numeric(p,s), decimal(p,s),
float(p), double precision,
real, smallmoney, money
В MySQL допускается
нестандартный синтаксис:
FLOAT(P,S), или REAL(P,S),
или DOUBLE
PRECISION(P,S). Здесь
«(P,S)» означает, что
отображается до P знаков
значения, из которых до S
знаков может быть после
запятой. MySQL выполняет
округление при сохранении
значений.
numeric(p,s), decimal(p,s),
float(p), double precision,
real, smallmoney, money
numeric(p,s), decimal(p,s),
float(p), double precision,
real, smallmoney, money
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
6
Если M и D опущены, предельный размер хранящихся
значений определяется
возможностями оборудования
DECIMAL [(P [,
S])]
decimal [(P [, S])]
numeric [(P [, S])]
DEC [(P [, S])]
NUMERIC [(P [,
S])]
FIXED [(P [, S])]
Десятичные типы могут
содержать до 65 цифр. Для
десятичных значений с
точностью свыше 38
необходимо использовать
тип данных float или double
numeric(p,s),
decimal(p,s), float(p),
double precision, real,
smallmoney, money
В MySQL можно сохранять
даты с 0000-00-по 9999-12-31.
В MySQL можно сохранять
нулевое значение года,
месяца и дня
smalldatetime, datetime
DATETIME
datetime
DATE
datetime
TIME
datetime
Диапазон от -838:59:59
до 838:59:59
smalldatetime, datetime,
varchar, nvarchar
TIMESTAMP
smalldatetime
Диапазон — с 1970-01-01
00:00:00 до 2037 года включительно. Если не определено при преобразовании,
данный тип получает текущее значение datetime
datetime, rowversion,
timestamp, varbinary(8),
binary(8)
YEAR [(2| 4)]
smallint
В четырехзначном формате
доступные значения — с
1901 по 2155, а также 0000.
В двухзначном формате
доступные значения — с 70
по 69 (что соответствует
годам с 1970 по 2069)
datetime, varchar(4)
[NATIONAL]
CHAR (N)
nchar (N)
Диапазон N — от 0 до 255
знаков
char, varchar, nchar,
nvarchar
Диапазон N — от 0 до
65 535.
char, varchar, nchar,
nvarchar
nchar
smalldatetime, datetime
[NATIONAL]
CHAR
[NATIONAL]
VARCHAR (N)
CHARACTER
VARYING (N)
nvarchar (N | max)
Если N<=8000, то используется nvarchar(N), в противном случае —
nvarchar(max)
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
TINYTEXT
nvarchar (255)
TEXT (N)
nvarchar (N | max)
7
char, varchar, nchar,
nvarchar
Текстовый столбец длиной
до 65 535 знаков.
Если N<=8000, то
используется nvarchar(N),
в противном случае —
nvarchar(max)
char, varchar, nchar,
nvarchar, varchar(max),
nvarchar(max)
MEDIUMTEXT
nvarchar (max)
char, varchar, nchar,
nvarchar, varchar(max),
nvarchar(max)
LONGTEXT
nvarchar (max)
char, varchar, nchar,
nvarchar, varchar(max),
nvarchar(max)
BINARY (N)
binary (N)
binary, varbinary, char,
varchar, nchar, nvarchar
VARBINARY (N)
varbinary (N)
binary, varbinary, char,
varchar, nchar, nvarchar
TINYBLOB
varbinary (255)
binary, varbinary,
varbinary(max)
BLOB (N)
varbinary (N |
max)
Столбец BLOB длиной
до 65 535 знаков.
binary, varbinary,
varbinary(max)
Если N<=8000, то
используется nvarchar(N),
в противном случае —
nvarchar(max)
MEDIUMBLOB
varbinary (max)
binary, varbinary,
varbinary(max)
LONGBLOB
varbinary (max)
binary, varbinary,
varbinary(max)
ENUM
См. типы данных ENUM и
SET в данном руководстве.
SET
См. типы данных ENUM и
SET в данном руководстве.
Примечание. Числовые типы MySQL имеют флаг UNSIGNED. Их следует преобразовывать
в более крупный числовой тип.
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
8
Проблемы переноса типов данных
В этом разделе описываются проблемы, возникающие при преобразовании типов данных. Причина
каждой проблемы заключается в функции MySQL, которая не поддерживается в SQL Server.
Числовые типы данных
Проблема: беззнаковые типы данных
Все целые типы данных в MySQL (TINYINT, SMALLINT, MEDIUMINT, INT, BIGINT) могут иметь
дополнительный атрибут UNSIGNED. Беззнаковые значения можно использовать, чтобы
разрешить в столбце только неотрицательные значения, когда требуется большой верхний
предел диапазона допустимых значений для столбца.
Используя беззнаковые значения, можно также разрешить только неотрицательные значения
в столбцах, содержащих типы данных с плавающей (FLOAT, DOUBLE) и фиксированной
запятой (DECIMAL).
Пример
create table numeric_unsigned (t tinyint unsigned, s smallint unsigned,
m mediumint unsigned, i int unsigned, b bigint unsigned);
insert numeric_unsigned values
(255, 65535, 16777215, 4294967295, 18446744073709551615);
create table point_unsigned (f float unsigned, d double unsigned);
insert point_unsigned values (-1.1234567890,-1.12345678901234567890);
insert point_unsigned values ( 5.1234567890, 5.12345678901234567890);
select * from point_unsigned;
--
0
0
-- 5.12346 5.12345678901235
Решение
Для исключения отрицательных значений используйте ограничения CHECK. Это самый простой
способ, но у него имеется один недостаток — при попытке назначить недопустимое значение
вы получите исключение.
Можно также исключать отрицательные значения с помощью триггера INSERT или UPDATE.
Этот метод позволяет корректировать недопустимые значения перед сохранением их в базу
данных.
Проблема: операции с беззнаковыми значениями
При вычитании целочисленных значений, одно из которых имеет тип UNSIGNED, результат
будет беззнаковым.
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
9
Пример
create table unsing (a int unsigned, b int);
insert unsing values (1,2),(4,3),(10,100);
select a-b from unsing;
-- 18446744073709551615
-- 1
-- 18446744073709551526
Решение
Используйте функцию CASE, чтобы вычислить результат операции с беззнаковыми значениями.
Проблема: ширина отображения целочисленных значений и атрибут ZEROFILL
В MySQL можно указывать ширину отображения целого (TINYINT, SMALLINT, MEDIUMINT,
INT, BIGINT) значения в скобках следом за базовым ключевым словом типа (например, INT(4)).
Это необязательное указание ширины отображения применяется для дополнения пробелами
слева отображения тех чисел, ширина которых меньше ширины, указанной для столбца.
Ширина отображения не ограничивает ни диапазон значений, которые можно сохранять
в столбце, ни число цифр, отображаемых для значений, ширина которых превышает ширину,
указанную для столбца.
См. также: атрибут ZEROFILL
Решение
Пропускайте эти атрибуты во время преобразования. Форматируйте выводимые данные
с помощью таких функций, как STR и CONVERT.
Проблема: атрибут ZEROFILL
При использовании совместно с дополнительным атрибутом ZEROFILL вместо применяемого
по умолчанию дополнения пробелами в MySQL используется дополнение нулями.
Если атрибут ZEROFILL указывается для числового столбца, MySQL автоматически добавляет
столбцу атрибут UNSIGNED.
Пример
create table table_zerofill (a int(2) zerofill, b int(4) zerofill,
c int(8) zerofill, d decimal(5,2) zerofill);
insert table_zerofill values (2,4,8,1.23);
select concat('BEGIN',a,b,c,d,'END') from table_zerofill
-- BEGIN02000400000008001.23END
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
10
create table point_zerofill (f float zerofill, d double zerofill);
insert point_zerofill values (-1.1234567890,-1.12345678901234567890);
insert point_zerofill values ( 5.1234567890, 5.12345678901234567890);
select * from point_zerofill;
-- 000000000000 0000000000000000000000
-- 000005.12346 0000005.12345678901235
Решение
Пропускайте эти атрибуты во время преобразования. Форматируйте выводимые данные
с помощью таких функций, как STR, REPLICATE и REPLACE.
Проблема: точность и масштаб типов данных FLOAT и DOUBLE
В MySQL типы данных FLOAT и DOUBLE могут иметь точность и масштаб.
Пример
create table table_float (f2 float|double(10,2),
f5 float|double(10,5), f7 float|double(10,7));
insert into table_float values (1.1234567,1.1234567,1.1234567);
insert into table_float values
(12345.1234567,12345.1234567,12345.1234567);
select * from table_float;
--
1.12
1.12346
1.1234567
-- 12345.12 12345.12305 1000.0000000
Решение
Значения типа FLOAT и DOUBLE с точностью и масштабом можно округлять в триггерах
или в инструкциях DML при помощи функции ROUND.
Проблема: максимальное количество цифр для типа данных DECIMAL
В MySQL максимальное количество цифр для типа данных DECIMAL равно 65.
Пример
create table table_decimal (d decimal(65), m decimal(65,30));
insert table_decimal values
(1234567890123456789012345678901234567890123456789012345678901234567890,
1234567890123456789012345678901234567890123456789012345678901234567890);
select * from table_decimal;
-- 99999999999999999999999999999999999999999999999999999999999999999
-- 99999999999999999999999999999999999.999999999999999999999999999999
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
11
Решение
Для десятичных значений с точностью свыше 38 необходимо использовать тип данных
float или double.
Типы данных даты и времени
Проблема: «нулевые» значения
В MySQL можно сохранять значение «0000-00-00» в качестве «фиктивной даты»,
если не используется SQL-режим NO_ZERO_DATE.
Недопустимые значения DATETIME, DATE, YEAR или TIMESTAMP преобразуются в «нулевое»
значение соответствующего типа ('0000-00-00 00:00:00', '0000-00-00' или '0000').
Для типов времени и даты, отличных от TIMESTAMP в MySQL, по умолчанию используется
нулевое значение соответствующего типа. Для первого столбца TIMESTAMP в таблице
в качестве значения по умолчанию используются текущая дата и время.
Пример
create table date_zero (dt datetime not null, d date not null,
t time not null, y year not null, ts timestamp not null)
insert date_zero values ();
select * from date_zero;
-- 0000-00-00 00:00:00 | 0000-00-00 | 00:00:00 | 0000 | 2006-12-19
18:24:49
insert date_zero values
('20060229150000','20060229','900:15:20','0321','19000101140000');
select * from date_zero;
-- 0000-00-00 00:00:00 | 0000-00-00 | 838:59:59 | 0000 | 0000-00-00
00:00:00
Решение
Замените нулевые значения даты датой «01 января 1753 г.».
Примените другой метод для сохранения нулевых дат с использованием строкового
или числового типа данных.
Проблема: нули в значениях года, месяца и числа
В MySQL можно сохранять даты с нулевым значением года, месяца и числа в столбце DATE
или DATETIME.
Пример
create table date_zeropart (d datetime null);
insert date_zeropart values
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
12
('00001215'),('20060015'),('20061200'),('20060000'),('20060229');
-- 0000-12-15 00:00:00
-- 2006-00-15 00:00:00
-- 2006-12-00 00:00:00
-- 2006-00-00 00:00:00
-- 0000-00-00 00:00:00
Решение
Используйте строковые или числовые типы данных для хранения этих значений.
Проблема: недопустимые даты
MySQL принимает недопустимые даты в режиме ALLOW_INVALID_DATES SQL.
В режиме In ALLOW_INVALID_DATES MySQL лишь проверяет, находится ли значение месяца
в диапазоне от 0 до 12, а числа — от 0 до 31.
Пример
create table date_inval (d datetime null);
set sql_mode='ALLOW_INVALID_DATES';
insert date_inval values ('20061131');
insert date_inval values ('20061132');
set sql_mode='';
insert date_inval values ('20061131');
select * from date_inval;
-- 2006-11-31 00:00:00
-- 0000-00-00 00:00:00
-- 0000-00-00 00:00:00
Решение
Используйте строковые или числовые типы данных для хранения этих значений.
Проблема: поддерживаемый диапазон типа данных DATETIME
В MySQL тип данных DATETIME допускает значения от '0000-00-00 00:00:00' до '9999-12-31
23:59:59'.
Пример
create table datetime_range (d datetime);
insert datetime_range values ('0000-00-00 00:00:01');
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
13
insert datetime_range values ('0000-02-28 23:00:01');
insert datetime_range values ('0170-04-30 08:05:01');
insert datetime_range values ('9999-12-31 23:59:59');
Решение
Используйте строковые или числовые типы данных для хранения этих значений.
Проблема: типы данных MySQL YEAR, DATE, TIME
В MySQL поддерживаются типы данных YEAR, DATE и TIME, отсутствующие в SQL Server.
Тип данных YEAR допускает значения в диапазоне от 1901 до 2155. Недопустимые значения
YEAR преобразуются в 0000.
Тип данных DATE допускает значения от '0000-00-00' до '9999-12-31'. Недопустимые значения
DATE преобразуются в '0000-00-00'.
Тип данных TIME допускает значения в диапазоне от '-838:59:59' до '838:59:59'. По умолчанию
значения TIME, которые выходят за пределы диапазона, но являются корректными, усекаются
до ближайшего граничного значения. Например, значения '-850:00:00' и '850:00:00' преобразуются
в '-838:59:59' и '838:59:59'. Недопустимые значения TIME преобразуются в '00:00:00'.
Пример
create table time_range (t time);
insert time_range values ('2 01:30:54'); -- 49:30:54
insert time_range values ('201:03:45'); -- 201:03:45
insert time_range values ('900:42:14'); -- 838:59:59
insert time_range values ('-900:42:14'); -- -838:59:59
insert time_range values ('-1 05:15:20'); -- -29:15:20
create table year2 (y year(2));
insert year2 values (20),(1920),(80),(2080);
select * from year2; -- 20 20 80 80
create table year4 (y year);
insert year4 select y from year2;
select * from year4; -- 2020 1920 1980 2080
Решение
Используйте строковые или числовые типы данных для хранения этих значений.
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
14
Проблема: типы данных TIMESTAMP и DATETIME
Тип данных TIMESTAMP идентичен типу данных DATETIME, могут возникать дублирующиеся
значения.
Пример
create table table_ts (
id int auto_increment not null, d datetime null,
t timestamp not null default current_timestamp on update urrent_timestamp,
key(id));
insert table_ts (d) values (now()),(now()),(now()),(now()),(now());
select t, count(*) from table_ts group by t
-- 2006-12-22 19:20:38 | 5
Решение
Для эмуляции типа данных TIMESTAMP можно использовать триггер при событиях INSERT
и UPDATE, сохраняющий текущие дату и время в поле datetime.
Строковые типы
Проблема: максимальный размер VARCHAR и VARBINARY
В MySQL для типов данных VARCHAR и VARBINARY используется максимальный размер 65535.
Данные MySQL типа VARCHAR, длина которых превышает 65535, преобразуются в данные
MEDIUMTEXT или LONGTEXT.
Данные MySQL типа VARBINARY, длина которых превышает 65535, преобразуются в данные
MEDIUMBLOB или LONGBLOB.
Пример
create table t_varchar (v varchar(65532));
describe t_varchar; -- v varchar(65532) ...
create table t_varchar (v varchar(65536));
describe t_varchar; -- v mediumtext ...
create table t_varbinary (v varbinary(65532));
describe t_varbinary; -- v varbinary(65532) ...
create table t_varbinary (v varbinary(65536));
describe t_varbinary; -- v mediumblob ...
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
15
Решение
Для сохранения символьных и двоичных данных длиннее 8000 байт используйте типы
данных varchar(max) и varbinary(max).
Проблема: BINARY attribute for fields with CHAR and VARCHAR data types
Из-за атрибута MySQL BINARY происходит двоичное сличение для используемого набора символов
столбца. Например, CHAR(5) BINARY в MySQL обрабатывается как CHAR(5) CHARACTER SET
latin1 COLLATE latin1_bin, если по умолчанию используется набор символов latin1.
Пример
create table char_binary_ci (v varchar(8));
insert char_binary_ci values ('a'),('A'),('C'),('B');
select * from char_binary_ci order by v; -- 'a' 'A' 'B' 'C'
create table char_binary_cs (v varchar(8) binary);
insert char_binary_cs values ('a'),('A'),('C'),('B');
select * from char_binary_cs order by v; -- 'A' 'B' 'C' 'a'
Решение
Решения пока нет.
Проблема: типы данных CHAR, VARCHAR и TEXT могут включать кодировки Юникода
В MySQL имеются две кодировки Юникода: ucs2 (UCS-2 Unicode) и utf8 (UTF-8 Unicode).
В SQL Server имеются типы данных nchar и nvarchar для хранения данных в кодировке
Юникода и использования кодировки Юникода UCS-2.
Пример
create table unicode_ucs2 (v varchar(10) character set ucs2);
create table unicode_utf8 (v varchar(10) character set utf8);
create table collation_cp (v varchar(10) charset cp1251);
insert unicode_ucs2 values ('Ïðèâåò!');
insert unicode_ucs2 values ('您好您');
insert unicode_utf8 values ('Ïðèâåò!');
insert unicode_utf8 values ('您好您');
insert collation_cp values ('Ïðèâåò!');
select length(v) from unicode_ucs2; -- 14 6
select length(v) from unicode_utf8; -- 13 9
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
16
select length(v) from collation_cp; -- 7
select char_length(v) from unicode_ucs2; -- 7 3
select char_length(v) from unicode_utf8; -- 7 3
select char_length(v) from collation_cp; -- 7
Решение
Преобразуйте типы данных CHAR, VARCHAR и TEXT в кодировке Юникода в типы данных
SQL Server nchar и nvarchar.
Проблема: допускается индексирование типов данных BLOB и TEXT
Для индексов столбцов BLOB и TEXT в MySQL нужно указать длину префикса индекса.
Длина префикса может составлять до 1000 байт (767 байт для таблиц InnoDB).
Пример
create table blob_index (blob_col blob, index(blob_col(20)));
Решение
Решения пока нет.
Проблема: строковые константы могут содержать ESCAPE-последовательности
Каждая ESCAPE-последовательность в строковой константе начинается с обратной косой
черты («\») в MySQL.
Пример
select 'This is \'Quoted string\'';
select 'This is ''Quoted string''';
-- This is 'Quoted string'
Решение
Решения пока нет.
Типы данных ENUM и SET
Проблема: тип данных ENUM (перечисление)
В MySQL поддерживается тип данных ENUM (перечисление). ENUM представляет собой строковый
объект, значение которого выбрано из списка допустимых значений, пронумерованных явным
образом в спецификации столбца во время создания таблицы.
Если вставить недопустимое значение в столбец типа ENUM, то вставляется пустая строка
в качестве специального значения ошибки. Если столбец ENUM объявлен как допускающий
значение NULL, значение NULL является для него корректным и используется по умолчанию.
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
17
Если столбец ENUM объявлен как NOT NULL, значением по умолчанию для него является
первый элемент из списка допустимых значений.
Каждое значение перечислимого типа имеет индекс.
Значения ENUM сортируются в соответствии с порядком, в котором элементы перечисления
указаны в спецификации столбца.
Пример
create table table_enum (e enum ('a','b','c') not null);
insert into table_enum values ('a');
insert into table_enum values ('d');
insert into table_enum values ('a,c');
insert into table_enum values ('b,b,b');
insert into table_enum values ('b');
insert into table_enum values ();
select * from table_enum; -- 'a','','','','b','a';
select * from table_enum where e=1 -- 'a', 'a'
--------------------------------------------------
create procedure proc_enum (e enum ('a','b','c'))
begin
if e!=''
then select e;
else select 'Invalid argument';
end if;
end
call proc_enum ('a'); -- 'a'
call proc_enum ('t'); -- 'Invalid argument'
Решение
Попробуйте эмулировать тип данных ENUM в виде таблицы подстановок, как в следующем
примере кода:
create table someenumtype (_id integer, _value varchar(max)).
Исходная таблица будет ссылаться на эту хэш-таблицу по идентификатору _id.
Необходимо добавить операторы присоединения ко всем запросам, где используется
значение поля ENUM.
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
18
Проблема: тип данных SET
В MySQL поддерживается тип данных SET. SET представляет собой строковый объект, который
может принимать различные значения, включая нулевое, каждое из которых должно выбираться
из списка допустимых значений, указанного при создании таблицы.
Если для столбца SET задано неподдерживаемое значение, это значение игнорируется.
В MySQL значения SET сохраняются в числовом виде, причем младший разряд сохраненного
значения соответствует первому компоненту набора.
Пример
create table table_set (s set('a','b','c') not null);
insert into table_set values ('a');
insert into table_set values ('d');
insert into table_set values ('a,c');
insert into table_set values ('b,b,b');
insert into table_set values ('b');
insert into table_set values ();
select * from table_set; -- 'a','','a,c','b','b',''
select * from table_set where s='a,c' -- 'a,c'
--------------------------------------------------
create procedure proc_set (p char(1), s set ('a','b','c'))
begin
if find_in_set(p,s)>0
then select p;
else select 'Invalid argument';
end if;
end
call proc_set ('a','b,c,a'); -- 'a'
call proc_set ('a','b,c'); -- 'Invalid argument'
Решение
Тип данных SET имеет двойственную природу — целое число (до 64 бит) и строка одновременно.
Каждый бит SET соответствует описанию строки. Строковое представление значения SET
состоит из соответствующих строк, разделенных запятыми.
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
19
При обработке данных можно использовать как целочисленные, так и строковые представления
объекта SET.
Внутри объект SET хранится в виде целого числа, размер зависит от количества значений
SET (от 1 до 8 байт). При эмуляции типа данных SET в SQL Server за основу берется bigint,
самый большой из возможных целочисленных типов данных.
Чтобы сохранить строковое представление битов в значении SET и определить все возможные
биты, создайте «таблицу подстановки», как показано в следующем примере:
create table lookup_set(
schemaname sysname not null,
-- schema name
tablename sysname not null, -- table name
colname sysname not null, -- column name
bitmask bigint not null, -- bitmask for value
position int not null, -- position in list
description varchar(512) not null,
-- chararcter description of value
constraint pk_lookup_set
primary key clustered (schemaname,tablename,colname,bitmask)
)
Кроме того, создайте набор UDF для поддержки операций, использующих тип данных SET.
UDF
Описание
char_to_set
Преобразовывает строковое представление в целочисленное.
Примечание. char_to_set всегда работает как при отключенном
«строгом режиме» или наличии слова IGNORE в конструкции INSERT
или UPDATE.
set_to_char
Преобразовывает целочисленное представление в строковое.
clean_set
Удаляет недопустимые биты из целочисленного представления.
Примечание. Использование clean_set может зависеть от «строгого
режима» или слова IGNORE в конструкциях INSERT и UPDATE.
check_set
Проверяет, имеет ли данное целочисленное представление допустимое
значение SET.
find_in_set
Эмулирует функцию MySQL FIND_IN_SET.
Проверьте в функции FIND_IN_SET возможный конфликт имен
со второй эмуляцией FIND_IN_SET.
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
20
Другие типы данных
Проблема: пространственные типы данных в MySQL
В MySQL есть типы данных, соответствующие классам OpenGIS (пространственные типы
данных MySQL).
Пример
create table spatial_type (g geometry, p point,
l linestring, pg polygon, mp multipoint)
Решение
Решения пока нет.
Неявное преобразование типов данных
Проблема: неявное преобразование типов данных в MySQL
Когда значение одного типа используется в контексте, для которого требуется значение
другого типа, MySQL автоматически преобразует типы данных в соответствии с типом
выполняемой операции.
Примеры:
select 100+'ABC' -- 100
select 100+'23ABC' -- 123
select concat('ABC',345,now(),50.4789) -- ABC3452006-11-08 19:00:0050.4789
drop table if exists table_date;
create table table_date
(d datetime, b smallint, i int(10) zerofill, f float, s varchar(64));
set @d=19980514;
insert into table_date values (@d, @d, @d, @d, @d);
select * from table_date;
-- 1998-05-14 00:00:00 32767 0019980514 1.99805e+007 19980514
set @d=now();
insert into table_date values (@d, @d, @d, @d, @d);
select * from table_date;
-- 2006-11-08 19:24:25 2006 0000002006 2006 2006-11-08 19:26:27
Решение
Решения пока нет.
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
21
Значения типов данных по умолчанию
Проблема: неявные значения DEFAULT
Если в определение столбца не включено явное значение DEFAULT, значение по умолчанию
в MySQL определяется следующим образом:

Если столбец может принимать значение NULL, он определяется с использованием
явного предложения DEFAULT NULL.

Если столбец не может принимать значение NULL, он определяется в MySQL без явного
предложения DEFAULT. Если в инструкции INSERT или REPLACE не указано значение
для столбца, то для ввода данных MySQL обрабатывает столбец в соответствии
с действующим на данный момент режимом SQL.

Если не включен строгий режим SQL, столбцу в MySQL присваивается неявное значение
по умолчанию для типа данных столбца.

Если строгий режим включен, для транзакционных таблиц появляется ошибка и происходит откат инструкции. Для нетранзакционных таблиц ошибка появляется, но если
это происходит для второй или последующей строки многострочной инструкции,
предыдущие строки будут вставлены.
Пример
create table table_default (i int not null, d datetime not null,
s varchar(64) not null, e enum ('a','b','c') not null, n int null);
insert table_default values ();
insert table_default values (default,default,'ABC',default,default);
select * from table_default;
-- 0 0000-00-00 00:00:00
a NULL
-- 0 0000-00-00 00:00:00 ABC a NULL
-- DEFAULT function example
create table table_defaultfunc (a int not null default 1,
b int not null default 2);
insert table_defaultfunc values ();
insert table_defaultfunc values (default(b),default(a));
select * from table_defaultfunc;
-- 1 2
-- 2 1
Решение
Решения пока нет.
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
22
Проблемы перехода с MySQL
В этом разделе описываются проблемы, которые могут возникнуть при переходе с MySQL 5
на SQL Server 2005, и способы их устранения.
Операторы
В этом разделе описываются различия между операторами в MySQL и SQL Server 2005.
Операторы сравнения
Проблема: операторы сравнения в инструкциях DML
В отличие от SQL Server в MySQL допускаются операторы сравнения в инструкциях DML.
Пример
create table table_logic (id int not null,
v varchar(64) not null, b int not null);
insert table_logic values (1,'1=2',1=2);
insert table_logic values (2,'1>2',1>2);
insert table_logic values (3,'1<2',1<2);
select * from table_logic; -- 1 1=2 0 | 2 1>2 0 | 3 1<2 1
select 1=2, 1>2, 1<2 from dual; -- 0 0 1
update table_logic set v='2=3', b=2=3 where id=3;
select * from table_logic; -- 3 2=3 0
update table_logic set v='NULL IS UNKNOWN', b=NULL IS UNKNOWN where id=3;
select * from table_logic; -- 3 NULL IS UNKNOWN 1
select @a is unknown, @a is null, @a is not null; -- 1 1 0
set @a=5-1=3+1
select @a -- 0
select 'a' in ('a','b','c'), 'a' not in ('a','b','c'); -- 1 0
select 1=2=0=5=0, 2>1=1<7=1<0 -- 1 0
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
23
Решение
Эмулируйте операторы сравнения в инструкциях DML с помощью функции CASE.
Проблема: оператор равенства <=>, не возвращающий значение NULL
Этот оператор MySQL сравнивает равенство, как и оператор =, однако возвращает 1, а не NULL,
если оба операнда равны NULL, и 0, а не NULL, если один операнд равен NULL. В SQL Server
нет идентичного оператора.
Пример
select 1 <=> 1, null <=> null, 1 <=> null, @d <=> null;
-- 1 1 0 1
select 1 = 1, null = null, 1 = null, @d = null;
-- 1 NULL NULL NULL
Решение
Решения пока нет.
Проблема: оператор сравнения IS [NOT] логическое_значение
Этот оператор MySQL сравнивает значение с логическим значением, где логическое_значение
может быть TRUE, FALSE или UNKNOWN. В SQL Server нет аналогичного оператора.
Пример
create table table_is_int (i int);
insert table_is_int values (-1),(0),(1),(2),(3),(null);
select i is true from table_is_int; -- 1 0 1 1 1 0
select i is false from table_is_int; -- 0 1 0 0 0 0
select i is unknown from table_is_int; -- 0 0 0 0 0 1
select i=0 is true from table_is_int; -- 0 1 0 0 0 0
select * from table_is_int where (i is true) is false; -- 0 NULL
select 'A' is false, 'A' is true,
'7A' is false, '7A' is true, now() is true;
-- 1 0 0 1 1
Решение
Эмулируйте этот оператор сравнения с помощью функции CASE.
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
24
Проблема: дополнительные функции оператора сравнения IS NULL
В MySQL поддерживаются дополнительные функции оператора сравнения IS NULL.
В MySQL можно найти строку, содержащую самое последнее значение AUTO_INCREMENT,
с помощью выдачи инструкции следующего вида сразу же после создания значения:
SELECT * FROM tbl_name WHERE auto_col IS NULL
Для столбцов DATE и DATETIME, объявленных NOT NULL, можно найти дату '0000-00-00'
с помощью следующей инструкции:
SELECT * FROM tbl_name WHERE date_column IS NULL
Пример
create table auto_inc (id int not null auto_increment,
v varchar(64) not null, key(id));
insert auto_inc (v) values ('ABC');
insert auto_inc (v) values ('DEF');
insert auto_inc (v) values ('GHI');
select * from auto_inc where id is null;
-- 3 'GHI'
create table auto_date (d datetime not null, v varchar(64) not null);
insert auto_date set v='A';
insert auto_date set v='B';
insert auto_date set v='C', d=now();
select * from auto_date where d is null;
-- 0000-00-00 00:00:00 A
-- 0000-00-00 00:00:00 B
Решение
Решения пока нет.
Битовые операторы
Проблема: операторы побитового сдвига
В MySQL поддерживаются операторы побитового сдвига (<< и >>), отсутствующие в SQL Server.
Пример
create procedure bit_shift (count int)
begin
declare v bigint; declare i int;
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
25
set v:=1; set i:=1;
while i<=count do
set v := v << 1;
select v, i;
set i := i+1;
end while;
end;
call bit_shift (70);
-- 2
1
-- 4611686018427387904
62
-- 9223372036854775807
63
-- 9223372036854775807
64
Решение
Решения пока нет.
Операторы присвоения
Проблема: присвоение переменных в инструкциях SET
В MySQL можно присваивать переменные в инструкциях SET при помощи операторов := или =.
MySQL также может присваивать значение пользовательской переменной в инструкциях,
отличных от SET. В этом случае для присвоения нужно использовать оператор :=, а не =,
поскольку оператор = обрабатывается как оператор сравнения в инструкциях, отличных от SET.
В отличие от SQL Server, если переменная назначается в инструкции MySQL SELECT,
возвращается набор записей.
Пример
set @a=1; set @b:=2;
select @a, @b, @a=@b; -- 1 2 0
select @a:=@b; -- 2
select @a, @b, @a=@b; -- 2 2 1
create table assign_var (i int not null);
insert assign_var values (1),(2),(3);
select @i, @i:=i from assign_var order by i;
-- NULL 1
-- 1
2
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
-- 2
26
3
select @i:=i, @i from assign_var order by i;
-- 1 1
-- 2 2
-- 3 3
select @i; -- 3
Решение
Решения пока нет.
Переменные
В этом разделе описываются различия между переменными в MySQL и SQL Server 2005.
Проблема: типы поддерживаемых переменных
В MySQL поддерживаются два типа переменных:

пользовательские переменные @var_name

Локальные переменные (переменные в хранимых процедурах)
DECLARE var_name[,...] type [DEFAULT value];
В MySQL для инициализации пользовательских переменных не используется инструкция
DECLARE. Они инициализируются неявным образом, когда впервые задаются (с помощью
инструкции SET или SELECT) или применяются. Если обратиться к переменной, которая еще
не была инициализирована с помощью инструкции SET или SELECT, эта переменная будет
иметь значение NULL и строковый тип.
Пользовательские переменные используются для конкретного подключения. В SQL Server нет
определенных переменных для конкретного подключения.
Пример 1
create procedure proc ()
begin
select @a;
end
set @a=100;
call proc2 ();
Пример 2
create procedure proc (inout par_a int)
begin
set par_a=200;
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
27
end
call proc2 (@b);
select @b;
Решение
Решения пока нет.
Проблема: учет регистра в пользовательских переменных
В именах пользовательских переменных учитывается регистр в версиях до MySQL 5.0
и не учитывается в MySQL 5.0 и более поздних версиях.
Это следует принимать во внимание при выборе сопоставления в SQL Server.
Решение
Решения пока нет.
Проблема: значение локальных переменных по умолчанию
В MySQL локальные переменные могут иметь значение по умолчанию.
Пример
create procedure ProcA ()
begin
declare var_a int default 100;
declare var_b varchar(8) default 'ABCDEFGHIJKLMN';
declare var_c datetime default now();
declare var_d int;
select var_a, var_b, var_c, var_d;
-- 100 ABCDEFGH 2006-11-08 15:05:04 (NULL)
end
Решение
Решения пока нет.
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
28
Служебные инструкции
Проблема: команда DELIMITER
Команда MySQL DELIMITER допускает изменение разделителя инструкций.
Пример
create table table_a (id int);
select * from table_a;
delimiter //
select * from table_a//
drop table table_a//
Решение
Решения пока нет.
Проблема: команда HELP (синтаксис HELP)
Команда HELP возвращает сведения из справочного руководства по MySQL.
HELP 'search_string'
Пример
HELP 'replace'
Syntax:
REPLACE(str,from_str,to_str)
Returns the string str with all occurrences of the string from_str
replaced by the string to_str. REPLACE() performs a case-sensitive
match when searching for from_str.
Решение
Решения пока нет.
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
29
Инструкции определения данных
В этом разделе поясняются различия между языками определения данных в MySQL и SQL
Server 2005, а также приводятся решения для устранения проблем. В разделе описываются
создание таблиц, схем и представлений, преобразование временных таблиц и другие
проблемы, связанные с DDL.
Предложения IF NOT EXISTS, IF EXISTS и REPLACE
Проблема: предложение IF NOT EXISTS в инструкциях CREATE DATABASE, CREATE TABLE,
CREATE EVENT
Ключевые слова IF NOT EXISTS не допускают возникновение ошибки, если таблица
(база данных, событие) существует.
Примечание. Если использовать IF NOT EXISTS в инструкции CREATE TABLE...SELECT,
то все строки, выбранные при помощи SELECT, вставляются вне зависимости от того,
существует ли таблица.
Пример кода MySQL
create database db_exists;
create database db_exists;
-- Error Code : 1007 Can't create database 'db_exists'; database exists
A: create database if not exists db_exists;
-- No Action
create table exists_a (i int not null);
create table exists_a (i int not null);
-- Error Code : 1050 Table 'exists_a' already exists
B: create table if not exists exists_a (i int not null, v varchar(64)
null);
-- No Action
show create table exists_a; -- create table exists_a (i int(11) not null)
C: create table if not exists exists_a select now() as d from dual;
show create table exists_a; -- create table exists_a (i int(11) not null)
select * from exists_a; -- 2007
Решение

CREATE DATABASE
Замените предложение IF NOT EXISTS следующим условием:
IF NOT EXISTS (SELECT name FROM sys.databases
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
30
WHERE name = N'<db_name>')
BEGIN
<create_database_statement_without_if_not_exists>
END

CREATE TABLE
Если синтаксис CREATE TABLE...SELECT не используется, замените предложение IF NOT
EXISTS следующим условием:

Для постоянных таблиц:
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id =
OBJECT_ID(N'<table_name>') AND type in (N'U'))
BEGIN
<create_table_statement_without_if_not_exists>
END

Для временных таблиц:
IF NOT EXISTS (SELECT * FROM tempdb.sys.objects WHERE object_id =
OBJECT_ID(N'tempdb..<#table_name>') AND type in (N'U'))
BEGIN
<create_#table_statement_without_if_not_exists>
END
Если используется синтаксис CREATE TABLE...SELECT, замените предложение IF
NOT EXISTS следующим условием:

Для постоянных таблиц:
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id =
OBJECT_ID(N'<table_name>') AND type in (N'U'))
BEGIN
<create_table_statement_without_if_not_exists>
<insert_select_statement>
END
ELSE BEGIN
<insert_select_statement>
END

Для временных таблиц:
IF NOT EXISTS (SELECT * FROM tempdb.sys.objects WHERE object_id =
OBJECT_ID(N'tempdb..<#table_name>') AND type in (N'U'))
BEGIN
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
31
<create_#table_statement_without_if_not_exists>
<insert_select_statement>
END
ELSE BEGIN
<insert_select_statement>
END

CREATE EVENT
Решения пока нет.
Пример кода SQL Server
A: IF NOT EXISTS (SELECT name FROM sys.databases WHERE name =
N'db_exists')
BEGIN
create database db_exists
END
B: IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id =
OBJECT_ID(N'exists_a') AND type in (N'U'))
BEGIN
create table exists_a (i int not null, v varchar(64) null)
END
C: IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id =
OBJECT_ID(N'exists_a') AND type in (N'U'))
BEGIN
create table exists_a (d datetime not null default '1753-01-01 00:00:00')
insert exists_a select getdate() as d
END
ELSE BEGIN
insert exists_a select getdate() as d
END
Проблема: предложение IF EXISTS в инструкциях DROP DATABASE, DROP TABLE, DROP
VIEW, DROP EVENT, DROP PROCEDURE, DROP FUNCTION
Ключевые слова IF EXISTS не допускают возникновение ошибки, если база данных
(таблица, представление, событие, процедура, функция) не существует.
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
32
Пример кода MySQL
A: drop database if exists db_exists;
drop database db_exists;
-- Error Code : 1008 Can't drop database 'db_exists'; database doesn't
exist
B: drop table if exists exists_a;
C: drop view if exists exists_view;
D: drop procedure if exists exists_proc;
E: drop function if exists exists_func;
Решение

DROP DATABASE. Замените предложение IF EXISTS следующим условием:
IF EXISTS (SELECT name FROM sys.databases WHERE name = N'<db_name>')
BEGIN
<drop_database_statement_without_if_exists>
END

DROP TABLE. Замените предложение IF EXISTS следующим условием:
IF EXISTS (SELECT * FROM tempdb.sys.objects WHERE object_id =
OBJECT_ID(N'tempdb..<#table_name>') AND type in (N'U'))
BEGIN
<drop_#table_statement_without_if_exists>
END
ELSE BEGIN
IF EXISTS (SELECT * FROM sys.objects WHERE object_id =
OBJECT_ID(N'<table_name>') AND type in (N'U'))
BEGIN
<drop_table_statement_without_if_exists>
END

DROP TEMPORARY TABLE. Замените предложение IF EXISTS следующим условием:
IF EXISTS (SELECT * FROM tempdb.sys.objects WHERE object_id =
OBJECT_ID(N'tempdb..<#table_name>') AND type in (N'U'))
BEGIN
<drop_#table_statement_without_if_exists>
END
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005

33
DROP VIEW. Замените предложение IF EXISTS следующим условием:
IF EXISTS (SELECT * FROM sys.views WHERE object_id =
OBJECT_ID(N'<view_name>'))
BEGIN
<drop_view_statement_without_if_exists>
END

DROP EVENT. Решения пока нет.

DROP PROCEDURE. Замените предложение IF EXISTS следующим условием:
IF EXISTS (SELECT * FROM sys.objects WHERE object_id =
OBJECT_ID(N'<proc_name>') AND type in (N'P', N'PC'))
BEGIN
<drop_procedure_statement_without_if_exists>
END

DROP FUNCTION. Замените предложение IF EXISTS следующим условием:
IF EXISTS (SELECT * FROM sys.objects WHERE object_id =
OBJECT_ID(N'<func_name>')
AND type in (N'FN', N'IF', N'TF', N'FS', N'FT'))
BEGIN
<drop_function_statement_without_if_exists>
END
Пример кода SQL Server
A: IF EXISTS (SELECT name FROM sys.databases WHERE name = N'db_exists')
BEGIN
drop database db_exists
END
B: IF EXISTS (SELECT * FROM sys.objects WHERE object_id =
OBJECT_ID(N'exists_a') AND type in (N'U'))
BEGIN
drop table exists_a
END
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
34
C: IF EXISTS (SELECT * FROM sys.views WHERE object_id =
OBJECT_ID(N'exists_view'))
BEGIN
drop view exists_view
END
D: IF EXISTS (SELECT * FROM sys.objects WHERE object_id =
OBJECT_ID(N'<exists_proc>') AND type in (N'P', N'PC'))
BEGIN
drop procedure exists_proc
END
E: IF EXISTS (SELECT * FROM sys.objects WHERE object_id =
OBJECT_ID(N'exists_func')
AND type in (N'FN', N'IF', N'TF', N'FS', N'FT'))
BEGIN
drop function exists_func;
END
Проблема: предложение OR REPLACE в инструкциях CREATE VIEW
Предложение MySQL OR REPLACE заменяет существующее представление.
Пример кода MySQL
create or replace view repl_view as select now();
create or replace view repl_view as select version();
Решение
Замените предложение OR REPLACE следующим условием:
IF EXISTS (SELECT * FROM sys.views WHERE object_id =
OBJECT_ID(N'<view_name>'))
BEGIN
<drop_view_statement>
exec dbo.sp_executesql @statement
= N'<create_view_statement_without_or_replace>'
END
ELSE BEGIN
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
35
exec dbo.sp_executesql @statement
= N'<create_view_statement_without_or_replace>'
END
Пример кода SQL Server
IF EXISTS (SELECT * FROM sys.views WHERE object_id =
OBJECT_ID(N'repl_view'))
BEGIN
drop view repl_view
exec dbo.sp_executesql @statement
= N'create view repl_view as select getdate() as d'
END
ELSE BEGIN
exec dbo.sp_executesql @statement
= N'create view repl_view as select getdate() as d'
END
Временные таблицы
Проблема: таблицы MySQL TEMPORARY не удаляются при выходе из области действия
Временные таблицы SQL Server, созданные с помощью инструкции CREATE TEMPORARY
TABLE, видны только текущему подключению и удаляются автоматически после закрытия
подключения. Но временные таблицы MySQL не удаляются при выходе из области действия.
В SQL Server:

Локальная временная таблица, создаваемая в хранимой процедуре, удаляется автоматически
при завершении этой процедуры. К таблице могут обращаться любые вложенные хранимые
процедуры, выполняемые хранимой процедурой, в которой создана таблица. К таблице не
может обращаться процесс, вызываемый хранимой процедурой, в которой создана таблица.

Имя локальной временной таблицы, создаваемой в хранимой процедуре или триггере, может
совпадать с именем временной таблицы, которая была создана до вызова хранимой процедуры или триггера. Однако если в запросе указывается временная таблица и одновременно
существуют две временные таблицы с одним именем, невозможно определить, какая таблица будет выбрана по запросу. Во вложенной хранимой процедуре может также создаваться
временная таблица, имя которой совпадает с именем временной таблицы, которая была
создана вызывающей ее хранимой процедурой. Однако для разрешения модификаций
в таблице, созданной во вложенной процедуре, таблица должна иметь ту же структуру
и те же имена столбцов, что и таблица, созданная в вызывающей процедуре.
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
36
Пример 1 кода MySQL
create procedure proctemptable ()
begin
create temporary table table_temp (d datetime);
insert table_temp values (now());
end
call proctemptable();
select * from table_temp; -- 2006-11-20 11:18:58
call proctemptable(); -- Error Code : 1050 Table 'table_temp' already
exists
Пример 2 кода MySQL
create procedure test2 ()
begin
create temporary table t (x int);
insert into t values (2);
select x as test2col from t;
end
create procedure test1 ()
begin
create temporary table t (x int);
insert into t values (1);
select x as test1col from t;
call test2 ();
end
call test1 ();
-- test1col = 1 (1 row)
-- ERROR 1050 (42S01): Table 't' alredy exists
Решение
Решения пока нет.
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
37
Проблема: ключевое слово TEMPORARY в инструкциях CREATE TABLE и DROP TABLE
В MySQL ключевое слово TEMPORARY в инструкции CREATE TABLE служит для создания
временной таблицы.
В MySQL ключевое слово TEMPORARY в инструкции DROP TABLE служит для удаления
временной таблицы.
Пример кода MySQL
A: create temporary table temp_table_a (a int not null);
B: create temporary table if not exists atest.temp_table_b (b int not
null);
C: drop temporary table temp_table_a;
D: drop temporary table if exists atest.temp_table_b;
Решение
Замените ключевое слово TEMPORARY знаком решетки (#) перед именем таблицы. Имя базы
данных опустите.
Пример кода SQL Server
A: create table #temp_table_a (a int not null)
B: IF NOT EXISTS (SELECT * FROM tempdb.sys.objects WHERE object_id =
OBJECT_ID(N'tempdb..#temp_table_b') AND type in (N'U'))
BEGIN
create table #temp_table_b (b int not null)
END
C: drop table #temp_table_a;
D: IF EXISTS (SELECT * FROM tempdb.sys.objects WHERE object_id =
OBJECT_ID(N'tempdb..#temp_table_b') AND type in (N'U'))
BEGIN
drop table #temp_table_b;
END
Проблема: скрытие таблиц
Если в MySQL временная таблица создается с тем же именем, как и существующая
постоянная таблица, то постоянная таблица скрывается до удаления временной таблицы.
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
38
Пример 1 кода MySQL
create table permanent_temp (v varchar(4) not null, d datetime not null);
insert permanent_temp values ('ABCD',now());
select * from permanent_temp; -- 'ABCD' '2007-02-08 16:19:40'
create temporary table permanent_temp (i int not null);
insert permanent_temp values (1);
select * from permanent_temp; -- 1
drop table permanent_temp; -- drop temporary table
select * from permanent_temp; -- 'ABCD' '2007-02-08 16:19:40'
drop table permanent_temp; -- drop permanent table
Пример 2 кода MySQL
create table permanent_temp (i int not null);
insert permanent_temp values (0);
select * from permanent_temp; -- 0
create temporary table permanent_temp (i int not null);
insert permanent_temp values (1);
select * from permanent_temp; -- 1
drop temporary table permanent_temp; -- drop temporary table
select * from permanent_temp; -- 0
drop temporary table permanent_temp;
-- Error Code : 1051 Unknown table
'permanent_temp'
drop table permanent_temp; -- drop permanent table
Решение
Решения пока нет.
Проблема: временные таблицы в функциях
В MySQL можно использовать временные таблицы в функциях. В SQL Server это
не допускается.
Пример кода MySQL
create function temp_func_sum () returns double
begin
declare s double;
select sum(i) into s from temp_func;
return s;
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
39
end
session 1:
create temporary table temp_func (i int not null);
insert into temp_func values (1),(2),(3),(4);
select temp_func_sum(); -- 10
session 2:
create temporary table temp_func (i numeric(19,9) not null);
insert into temp_func values (1.1000),(1.0100),(1.0010),(1.0001);
select temp_func_sum(); -- 4.1111
session 3:
create temporary table temp_func (i varchar(4) not null);
insert into temp_func values ('ABCD'),('5A'),('3.14P'),('1')
select temp_func_sum(); -- 9.14
Решение
Решения пока нет.
Ключевое слово SCHEMA в инструкциях DATABASE
Проблема: ключевое слово SCHEMA в инструкциях DATABASES
В инструкциях DATABASE (ALTER, CREATE, DROP, RENAME) ключевое слово SCHEMA
можно использовать как синоним ключевого слова DATABASE.
Решение
Замените ключевое слово SCHEMA на ключевое слово DATABASE.
Предложения CHARACTER SET и COLLATE
в инструкциях DDL
Проблема: предложения CHARACTER SET и COLLATE в инструкциях DDL
В терминологии MySQL набор символов — это набор символов и кодов, а сличение — это
набор правил для сравнения символов в наборе. Понятие сличение в SQL Server включает
оба эти значения.
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
40
Пример кода MySQL
create database db_a character set latin1 collate latin1_swedish_ci;
Решение
Преобразуйте предложения MySQL CHARACTER SET и COLLATE в предложение
SQL Server COLLATE.
Проблема: предложения CONVERT TO CHARACTER SET и [DEFAULT] CHARACTER SET
в инструкциях ALTER TABLE
В отличие от MySQL в SQL Server не поддерживаются изменения сличения на уровне таблиц.
Решение
Решения пока нет.
Инструкция CREATE INDEX
Проблема: значения NULL в индексах UNIQUE
Индекс MySQL UNIQUE допускает несколько значений NULL в столбцах, которые могут
содержать значения NULL.
Пример кода MySQL
create table tabindex_b (i int null);
create unique index idx_tabindex_b on tabindex_b (i);
insert tabindex_b values (1);
insert tabindex_b values (2);
insert tabindex_b values (3);
insert tabindex_b values (1);
-- Duplicate entry '1' for key 1
insert tabindex_b values (null);
-- 1 row(s) affected
insert tabindex_b values (null);
-- 1 row(s) affected
Решение
Решения пока нет.
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
41
Проблема: индексы FULLTEXT
MySQL может создавать индексы FULLTEXT в таблицах, не имеющих уникального индекса ключа.
MySQL может создавать более одного индекса FULLTEXT в таблице.
Параметр WITH PARSER можно использовать только вместе с индексами FULLTEXT. Он связывает
подключаемый модуль синтаксического анализа с индексом, если необходима специальная
обработка полнотекстовых операций индексации и поиска.
Пример кода MySQL
create table tabindex_full (i int not null, t varchar(2048) null)
engine = myisam;
create unique index unique_tabindex_full on tabindex_full (i);
create fulltext index full_tabindex_full on tabindex_full (t);
Решение
Индексы FULLTEXT можно преобразовывать при выполнении всех перечисленных ниже условий:

для таблицы существует только один индекс FULLTEXT;

в таблице есть индекс для применения ключа полнотекстового поиска;

индекс FULLTEXT не использует подключаемый модуль анализатора.
Пример кода SQL Server
create table tabindex_full (i int not null, t varchar(2048) null)
create unique index unique_tabindex_full on tabindex_full (i)
create fulltext index on tabindex_full (t) key index unique_tabindex_full
Проблема: индексы SPATIAL
Индексы SPATIAL поддерживаются только для таблиц MyISAM и могут включать только
пространственные столбцы, определенные как NOT NULL.
Решение
Решения пока нет.
Проблема: длина префикса индекса
Для столбцов CHAR, VARCHAR, BINARY и VARBINARY можно создавать индексы
с использованием только главной части значений столбца; при этом с помощью синтаксиса
имя_столбца(длина) указывается длина префикса индекса. Столбцы типа BLOB и TEXT тоже
можно индексировать, но для них необходимо указывать длину префикса. Длина префикса
указывается в символах для недвоичных строковых типов и в байтах для двоичных строковых
типов. Таким образом, элементы индекса состоят из указанного числа первых символов каждого
значения столбца для типов CHAR, VARCHAR и TEXT и указанного числа первых байт каждого
значения столбца для типов BINARY, VARBINARY и BLOB.
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
42
Пример кода SQL Server
create table tabindex_text (t text not null);
create unique index unique_tabindex_text on tabindex_text (t(4));
insert tabindex_text values ('ABCDEFG');
insert tabindex_text values ('ABCEFGD');
insert tabindex_text values ('ABKLMND');
insert tabindex_text values ('ABCKLMN');
insert tabindex_text values ('ABCDLMN');
-- Duplicate entry 'ABCD' for key 1
create table tabindex_blob (b blob null);
create unique index unique_tabindex_blob on tabindex_blob (b(4));
insert tabindex_blob values (0x01020304050607);
insert tabindex_blob values (0x01020310111204);
insert tabindex_blob values (0x01020304101112);
-- Duplicate entry '
' for key 1
Решение
Добавьте в таблицу вычисленные столбцы, эмулирующие длину префикса индекса.
Создайте индекс по вычисленным столбцам.
Пример кода SQL Server
create table tabindex_text (t varchar(max) not null,
t_comp as convert(varchar(4),t))
create unique index unique_tabindex_text on tabindex_text (t_comp)
insert tabindex_text values ('ABCDEFG')
insert tabindex_text values ('ABCEFGD')
insert tabindex_text values ('ABKLMND')
insert tabindex_text values ('ABCKLMN')
insert tabindex_text values ('ABCDLMN')
-- Cannot insert duplicate key row ...
create table tabindex_blob (b varbinary(max) null,
b_comp as
convert(varbinary(4),b));
create unique index unique_tabindex_blob on tabindex_blob (b_comp);
insert tabindex_blob values (0x01020304050607);
insert tabindex_blob values (0x01020310111204);
insert tabindex_blob values (0x01020304101112);
-- Cannot insert duplicate key row ...
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
43
Инструкция CREATE TABLE
Проблема: имена CONSTRAINT
В MySQL можно опускать имена ограничений.
В MySQL разрешены повторяющиеся имена ограничений.
Пример кода MySQL
create table tab_constr (
id int not null, d
datetime,
fk int not null,
constraint primary key (id),
constraint unique (d),
constraint foreign key (fk) references tab_a (i)
);
create table tab_constr_dub (
id int not null, d
datetime,
constraint key_tab_constr_dub primary key (id),
constraint key_tab_constr_dub unique (d)
);
Решение
Создавайте допустимые уникальные имена ограничений.
Пример кода SQL Server
create table tab_constr (
id int not null, d
datetime,
fk int not null,
constraint pk_tab_constr primary key (id),
constraint uq_tab_constr unique (d),
constraint fk_tab_constr foreign key (fk) references tab_a (i)
);
create table tab_constr_dub (
id int not null, d
datetime,
constraint pk_tab_constr_dub primary key (id),
constraint uq_tab_constr_dub unique (d)
);
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
44
Проблема: определения индексов
В MySQL можно определять индексы в тексте объявления таблицы.
Пример кода MySQL
create table tab_index (
i int not null,
n int not null,
d datetime null,
v varchar(2048) not null,
primary key (i),
index idx_tab_index (n),
key (d),
fulltext index ft_tab_index (v)) engine = myisam;
Решение
Удалите объявления индексов из объявлений таблиц. Преобразуйте их в отдельные
инструкции CREATE INDEX.
Создавайте допустимые уникальные имена индексов.
Замените ключевое слово KEY на ключевое слово INDEX.
Пример кода SQL Server
create table tab_index (
i int not null,
n int not null,
d datetime null,
v varchar(2048) not null,
primary key (i))
create index idx_tab_index on tab_index (n)
create index key_tab_index on tab_index (d)
create fulltext index on tab_index (v) key index pk__tab_index__72e607db
Проблема: индексы ограничений FOREIGN KEY
В отличие от SQL Server в MySQL для ограничений FOREIGN KEY индекс создается
автоматически.
Решение
Решения пока нет.
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
45
Проблема: ключевое слово RESTRICT в параметрах ссылок
В MySQL поддерживается ключевое слово RESTRICT в параметрах ссылок.
Решение
Замените ключевое слово RESTRICT в параметрах ссылок на ключевое слово NO ACTION.
Проблема: ключевое слово KEY в определениях столбцов
В MySQL поддерживается ключевое слово KEY в определениях столбцов.
Решение
Замените ключевое слово KEY в определениях столбцов на ключевое слово PRIMARY KEY.
Проблема: параметр столбца AUTO_INCREMENT и параметр таблицы AUTO_INCREMENT
В MySQL поддерживаются параметр столбца AUTO_INCREMENT и параметр таблицы
AUTO_INCREMENT.
Пример кода MySQL
create table auto_a (
i int not null auto_increment primary key,
d datetime null
)
auto_increment = 1000;
insert auto_a values (null,now()),(null,now()),(null,now());
select * from auto_a;
-- 1000 2007-02-16 17:41:43
-- 1001 2007-02-16 17:41:43
-- 1002 2007-02-16 17:41:43
Решение
Вместо параметра столбца MySQL AUTO_INCREMENT следует использовать свойство
столбца SQL Server IDENTITY. Параметр таблицы MySQL AUTO_INCREMENT следует
преобразовать в SQL Server как параметр seed свойства IDENTITY.
Пример кода SQL Server
create table auto_a (
i int not null identity(1000,1) primary key,
d datetime null
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
46
)
insert auto_a values (getdate())
insert auto_a values (getdate())
insert auto_a values (getdate())
Проблема: таблицы MERGE
Таблицы MERGE (система хранения) представляют собой набор идентичных таблиц MyISAM,
которые можно использовать как одну.
Пример кода MySQL
create table merge_a (a int not null) engine=myisam ;
create table merge_b (b int not null) engine=myisam;
create table merge_m (m int not null)
engine=merge union=(merge_a,merge_b);
insert merge_a values (1),(2),(3);
insert merge_b values (4),(5),(6),(7);
select * from merge_a; -- 1 2 3
select * from merge_b; -- 4 5 6 7
select * from merge_m; -- 1 2 3 4 5 6 7
update merge_m set m=m+10 where m % 2 = 0;
select * from merge_a; -- 1 12 3
select * from merge_b; -- 14 5 16 7
Решение
Решения пока нет.
Проблема: синтаксис CREATE TABLE...SELECT
В MySQL можно создавать одну таблицу из другой, добавляя инструкцию SELECT в конце
инструкции CREATE TABLE.
MySQL создает новые столбцы для всех элементов в списке SELECT с уникальными именами.
Инструкция CREATE TABLE...SELECT добавляет данные результата в новую таблицу.
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
47
Пример кода MySQL
create table sel_a select 1 as id from dual;
show create table sel_a;
-- create table sel_a (id bigint not null)
select * from sel_a; -- 1
create table sel_b (id bigint not null) select 2 as id from dual;
show create table sel_b;
-- create table sel_b (id bigint not null)
select * from sel_b; -- 2
create table sel_c (id bigint not null) select 'ABC' as val, 1000 as id
from dual;
show create table sel_c;
-- create table sel_c (val varchar(3) not null, id bigint not null)
select * from sel_c; -- ABC 1000
create table sel_d (id bigint not null) select 'ABC' as val, 1000
from dual;
show create table sel_d;
-- create table sel_d (id bigint not null, val varchar(3) not null,
`1000` bigint not null)
select * from sel_d; -- 0 ABC 1000
Решение
Решения пока нет.
Проблема: синтаксис CREATE TABLE...LIKE
В MySQL поддерживается LIKE для создания пустой таблицы на базе определения другой
таблицы, включая все атрибуты столбцов и индексы, определенные в исходной таблице.
Пример кода MySQL
create table like_a (
i int not null auto_increment primary key,
d datetime not null unique,
v varchar(1024) null,
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
48
fulltext (v)
) engine = myisam;
create table like_b like like_a;
show create table like_b;
/*
create table `like_b` (
`i` int not null auto_increment,
`d` datetime not null,
`v` varchar(1024) collate latin1_general_ci default null,
primary key
(`i`),
unique key `d` (`d`),
fulltext key `v` (`v`)
) engine=myisam default charset=latin1 collate=latin1_general_ci
*/
Решение
Решения пока нет.
Проблема: ссылки чужих ключей на другие базы данных
В MySQL можно создавать ссылки чужих ключей на другие базы данных.
Решение
Решения пока нет.
Инструкция ALTER TABLE
Проблема: ключевое слово IGNORE
Расширение IGNORE определяет действия ALTER TABLE, если имеются повторяющиеся
элементы в уникальных ключах новой таблицы или появляются предупреждения при включенном строгом режиме. Если ключевое слово IGNORE не указано, то при появлении ошибки
повторяющегося ключа копия отменяется и выполняется откат. Если указано ключевое слово
IGNORE, используется только первая строка из строк, имеющих копии в уникальном ключе.
Остальные конфликтующие строки удаляются.
Решение
Решения пока нет.
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
49
Проблема: ключевые слова FIRST | AFTER
Чтобы добавить в MySQL столбец на определенном месте строки таблицы, используется
предложение FIRST или AFTER имя_столбца. По умолчанию столбец добавляется последним.
Также можно использовать предложения FIRST и AFTER в операциях CHANGE и MODIFY
со столбцами.
Решение
Решения пока нет.
Проблема: предложение ALTER
ALTER...SET DEFAULT и ALTER...DROP DEFAULT соответственно указывают новое значение
по умолчанию для столбца или удаляют старое значение по умолчанию.
Пример кода MySQL
create table alter_def (i int not null);
insert alter_def values ();
alter table alter_def alter i set default 99;
insert alter_def values ();
alter table alter_def alter i drop default;
insert alter_def values ();
select * from alter_def; -- 0 99 0
Решение
Преобразуйте предложения ALTER...SET DEFAULT и ALTER...DROP DEFAULT в предложения
ограничений ADD/DROP DEFAULT.
Пример кода SQL Server
create table alter_def (i int not null);
insert alter_def default values; -- Cannot insert the value NULL into 'i'
alter table alter_def add constraint i_def default 99 for i;
insert alter_def default values;
alter table alter_def drop constraint i_def;
insert alter_def default values; -- Cannot insert the value NULL into 'i'
select * from alter_def; -- 99
Проблема: предложение CHANGE
MySQL поддерживает предложение CHANGE в инструкциях ALTER TABLE.
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
50
Пример кода MySQL
create table change_a (i int not null);
alter table change_a change i i varchar(64) null;
show create table change_a;
alter table change_a change i d datetime not null;
show create table change_a;
Решение
Предложение CHANGE преобразуется в предложение SQL Server ALTER COLUMN.
Если CHANGE переименовывает столбец, используйте дополнительный вызов sp_rename.
Пример кода SQL Server
create table change_a (i int not null);
alter table change_a alter column i varchar(64) null;
sp_help 'change_a';
alter table change_a alter column i datetime not null;
exec sp_rename 'change_a.i', 'd', 'COLUMN';
sp_help 'change_a';
Проблема: предложение MODIFY
MySQL поддерживает предложение MODIFY в инструкциях ALTER TABLE.
Пример кода MySQL
create table modify_a (i int not null);
alter table modify_a modify i varchar(64) null;
show create table modify_a;
alter table modify_a modify i datetime not null;
show create table modify_a;
Решение
Преобразуйте предложение MODIFY в предложение ALTER COLUMN.
Пример кода SQL Server
create table modify_a (i int not null);
alter table modify_a alter column i varchar(64) null;
sp_help 'modify_a';
alter table modify_a alter column i datetime not null;
sp_help 'modify_a';
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
51
Проблема: предложение DROP [COLUMN] имя столбца
В MySQL инструкция ALTER TABLE может содержать предложение DROP с таким же значением,
как у DROP COLUMN.
Решение
Добавьте все отсутствующие ключевые слова COLUMN.
Проблема: предложение DROP PRIMARY KEY
MySQL поддерживает предложение DROP PRIMARY KEY в инструкциях ALTER TABLE.
Пример кода MySQL
create table alter_c (id int not null, v varchar(64) not null);
alter table alter_c add constraint pk_alter_c primary key (id);
alter table alter_c drop primary key;
Решение
Предложение DROP PRIMARY KEY следует заменить на предложение DROP CONSTRAINT
pk_имя_ограничения.
Пример кода SQL Server
create table alter_c (id int not null, v varchar(64) not null)
alter table alter_c add constraint pk_alter_c primary key (id)
alter table alter_c drop constraint pk_alter_c
Проблема: предложение DROP {INDEX|KEY} имя_индекса
MySQL поддерживает предложение DROP INDEX в инструкциях ALTER TABLE.
Пример кода MySQL
create table alter_i (
i int not null,
n int not null,
primary key (i),
index idx_tab_index (n));
alter table alter_i drop index idx_tab_index;
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
52
Решение
Предложения DROP INDEX в инструкциях ALTER TABLE следует преобразовать в отдельные
инструкции DROP INDEX.
Пример кода SQL Server
create table alter_i (
i int not null,
n int not null,
primary key (i))
create index idx_tab_index on alter_i (n)
drop index alter_i.idx_tab_index
Проблема: предложение DROP FOREIGN KEY
MySQL поддерживает предложение DROP FOREIGN KEY в инструкциях ALTER TABLE.
Пример кода MySQL
create table alter_f (f_id int not null, c_id int not null);
alter table alter_f add constraint fk_alter_f foreign key (c_id)
references alter_c (id);
alter table alter_f drop foreign key fk_alter_f;
Решение
Предложение DROP FOREIGN KEY следует заменить на предложение DROP CONSTRAINT
fk_имя_ограничения.
Пример кода SQL Server
create table alter_f (f_id int not null, c_id int not null)
alter table alter_f add constraint fk_alter_f foreign key (c_id)
references alter_c (id)
alter table alter_f drop constraint fk_alter_f
Проблема: предложения DISABLE KEYS и ENABLE KEYS
Предложения ALTER TABLE...DISABLE KEYS сообщают MySQL о том, что необходимо остановить
обновление неуникальных индексов для таблицы MyISAM. Затем используйте предложения
ALTER TABLE...ENABLE KEYS для повторного создания отсутствующих индексов. В MySQL
это делается по специальному алгоритму, который работает значительно быстрее, чем
поочередная вставка ключей, поэтому отключение ключей перед массовыми операциями
вставки должно значительно ускорять операции.
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
53
Решение
Решения пока нет.
Проблема: предложение RENAME
MySQL поддерживает предложение RENAME в инструкциях ALTER TABLE.
Пример кода MySQL
create table rename_a (i int not null);
insert rename_a values (1);
select * from rename_a; -- 1
alter table rename_a rename to rename_b;
select * from rename_a; -- Table 'rename_a' doesn't exist
select * from rename_b; -- 1
Решение
Преобразуйте предложение RENAME в отдельный вызов sp_rename.
Пример кода SQL Server
create table rename_a (i int not null);
insert rename_a values (1);
select * from rename_a; -- 1
exec sp_rename 'rename_a', 'rename_b';
select * from rename_a; -- Invalid object name 'rename_a'
select * from rename_b; -- 1
Проблема: предложение ORDER BY
В MySQL предложение ORDER BY в инструкции ALTER TABLE позвляет создавать новую таблицу
с определенным порядком строк.
Решение
Решения пока нет.
Инструкция RENAME DATABASE
Проблема: инструкции RENAME DATABASE
В MySQL поддерживается инструкция RENAME DATABASE.
Решение
Преобразуйте инструкции RENAME DATABASE в вызов sp_renamedb.
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
54
Инструкция RENAME TABLE
Проблема: инструкции RENAME TABLE
Инструкция MySQL RENAME TABLE позволяет переименовать одну или несколько таблиц
или представлений.
Пример кода MySQL
create table rename_a (i int not null);
insert rename_a values (1);
create table rename_b (d datetime not null);
insert rename_b values (now());
rename tables rename_a to rename_c, rename_b to rename_a,
rename_c to rename_b;
select * from rename_a; -- 2007-02-20 15:03:37
select * from rename_b; -- 1
select * from rename_c; -- Table 'ATest.rename_c' doesn't exist
create view rename_view_a as select 'view_string' as vs;
rename table rename_view_a to rename_view_b;
select * from rename_view_a; -- Table 'ATest.rename_view_a' doesn't exist
select * from rename_view_b; -- 'view_string'
Решение
Преобразуйте каждую операцию RENAME TABLE в отдельный вызов sp_rename.
Пример кода SQL Server
create table rename_a (i int not null);
insert rename_a values (1);
create table rename_b (d datetime not null);
insert rename_b values (getdate());
exec sp_rename 'rename_a', 'rename_c'
exec sp_rename 'rename_b', 'rename_a'
exec sp_rename 'rename_c', 'rename_b'
select * from rename_a; -- 2007-02-20 15:06:48.967
select * from rename_b; -- 1
select * from rename_c; -- Invalid object name 'rename_c'
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
55
create view rename_view_a as select 'view_string' as vs;
exec sp_rename 'rename_view_a', 'rename_view_b';
select * from rename_view_a; -- Invalid object name 'rename_view_a'
select * from rename_view_b; -- 'view_string'
Проблема: перемещение таблиц между базами данных при помощи инструкции RENAME TABLE
В MySQL можно использовать инструкцию RENAME TABLE для перемещения таблиц из одной
базы данных в другую.
Пример кода MySQL
create table world.rename_table (v varchar(8) null);
insert world.rename_table values ('ABC');
rename table world.rename_table to sakila.rename_table;
select * from world.rename_table;
-- Table 'world.rename_table' doesn't exist
select * from sakila.rename_table; -- 'ABC'
Решение
Решения пока нет.
Инструкции CREATE VIEW, ALTER VIEW, DROP VIEW
Проблема: префикс имени базы данных в имени представления
В отличие от MySQL в SQL Server CREATE/ALTER/DROP VIEW не позволяет указывать имя базы
данных в качестве префикса имени объекта.
Пример кода MySQL
create view sakila.view_a as select 'ABCDE' as s;
select * from sakila.view_a; -- ABCDE
drop view sakila.view_a;
Решение
Решения пока нет.
Проблема: ключевое слово LOCAL в предложении WITH CHECK OPTION
В предложении WITH CHECK OPTION для обновляемого представления ключевые слова LOCAL
и CASCADED определяют область действия контрольной проверки, когда представление
определено на основе другого представления. Ключевое слово LOCAL ограничивает действие
CHECK OPTION только определяемым представлением. При использовании ключевого слова
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
56
CASCADED проверки выполняются для базовых представлений, которые также требуется
оценить. Если ключевые слова не указаны, по умолчанию используется режим CASCADED.
Пример кода MySQL
create table t1 (a int);
create view v1 as select * from t1 where a < 2
with check option;
create view v2 as select * from v1 where a > 0
with local check option;
create view v3 as select * from v1 where a > 0
with cascaded check option;
insert into v1 values (2); -- CHECK OPTION failed 'ATest.v1'
insert into v2 values (2);
insert into v3 values (2); -- CHECK OPTION failed 'ATest.v3'
select * from t1; -- 2
Решение
Решения пока нет.
Проблема: безымянные столбцы в списке выбора представления
MySQL автоматически создает имена для безымянных столбцов в списке выбора представления.
Пример кода MySQL
create table table_name (a int not null, b int not null);
insert table_name values (1,2);
create view view_name as
select a, b, a+b, a*b, now() from table_name;
select * from view_name where `a+b`=3;
Решение
Создайте имена столбцов на базе списка выбора MySQL.
Пример кода SQL Server
create table table_name (a int not null, b int not null);
insert table_name values (1,2);
create view view_name as
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
57
select a, b, a+b as [a+b], a*b as [a*b], getdate() as [now()]
from table_name;
select * from view_name where [a+b]=3;
Инструкции CREATE EVENT, ALTER EVENT,
DROP EVENT
Проблема: события MySQL
События MySQL — это задачи, которые запускаются в соответствии с расписанием.
При создании события вы создаете именованный объект базы данных, содержащий одну
или несколько инструкций SQL, которые должны выполняться через один или несколько
постоянных интервалов, начинаясь и завершаясь в заданные дату и время.
Решение
Решения пока нет.
Инструкции CREATE, ALTER, DROP
PROCEDURE/FUNCTION
Проблема: префикс имени базы данных в имени процедуры или функции
В отличие от MySQL в SQL Server CREATE/ALTER/DROP PROCEDURE/FUNCTION
не позволяет указывать имя базы данных в качестве префикса имени объекта.
Пример кода MySQL
create function sakila.func_drop () returns float
begin
declare s float;
set s:=3.14;
return s;
end
drop function sakila.func_drop;
Решение
Решения пока нет.
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
58
Проблема: характеристика SQL SECURITY
В MySQL характеристику SQL SECURITY можно использовать, чтобы указать, как следует
выполнять процедуру: с правами пользователя, создавшего процедуру, или с правами
пользователя, вызвавшего ее. Значение по умолчанию — DEFINER.
Пример кода MySQL
root user:
create table table_access (i int not null);
insert table_access values (1),(2),(3),(4),(5);
create procedure proc_access ()
sql security definer
begin
select * from table_access;
end
grant execute on ATest.* to abc;
abc user:
select * from ATest.table_access;
-- SELECT command denied to user 'abc'
call ATest.proc_access();
-- 1 2 3 4 5
root user:
drop procedure proc_access;
create procedure proc_access ()
sql security invoker
begin
select * from table_access;
end
abc user:
select * from ATest.table_access;
-- SELECT command denied to user 'abc
call ATest.proc_access();
-- SELECT command denied to user 'abc'
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
59
Решение
Решения пока нет.
Проблема: имена параметров процедур
В отличие от SQL Server в MySQL не требуется префикс @ для имен переменных процедур.
Пример кода MySQL
create function func_pi (p int) returns float
begin
declare s float;
set s:=p*pi();
return s;
end
Решение
Преобразуйте имена параметров в процедурах в имена параметров процедур SQL
или функций и используйте знак @ в качестве первого знака.
Пример кода SQL Server
create function func_pi (@p int) returns float
begin
declare @s float;
set @s=@p*pi();
return @s;
end
Проблема: параметры процедуры INOUT
MySQL поддерживает параметры процедуры INOUT.
Пример кода MySQL
create procedure proc_inout (a int, inout b int)
begin
set b=b+a;
end
set @b=0;
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
60
call proc_out(7,@b);
select @b; -- 7
call proc_out(7,@b);
select @b; -- 14
Решение
Преобразуйте параметры процедуры MySQL INOUT в параметры процедуры SQL Server OUT.
Пример кода SQL Server
create procedure proc_inout (@a int, @b int out)
as
begin
set @b=@b+@a;
end
declare @b int
set @b=0;
exec proc_inout 7, @b out
select @b; -- 7
exec proc_inout 7, @b out
select @b; -- 14
Проблема: параметры процедуры OUT
MySQL поддерживает параметры процедуры OUT.
Параметр OUT передает значение из процедуры объекту, вызвавшему ее. Его начальное
значение равно NULL в процедуре, и его значение доступно для вызывающего объекта
при возврате процедуры.
Пример кода MySQL
create procedure proc_out (a int, out b int)
begin
set b=isnull(b)+a;
end
set @b=99;
call proc_out(7,@b);
select @b; -- 8
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
61
call proc_out(7,@b);
select @b; -- 8
Решение
Решения пока нет.
Проблема: ключевое слово AS перед текстом процедуры
В MySQL не используется ключевое слово AS перед текстом процедуры.
Пример кода MySQL
create procedure proc_as (a int, b int)
begin
select a+b;
end
Решение
Добавьте ключевое слово AS перед текстом процедуры.
Пример кода SQL Server
create procedure proc_as (@a int, @b int)
as
begin
select @a+@b;
end
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
62
Инструкции обработки данных
В этом разделе поясняются различия между языками обработки данных в MySQL и SQL
Server 2005, а также приводятся решения для устранения проблем.
Также рассматриваются инструкции SELECT, INSERT, UPDATE и DELETE, преобразования
ряда инструкций MySQL, таких как LIMIT, и поясняются различия в синтаксисе объединения.
Предложение LIMIT
Проблема: предложение LIMIT в инструкциях SELECT
С помощью предложения LIMIT можно ограничить результат инструкции MySQL SELECT.
Если в предложении LIMIT имеются два аргумента, то первый аргумент задает смещение
первой возвращаемой строки, а второй — максимальное число возвращаемых строк.
Если в предложении LIMIT имеется один аргумент, его значение задает число возвращаемых
строк, считая от начала результирующего набора.
Пример кода MySQL
select id, data from t1 order by id limit 3, 2;
Решение
Эмулируйте предложение LIMIT с одним аргументом при помощи предложения TOP
инструкции SELECT.
Для эмуляции предложения LIMIT с двумя аргументами можно использовать подчиненный
запрос с функцией ROW_NUMBER().
Пример кода SQL Server
select id, data
from
( select id, data, row_number () over (order by id) - 1 as rn
from t1 ) rn_subquery
where rn between 3 and (3+2)-1
order by id
Проблема: предложения LIMIT и ORDER BY в инструкции DELETE с одной таблицей
Предложение LIMIT устанавливает предельное число строк, которые можно удалить.
Если инструкция DELETE содержит предложение ORDER BY, то строки удаляются в порядке,
указанном в этом предложении. Это полезно только при использовании вместе с LIMIT.
Пример кода MySQL
delete from t3 where data<ascii(id) limit 2;
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
63
Решение
Эмулируйте предложение LIMIT при помощи предложения TOP инструкции DELETE.
Проверьте логику инструкций DELETE с предложениями LIMIT и ORDER BY.
Пример кода SQL Server
delete top (2) from t3 where data<ascii(id);
Проблема: предложения LIMIT и ORDER BY в инструкции UPDATE с одной таблицей
Можно использовать предложение LIMIT число_строк для ограничения области инструкции
UPDATE.
Если инструкция UPDATE содержит предложение ORDER BY, то строки обновляются в порядке,
указанном в этом предложении.
Пример кода MySQL
create table t_upd (id int not null primary key, v varchar(8) not null);
insert t_upd values (1,'A'),(2,'B'),(3,'C');
update t_upd set id=id+1; -- Error Code : 1062 Duplicate entry '2' for key
1
update t_upd set id=id+1 order by id desc; -- 3 row(s)affected
update t_upd set v=concat(v,'+',v) limit 1; -- 1 row(s)affected
Решение
Эмулируйте предложение LIMIT при помощи предложения TOP инструкции UPDATE.
Проверьте логику инструкций UPDATE с предложениями LIMIT и ORDER BY.
Пример кода SQL Server
create table t_upd (id int not null primary key, v varchar(8) not null)
insert t_upd values (1,'A')
insert t_upd values (2,'B')
insert t_upd values (3,'C')
update t_upd set id=id+1 -- 3 row(s) affected
update top (1) t_upd set v=v+'+'+v -- 1 row(s) affected
Инструкция DELETE
Проблема: DELETE для нескольких таблиц
В синтаксисе для нескольких таблиц инструкция DELETE удаляет из каждой таблицы строки,
удовлетворяющие указанным условиям.
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
64
Пример кода MySQL
create table del_a (id int not null, v varchar(8) not null);
create table del_b (id int not null, v varchar(8) not null);
insert del_a values (1,'A'),(2,'B'),(3,'C');
insert del_b values (1,'C'),(2,'B'),(3,'A');
-- deletes row with id=3 from both tables
delete a, b from del_a a, del_b b where a.id=b.id and a.v>b.v;
-- deletes row with id=3 only from table del_a
delete a from del_a a, del_b b where a.id=b.id and a.v>b.v;
Решение
Инструкцию DELETE для нескольких таблиц можно эмулировать при помощи отдельных
инструкций DELETE для каждой таблицы вместе с переменной таблицы (или временной
таблицы) для сохранения промежуточных данных.
Пример кода SQL Server
create table del_a (id int not null, v varchar(8) not null)
create table del_b (id int not null, v varchar(8) not null)
insert del_a select 1,'A' union select 2,'B' union select 3,'C'
insert del_b select 1,'C' union select 2,'B' union select 3,'A'
-- deletes row with id=3 from both tables
declare @temp table (id int, v varchar(8))
delete a output deleted.id, deleted.v into @temp
from del_a a, del_b b where a.id=b.id and a.v>b.v
delete b
from @temp a, del_b b where a.id=b.id and a.v>b.v
-- deletes row with id=3 only from table del_a
delete a from del_a a, del_b b where a.id=b.id and a.v>b.v
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
65
Инструкция UPDATE
Проблема: UPDATE для нескольких таблиц
В синтаксисе для нескольких таблиц инструкция UPDATE обновляет в каждой таблице строки,
удовлетворяющие указанным условиям.
Пример кода MySQL
create table upd_a (id int not null, v varchar(32) not null);
create table upd_b (id int not null, v varchar(32) not null);
insert upd_a values (1,'A'),(2,'B'),(3,'C');
insert upd_b values (1,'C'),(2,'B'),(3,'A');
update upd_b b, upd_a a
set a.v=concat('Z',b.v,'+',b.v),
b.v=concat('Z',a.v,'+',a.v)
where a.id=b.id and a.v>=b.v;
Решение
Инструкцию UPDATE для нескольких таблиц можно эмулировать при помощи отдельных
инструкций UPDATE для каждой таблицы вместе с переменной таблицы (или временной
таблицы) для сохранения промежуточных данных.
Пример кода SQL Server
create table upd_a (id int not null, v varchar(32) not null)
create table upd_b (id int not null, v varchar(32) not null)
insert upd_a select 1,'A' union select 2,'B' union select 3,'C'
insert upd_b select 1,'C' union select 2,'B' union select 3,'A'
declare @temp table (id int, v_old varchar(32), v_new varchar(32))
update b
set b.v='Z'+a.v+'+'+a.v
output deleted.id, deleted.v, inserted.v into @temp
from upd_b b, upd_a a
where a.id=b.id and a.v>=b.v;
update a
set a.v='Z'+b.v_new+'+'+b.v_new
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
66
from @temp b, upd_a a
where a.id=b.id and a.v>=b.v_old;
Инструкция INSERT
Проблема: инструкции INSERT и синтаксис VALUES
В MySQL инструкции INSERT, использующие синтаксис VALUES, могут вставлять несколько
строк.
Пример кода MySQL
create table tab_ins (id int not null, n numeric(19,9) not null);
insert tab_ins values (10,101.80),(20,120.90),(30,150.70);
Решение
Создайте отдельную инструкцию INSERT для каждой строки.
Пример кода SQL Serverы
create table tab_ins (id int not null, n numeric(19,9) not null)
insert tab_ins values (10,101.80)
insert tab_ins values (20,120.90)
insert tab_ins values (30,150.70)
Проблема: синтаксис INSERT...ON DUPLICATE KEY UPDATE
Если в MySQL указывается предложение ON DUPLICATE KEY UPDATE, то при вставке
строки, которая может привести к появлению повторяющегося значения в индексе UNIQUE
или ключе PRIMARY KEY, для прежней строки выполняется операция UPDATE.
В предложении UPDATE можно также использовать функцию VALUES(col_name) для
обращения к значениям столбца из части INSERT инструкции INSERT...UPDATE.
Пример кода MySQL
create table ins_upd
(a int not null primary key, b int not null, c int not null);
insert ins_upd values (1,2,3),(2,3,4),(1,20,30)
on duplicate key update c=values(c);
select * from ins_upd; -- 1 2 30, 2 3 4
Решение
Проверьте наличие добавленных ключей в индексе и выполните инструкцию INSERT
для новых ключей, а инструкцию UPDATE — для существующих.
Замените функцию VALUES ее значением.
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
67
Пример кода SQL Server
create table ins_upd
(a int not null primary key, b int not null, c int not null)
declare c cursor forward_only static read_only
for select 1,2,3 union all select 2,3,4 union all select 1,20,30
declare @a int, @b int, @c int
open c
fetch c into @a, @b, @c
while @@fetch_status=0
begin
if not exists (select top 1 0 from ins_upd where a=@a)
insert ins_upd values (@a, @b, @c)
else update ins_upd set c=@c where a=@a
fetch c into @a, @b, @c
end
close c deallocate c
select * from ins_upd; -- 1 2 30, 2 3 4
Проблема: поля INSERT и AUTO_INCREMENT
В MySQL инструкция INSERT допускает вставку в поля AUTO_INCREMENT.
Пример кода MySQL
create table table_autoinc
(id int not null auto_increment, v varchar(32) null, key (id));
insert into table_autoinc (v) values ('Value_1');
insert into table_autoinc (v) values ('Value_2');
insert into table_autoinc (v) values ('Value_3');
insert into table_autoinc (id, v) values (40,'Value_4');
insert into table_autoinc (id, v) values (50,'Value_5');
insert into table_autoinc (id, v) values (40,'Value_4_2');
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
68
insert into table_autoinc (id, v) values (40,'Value_4_3');
insert into table_autoinc (v) values ('Value_6');
insert into table_autoinc (v) values ('Value_7');
select * from table_autoinc; -- id: 1,2,3,40,50,40,40,51,52
Решение
Для эмуляции этой функциональности можно использовать инструкции SET
IDENTITY_INSERT.
Пример кода SQL Server
create table table_autoinc
(id int not null identity(1, 1), v varchar(32) null)
create index idx_table_autoinc on table_autoinc (id)
insert into table_autoinc (v) values ('Value_1');
insert into table_autoinc (v) values ('Value_2');
insert into table_autoinc (v) values ('Value_3');
set identity_insert table_autoinc on
insert into table_autoinc (id, v) values (40,'Value_4');
insert into table_autoinc (id, v) values (50,'Value_5');
insert into table_autoinc (id, v) values (40,'Value_4_2');
insert into table_autoinc (id, v) values (40,'Value_4_3');
set identity_insert table_autoinc off
insert into table_autoinc (v) values ('Value_6');
insert into table_autoinc (v) values ('Value_7');
select * from table_autoinc; -- id: 1,2,3,40,50,40,40,51,52
Проблема: выражения в синтаксисе INSERT VALUES
Выражения в синтаксисе INSERT VALUES могут ссылаться на любой столбец, заданный
ранее в списке значений.
Пример кода MySQL
create table ins_expr (a float not null, b float not null);
insert ins_expr values (sin(4),abs(a));
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
69
Решение
Замените ссылку на столбец ее значением.
Пример кода SQL Server
create table ins_expr (a float not null, b float not null);
insert ins_expr values (sin(4),abs(sin(4)));
Проблема: вставка явных и неявных значений по умолчанию
Если список столбцов и список VALUES пусты, инструкция INSERT создает строку, каждому
столбцу которой установлено значение по умолчанию: INSERT INTO имя_таблицы () VALUES();
Пример кода MySQL
create table ins_def (a int null, b int not null, c int default 1);
insert ins_def values (); -- insert ins_def () values ();
select * from ins_def; -- NULL 0 1
Решение
Решения пока нет.
Инструкция REPLACE
Проблема: инструкция REPLACE
В MySQL инструкция REPLACE работает в точности как инструкция INSERT, с одним исключением: если в старой строке таблицы такое же значение, как в новой строке для индекса
PRIMARY KEY или UNIQUE, то старая строка удаляется перед вставкой новой строки.
Пример кода MySQL
create table tab_repl
(a int not null primary key, b int not null, c int not null);
replace tab_repl values (1,2,3),(2,3,4),(1,20,30);
select * from tab_repl; -- 1 20 30, 2 3 4
Решение
Проверьте наличие добавленных ключей в индексе и выполните инструкцию INSERT для
новых ключей, а инструкцию UPDATE — для существующих или удалите существующие
ключи перед вставкой.
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
70
Пример кода SQL Server
create table tab_repl
(a int not null primary key, b int not null, c int not null)
declare c cursor forward_only static read_only
for select 1,2,3 union all select 2,3,4 union all select 1,20,30
declare @a int, @b int, @c int
open c
fetch c into @a, @b, @c
while @@fetch_status=0
begin
delete from tab_repl where a=@a;
insert tab_repl values (@a, @b, @c)
fetch c into @a, @b, @c
end
close c deallocate c
select * from tab_repl; -- 1 20 30, 2 3 4
Инструкция SELECT
Проблема: ключевое слово DISTINCTROW
В MySQL поддерживается ключевое слово DISTINCTROW в инструкциях SELECT.
Решение
Замените ключевое слово MySQL DISTINCTROW на ключевое слово SQL Server DISTINCT.
Проблема: ссылки в предложении ORDER BY
Предложение ORDER BY может ссылаться на поля, отсутствующие в списке SELECT,
при использовании инструкции DISTINCT.
Пример кода MySQL
create table tab_dist (a int, b int);
insert tab_dist values (1,30),(2,20),(3,40),(4,20),(5,10);
select distinct b from tab_dist order by a desc; -- 10 40 20 30
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
71
Решение
Это поведение можно эмулировать при помощи предложения GROUP BY.
Пример кода SQL Server
create table tab_dist (a int, b int);
insert tab_dist values (1,30)
insert tab_dist values (2,20)
insert tab_dist values (3,40)
insert tab_dist values (4,20)
insert tab_dist values (5,10)
select b from tab_dist group by b order by min(a) desc;
Проблема: таблица DUAL
В MySQL можно указать DUAL в качестве имени пустой таблицы в случаях, когда нет ссылок
на таблицы.
Пример кода MySQL
select curdate();
select curdate() from dual;
select count(*) from dual; -- 1
Решение
Обычно можно не обращать внимания на предложения FROM DUAL. Однако инструкцию
SELECT COUNT(*) FROM DUAL нужно преобразовать в SELECT 1.
Проблема: синтаксис SELECT...FROM...PROCEDURE
В MySQL можно определить процедуру Visual C++®, которая может получить доступ
и изменить данные запроса перед его отправкой клиенту.
Решение
Решения пока нет.
Инструкции SELECT…INTO и LOAD DATA INFILE
Проблема: инструкция SELECT…INTO переменная
В MySQL поддерживаются инструкции SELECT…INTO переменная.
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
72
Пример кода MySQL
select max(host), max(user) into @h, @u from mysql.user;
Решение
Определите назначение переменной в списке полей.
Пример кода SQL Server
select @h=max(host), @u=max([user]) from mysql.dbo.[user];
Проблема: инструкции SELECT…INTO и LOAD DATA INFILE
В MySQL инструкции SELECT...INTO OUTFILE служат для записи данных из таблицы в файл,
а LOAD DATA INFILE — для чтения данных из файла в таблицу.
Пример кода MySQL
select * into outfile "d:\\in.out\\table_gh.dat" from gh;
delete from gh;
load data infile "d:/in.out/table_gh.dat" into table gh;
Решение
Программа SQL Server bcp позволяет записывать таблицы в файлы и загружать содержимое
файлов в таблицы.
Пример кода SQL Server
exec xp_cmdshell 'bcp "select * from ATest.dbo.gh" queryout
"d:\table_gh.dat" -c -T'
delete from gh
exec xp_cmdshell 'bcp ATest.dbo.gh in "d:\table_gh.dat" -k -E -c -T'
Предложения GROUP BY, HAVING и ORDER BY
Проблема: ссылки на столбцы в предложениях GROUP BY и HAVING
В MySQL на столбцы из списка SELECT могут быть ссылки в предложениях GROUP BY
или HAVING с использованием псевдонимов столбцов или позиций (только в GROUP BY).
Пример кода MySQL
create table tab_alias (field_a int, field_b int);
insert tab_alias values (1,1),(1,2),(1,3),(2,1),(2,2);
select field_a as a, count(*) from tab_alias group by a order by a desc;
-- 2 2, 1 3
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
73
select field_b as b, count(*) from tab_alias group by 1 order by 1 desc;
-- 3 1, 2 2, 1 2
Решение
Ссылки на псевдонимы и позиции столбцов в предложениях GROUP BY и HAVING следует
заменить на поля, на которые указывают ссылки.
Пример кода SQL Server
create table tab_alias (field_a int, field_b int)
insert tab_alias select 1,1 union all select 1,2 union all select 1,3
union all select 2,1 union all select 2,2
select field_a as a, count(*) from tab_alias group by field_a order by a
desc
select field_b as b, count(*) from tab_alias group by field_b order by 1
desc
Проблема: сортировка GROUP BY
Если в MySQL используется сортировка GROUP BY, возвращаемые строки сортируются
в соответствии со столбцами GROUP BY, как если бы для этих столбцов использовалась
функция ORDER BY.
В MySQL расширены возможности предложения GROUP BY, так что теперь в этом
предложении можно указывать также ASC и DESC после поименованных столбцов.
Пример кода MySQL
select help_category_id, count(*)
from mysql.help_topic group by help_category_id desc
Решение
В SQL Server добавьте предложение ORDER BY для сортировки.
Проблема: синтаксис ORDER BY NULL
Чтобы избежать ненужной сортировки GROUP BY в MySQL, используется предложение
ORDER BY NULL.
Пример кода MySQL
select host, count(*) from mysql.user group by host order by null
Решение
Этот синтаксис можно пропустить.
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
74
Проблема: в предложениях SELECT и ORDER BY могут быть поля без агрегирования,
которые отсутствуют в GROUP BY
В MySQL расширены возможности GROUP BY — можно выбирать поля, не упомянутые
в предложении GROUP BY.
Подобное расширение MySQL применяется к предложению HAVING. В стандартной версии
SQL не разрешается указывать в предложении HAVING какой-либо столбец, не найденный
в предложении GROUP BY, если он не включен в агрегатную функцию. В MySQL можно
использовать эти столбцы для упрощения вычислений.
Это расширение предполагает, что несгруппированные столбцы имеют те же указанные
для группы значения. Иначе результат будет неопределенным.
Пример кода MySQL
create table customer (custid int, name varchar(32));
insert customer values (1,'Customer_A');
insert customer values (2,'Customer_B');
insert customer values (3,'Customer_C');
create table orde (custid int, payments numeric(19,2));
insert orde values (1,50.80);
insert orde values (1,140.84);
insert orde values (2,32.80);
select orde.custid, customer.name, max(payments)
from orde, customer
where orde.custid = customer.custid
group by orde.custid;
Решение
В SQL Server не поддерживаются запросы, поля которых представлены в списке SELECT или
предложении ORDER BY без агрегации, но отсутствуют в предложении GROUP BY. Измените
запрос, включив эти поля в предложение GROUP BY.
Проблема: предложение HAVING без предложения GROUP BY
В MySQL можно использовать предложение HAVING без предложения GROUP BY.
Пример кода MySQL
create table tab_hav (class varchar(128), amount int, date datetime);
insert tab_hav values ('PRINTER',2,'20061215');
insert tab_hav values ('SCANNER',3,'20070123');
insert tab_hav values ('FAX',5,'20070918');
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
75
insert tab_hav values ('PRINTER',1,'20070921');
insert tab_hav values ('PHONE',4,'20070308');
insert tab_hav values ('SCANNER',2,'20070514');
insert tab_hav values ('PRINTER',3,'20071011');
select * from tab_hav having sum(amount)=20; -- 1 row
select * from tab_hav having max(amount)=20; -- 0 row
select * from tab_hav having max(amount)=5;
-- 1 row
Решение
Для эмулирования этой функциональности преобразуйте предложение HAVING в предложение
WHERE и используйте подчиненный запрос для вычисления совокупных функций таблицы.
Соединения JOIN
Проблема: синтаксис JOIN...USING
В предложении USING (список_столбцов) указывается список столбцов, которые должны
присутствовать в обеих таблицах. Если в обеих таблицах a и b содержатся столбцы c1, c2
и c3, то соответствующие столбцы из двух таблиц будут сравниваться при следующей
операции объединения: a LEFT JOIN b USING (c1,c2,c3).
Пример кода MySQL
create table tab_value
(key_a char(8), key_b char(8), key_c char(8), value int);
create table tab_subvalue
(key_a char(8), key_b char(8), key_c char(8), subvalue int);
insert tab_value values ('A','A','A',1),('B','D','E',2),('X','Y','Z',3);
insert tab_subvalue
values ('A','A','A',100),('A','A','A',120),('B','D','M',200),
('X','Y','Z',318),('X','Y','Z',350);
select value, subvalue
from tab_value v join tab_subvalue sv using (key_a,key_b,key_c)
order by value, subvalue;
select value, subvalue
from tab_value v join tab_subvalue sv using (key_a,key_b)
order by value, subvalue;
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
76
Решение
Вместо предложения USING используйте предложение ON и задайте условие по всем
объединяемым полям.
Пример кода SQL Server
select value, subvalue
from tab_value v
join tab_subvalue sv on v.key_a=sv.key_a and v.key_b=sv.key_b
and v.key_c=sv.key_c
order by value, subvalue
select value, subvalue
from tab_value v
join tab_subvalue sv on v.key_a=sv.key_a and v.key_b=sv.key_b
order by value, subvalue
Проблема: CROSS JOIN и INNER JOIN
В MySQL с точки зрения синтаксиса CROSS JOIN эквивалентен INNER JOIN
(они взаимозаменяемы).
Пример кода MySQL
select value, subvalue
from tab_value v inner join tab_subvalue sv
order by value, subvalue;
select value, subvalue
from tab_value v cross join tab_subvalue sv on v.key_a=sv.key_a
order by value, subvalue;
Решение
В MySQL INNER JOIN можно использовать без условий объединения (ON …). В этом случае
он работает как CROSS JOIN.
В MySQL CROSS JOIN можно использовать с условиями объединения (ON …). В этом случае
он работает как INNER JOIN.
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
77
Пример кода SQL Server
select value, subvalue
from tab_value v cross join tab_subvalue sv
order by value, subvalue
select value, subvalue
from tab_value v inner join tab_subvalue sv on v.key_a=sv.key_a
order by value, subvalue
Проблема: STRAIGHT_JOIN
Выражение STRAIGHT_JOIN идентично выражению JOIN, за исключением того, что левая
таблица всегда читается раньше правой. Его можно использовать для тех (немногих) случаев,
когда оптимизатор объединения располагает таблицы в неправильном порядке.
Пример кода MySQL
select value, subvalue
from tab_value v straight_join tab_subvalue sv
order by value, subvalue;
select value, subvalue
from tab_value v straight_join tab_subvalue sv on v.key_a=sv.key_a
order by value, subvalue;
Решение
Ключевое слово MySQL STRAINT_JOIN решает проблему оптимизации, и в большинстве
случаев его можно заменить функцией объединения INNER или CROSS.
Пример кода SQL Server
select value, subvalue
from tab_value v cross join tab_subvalue sv
order by value, subvalue
select value, subvalue
from tab_value v inner join tab_subvalue sv on v.key_a=sv.key_a
order by value, subvalue
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
78
Проблема: NATURAL JOIN
Выражение NATURAL [LEFT] JOIN для двух таблиц определяется как семантический
эквивалент выражения INNER JOIN или LEFT JOIN с предложением USING, в котором
указываются все столбцы, имеющиеся в обеих таблицах.
Пример кода MySQL
select value, subvalue
from tab_value v natural join tab_subvalue sv
order by value, subvalue;
Решение
Если в объединяемых таблицах имеются столбцы с одинаковыми именами, преобразуйте
объединение NATURAL в объединение INNER по этим столбцам. Или же преобразуйте
объединение NATURAL в объединение CROSS.
Пример кода SQL Server
select value, subvalue
from tab_value v
join tab_subvalue sv on v.key_a=sv.key_a and v.key_b=sv.key_b
and v.key_c=sv.key_c
order by value, subvalue
Subqueries
Проблема: подчиненные запросы строк
В MySQL поддерживаются подчиненные запросы строк. Подчиненный запрос строки —
это вариант подчиненного запроса, который возвращает одну строку и, таким образом,
может вернуть несколько значений столбцов.
Пример кода MySQL
A: select * from gh where (id, value) = row(1, 'A');
B: select * from gh
where (id, value) = (select subid, value from gj where gj.id=gh.id);
Решение
Перепишите инструкции MySQL с подчиненными запросами строк, используя логический
оператор AND и условие EXISTS.
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
79
Пример кода SQL Server
A: select * from gh where id = 1 and value = 'A'
B: select * from gh
where exists (select 1 from gj
where gj.id=gh.id and gj.subid=gh.id and gj.value=gh.value)
Подготовленные инструкции
Проблема: серверные подготовленные инструкции
В MySQL 5.1 поддерживаются серверные подготовленные инструкции. Областью
подготовленной инструкции является клиентский сеанс, в котором она создается.
PREPARE stmt_name FROM preparable_stmt
EXECUTE stmt_name [USING @var_name [, @var_name] ...]
{DEALLOCATE | DROP} PREPARE stmt_name
Пример
create procedure ProcPrepare ()
begin
execute prep_stmt using @a, @b;
end
prepare prep_stmt from 'select sqrt(pow(?,2) + pow(?,2)) as hypotenuse';
set @a = 3, @b = 4;
call procprepare();
deallocate prepare prep_stmt;
Решение
Решения пока нет.
Команда DO
Проблема: синтаксис DO
В MySQL команда DO выполняет выражения, но не возвращает никаких результатов.
Во многих отношениях DO представляет собой краткий вариант предложения SELECT
выражение, ..., но работает немного быстрее, когда не нужно возвращать результаты.
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
80
Пример 1
select @a:=200; -- sets @a and returns 200
select @a; -- returns 200
do @a:=300; -- sets @a
select @a; -- returns 300
Пример 2
create table TableDO (d int not null);
create function func_do (par_d int) returns int
begin
delete from TableDO where d=par_d;
return row_count();
end
insert TableDO values (1), (2), (3);
do func_do(2);
select d from TableDO; -- 1, 3
do @r:=func_do(1);
select @r, d from TableDO; -- 1 3
Решение
Решения пока нет.
Обработчики
Проблема: интерфейс HANDLER
MySQL поддерживает интерфейс HANDLER для чтения данных таблицы.
HANDLER tbl_name OPEN [ AS alias ]
HANDLER tbl_name READ index_name { = | >= | <= | < } (value1,value2,...)
[ WHERE where_condition ] [LIMIT ... ]
HANDLER tbl_name READ index_name { FIRST | NEXT | PREV | LAST }
[ WHERE where_condition ] [LIMIT ... ]
HANDLER tbl_name READ { FIRST | NEXT }
[ WHERE where_condition ] [LIMIT ... ]
HANDLER tbl_name CLOSE
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
81
Инструкция HANDLER предоставляет прямой доступ к интерфейсам системы хранения
таблиц. Он доступен для таблиц MyISAM и InnoDB.
Пример
HANDLER TableA OPEN;
HANDLER TableA READ FIRST LIMIT 100;
HANDLER TableA CLOSE;
Решение
Решения пока нет.
Модификаторы
Проблема: модификаторы (LOW_PRIORITY, DELAYED, HIGH_PRIORITY, QUICK, IGNORE)
в инструкциях DML
Эти модификаторы MySQL позволяют применять нечто вроде уровня изоляции отдельно
для каждой инструкции и управлять выдачей сообщений об ошибках.
Решение
Решения пока нет.
Инструкции транзакций и блокировки
В этом разделе описываются основные различия между инструкциями транзакций и управления
блокировкой в MySQL и SQL Server 2005, запуск, сохранение и откат, блокировка таблиц, работа
с уровнями изоляции и режим AUTOCOMMIT.
Инструкции BEGIN TRANSACTION
Проблема: другой синтаксис начала транзакции
В MySQL и SQL Server используется разный синтаксис для начала транзакции.
Решение
Вместо инструкций MySQL START TRANSACTION в пакетах и подпрограммах и инструкций
BEGIN/BEGIN WORK в пакетах используйте инструкцию SQL Server BEGIN TRANSACTION.
Проблема: инструкции начала транзакций неявно сохраняют текущую транзакцию
Инструкция начала транзакции MySQL неявно сохраняет текущую транзакцию.
Решение
Добавьте инструкцию сохранения транзакции с проверкой состояния @@TRANCOUNT перед
инструкцией начала транзакции.
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
82
Проблема: инструкции, вызывающие неявное сохранение
Каждая из следующих инструкций MySQL (и их синонимов) неявно завершает транзакцию,
как при выполнении COMMIT перед выполнением инструкции:
ALTER FUNCTION, ALTER PROCEDURE, ALTER TABLE, BEGIN, CREATE DATABASE, CREATE
FUNCTION, CREATE INDEX, CREATE PROCEDURE, CREATE TABLE, DROP DATABASE, DROP
FUNCTION, DROP INDEX, DROP PROCEDURE, DROP TABLE, LOAD MASTER DATA, LOCK
TABLES, LOAD DATA INFILE, RENAME TABLE, SET AUTOCOMMIT=1, START TRANSACTION,
TRUNCATE TABLE, UNLOCK TABLES.
Решение
Добавьте инструкцию сохранения транзакции с проверкой состояния @@TRANCOUNT
перед инструкциями, вызывающими неявное сохранение.
Проблема: инструкции, откат которых невозможен
Для некоторых инструкций MySQL невозможно выполнить откат. Как правило, это инструкции
языка описания данных (DDL), например те, которые создают или удаляют базы данных, а
также те, которые создают, удаляют или изменяют таблицы или хранимые подпрограммы.
Решение
Решения пока нет.
Проблема: системы хранения не поддерживают транзакции
Транзакции не влияют на операции с таблицами, которые основаны на системах хранения,
не поддерживающих транзакции.
Пример кода MySQL
create table tran_x (i int not null) engine = innodb;
create table tran_y (i int not null) engine = myisam;
start transaction;
insert tran_x values (7);
insert tran_y values (7);
rollback;
select * from tran_x; -select * from tran_y; -- 7
Решение
Решения пока нет.
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
83
Инструкции END TRANSACTION
Проблема: инструкция окончания транзакции без инструкции начала транзакции
Инструкции окончания транзакции можно выполнять до инструкций начала транзакции.
Решение
Добавьте условие IF (@@TRANCOUNT>0) перед инструкциями COMMIT / COMMIT WORK /
ROLLBACK / ROLLBACK WORK.
Проблема: предложение CHAIN
Предложение MySQL AND CHAIN запускает новую транзакцию сразу после окончания текущей
транзакции. Новая транзакция имеет такой же уровень изоляции, как и только что оконченная.
Решение
Замените предложение MySQL CHAIN на инструкцию SQL Server BEGIN TRANSACTION после
инструкции END TRANSACTION.
Проблема: предложение RELEASE
Предложение RELEASE отключает на сервере текущее подключение клиента после
завершения текущей транзакции.
Решение
Решения пока нет.
Именованные инструкции SAVEPOINT транзакций
Проблема: различный синтаксис
В MySQL и SQL Server используется разный синтаксис для инструкции SAVEPOINT.
Пример кода MySQL
create table tran_a (i int not null);
begin;
insert tran_a values (1);
start transaction;
insert tran_a values (2);
rollback and chain;
insert tran_a values (3);
savepoint spoint;
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
84
insert tran_a values (4);
rollback to savepoint spoint;
commit;
select * from tran_a; -- 1 3
Решение
Замените инструкции MySQL SAVEPOINT имя_точки_сохранения на инструкции SQL Server
SAVE TRANSACTION имя_точки_сохранения.
Замените инструкции MySQL ROLLBACK [WORK] TO SAVEPOINT имя_точки_сохранения
на инструкции SQL Server ROLLBACK TRANSACTION имя_точки_сохранения.
Пример кода SQL Server
create table tran_a (i int not null)
begin transaction
insert tran_a values (1)
if (@@trancount>0) commit
begin transaction
insert tran_a values (2)
if (@@trancount>0) rollback
begin transaction
insert tran_a values (3)
save transaction spoint
insert tran_a values (4)
rollback transaction spoint
if (@@trancount>0) commit
select * from tran_a -- 1 3
Проблема: инструкция RELEASE SAVEPOINT
Инструкция MySQL RELEASE SAVEPOINT удаляет именованную точку сохранения из набора
точек сохранения текущей транзакции.
Решение
Решения пока нет.
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
85
Инструкции SET AUTOCOMMIT
Проблема: инструкция SET AUTOCOMMIT
В MySQL поддерживается инструкция SET AUTOCOMMIT.
Пример кода MySQL
create table tran_auto (i int not null);
set autocommit = 1;
insert tran_auto values (10);
insert tran_auto values (20);
rollback;
set autocommit = 0;
insert tran_auto values (30);
insert tran_auto values (40);
rollback;
insert tran_auto values (50);
commit;
select * from tran_auto; -- 10 20 50
Решение
Замените SET AUTOCOMMIT = 1 на SET IMPLICIT_TRANSACTIONS OFF.
Замените SET AUTOCOMMIT = 0 на SET IMPLICIT_TRANSACTIONS ON.
Пример кода SQL Server
create table tran_auto (i int not null)
set implicit_transactions off
insert tran_auto values (10)
insert tran_auto values (20)
if (@@trancount>0) rollback
set implicit_transactions on
insert tran_auto values (30)
insert tran_auto values (40)
if (@@trancount>0) rollback;
insert tran_auto values (50)
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
86
if (@@trancount>0) commit
select * from tran_auto -- 10 20 50
Инструкции LOCK TABLES и UNLOCK TABLES
Проблема: синтаксис LOCK TABLES и UNLOCK TABLES
LOCK TABLES блокирует базовые таблицы (но не представления) для текущего потока.
UNLOCK TABLES снимает все блокировки, удерживаемые текущим потоком.
Если поток получает блокировку READ для таблицы, этот поток (и все остальные потоки)
может только читать из таблицы. Если поток получает блокировку WRITE для таблицы,
то только удерживающий блокировку поток может записывать в таблицу и читать из нее.
Для других потоков запись или чтение в таблице заблокированы до тех пор, пока блокировка
не будет снята.
Решение
Решения пока нет.
Инструкция SET TRANSACTION ISOLATION LEVEL
Проблема: уровень изоляции транзакций MySQL по умолчанию
В MySQL по умолчанию используется уровень изоляции транзакций REPEATABLE READ.
В SQL Server по умолчанию используется уровень изоляции транзакций READ COMMITTED.
Решение
Решения пока нет.
Инструкции транзакций XA
Проблема: транзакции XA
Реализация транзакций MySQL XA основана на документе X/Open CAE Distributed Transaction
Processing: The XA Specification.
Интерфейс XA к серверу MySQL состоит из инструкций SQL, начинающихся с ключевого
слова XA.
Решение
Решения пока нет.
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
87
Инструкции администрирования баз данных
В этом разделе описывается преобразование административных инструкций MySQL,
включая управление учетными записями и обслуживание таблиц.
Инструкции управления учетными записями
Проблема: инструкции CREATE USER, DROP USER, GRANT, RENAME USER, REVOKE,
SET PASSWORD
В MySQL и SQL Server используется разный синтаксис для этих инструкций.
Решение
Решения пока нет.
Инструкции обслуживания таблиц
Проблема: инструкции ANALYZE TABLE, BACKUP TABLE, CHECK TABLE, CHECKSUM TABLE,
OPTIMIZE TABLE, REPAIR TABLE, RESTORE TABLE
В SQL Server нет идентичных инструкций.
Решение
Решения пока нет.
Инструкция SET
Проблема: присвоение нескольких переменных в инструкциях SET
В MySQL в инструкции SET можно указывать несколько назначений переменных, разделяя их
запятыми. В SQL Server инструкция SET может содержать только одно назначение переменной.
Пример кода MySQL
create procedure proc_set_var ()
begin
declare a, b int;
set a=10, b=20;
select a+b;
end
call proc_set_var () -- 30
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
88
Решение
Преобразуйте каждое назначение переменной в отдельную инструкцию SET.
Пример кода SQL Server
create procedure proc_set_var
as
begin
declare @a int, @b int
set @a=10
set @b=20
select @a+@b
end
exec proc_set_var -- 30
Проблема: системные переменные сервера (глобальные переменные)
Сервер MySQL поддерживает множество системных переменных, определяющих его конфигурацию. Для каждой системной переменной имеется значение по умолчанию. Системные
переменные могут задаваться при запуске сервера с использованием параметров в командной
строке или файле параметров. Большинство из них может изменяться динамически во время
работы сервера посредством инструкции SET, что позволяет изменять режим работы сервера
без остановки и перезапуска. Значения системных переменных можно указывать в выражениях.
Значения системных переменных могут задаваться глобально при запуске сервера с использованием параметров в командной строке или файле параметров.
Многие системные переменные являются динамическими, и их можно изменять во время
работы сервера с помощью инструкции SET. Чтобы изменить системную переменную с
помощью инструкции SET, укажите ее как var_name, при желании можно указать перед ней
модификатор.

Для явного указания на то, что переменная является глобальной, перед ее именем
укажите GLOBAL или @@global.

Для явного указания на то, что переменная является переменной сеанса, перед ее
именем укажите SESSION, @@session. или @@.

LOCAL и @@local. являются синонимами SESSION и @@session.
Если модификатор не указан, инструкция SET изменяет переменную сеанса.
В инструкции SET можно указывать несколько назначений переменных, разделяя их запятыми.
При изменении переменной сеанса значение продолжает действовать до тех пор, пока сеанс
не завершится или пока вы не измените значение переменной. Другие клиенты изменение не видят.
При изменении глобальной системной переменной значение запоминается и используется
для новых подключений до тех пор, пока сервер не перезагрузится. (Чтобы сделать назначение
глобальной системной переменной постоянным, задайте ее в файле параметров.)
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
89
Чтобы задать для переменной SESSION значение GLOBAL или скомпилированное по
умолчанию значение MySQL в качестве значения GLOBAL, используйте ключевое слово
DEFAULT.
См. также: режим SQL
Пример
create table table_inc
(id int not null auto_increment, unique key (id), v varchar(8) null);
insert table_inc (v) values ('A');
insert table_inc (v) values ('B');
insert table_inc (v) values ('C');
set session auto_increment_increment = 7;
insert table_inc (v) values ('D');
insert table_inc (v) values ('E');
set session auto_increment_increment = default;
insert table_inc (v) values ('F');
insert table_inc (v) values ('G');
select id from table_inc; -- 1 2 3 8 15 16 17
Решение
Решения пока нет.
Инструкция SHOW
Проблема: синтаксис SHOW
SHOW имеет множество форм, предоставляющих сведения о базах данных, таблицах,
столбцах и состоянии сервера.
См. также: синтаксис DESCRIBE
Решение
Решения пока нет.
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
90
Проблема: синтаксис DESCRIBE
DESCRIBE предоставляет сведения о столбцах в таблице. Это ярлык для SHOW COLUMNS
FROM. Эти инструкции также отображают сведения о представлениях.
Решение
Решения пока нет.
Другие административные инструкции
Проблема: инструкции CACHE INDEX, LOAD INDEX INTO CACHE, FLUSH, RESET, KILL
В SQL Server нет идентичных инструкций.
Решение
Решения пока нет.
Хранимые процедуры и функции (процедуры)
В этом разделе описываются различия между языком расширения процедур SQL в MySQL
и SQL Server. Описываются создание и вызов хранимых процедур и функций, работа
с локальными переменными, курсоры и управление инструкциями потока.
Инструкции CALL
Проблема: синтаксис процедур вызова
В MySQL инструкция CALL используется для вызова процедуры.
В MySQL поддерживаются выражения в виде параметров вызова.
Пример кода MySQL
create procedure proc_case (s varchar(64),
out s_low varchar(64), out s_up varchar(64))
begin
set s_low:=lower(s), s_up:=upper(s);
end
call proc_case (date_format(now(),'%D %M %Y'),@low,@up);
select @low, @up; -- 23rd october 2007, 23RD OCTOBER 2007
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
91
Решение
Преобразуйте инструкции MySQL CALL в инструкции Transact-SQL EXEC. Выражения в
параметрах вызовов можно вычислить с временными переменными перед инструкциями.
Включите ключевое слово OUTPUT для выходных параметров.
Пример кода SQL Server
create procedure proc_case (@s varchar(64),
@s_low varchar(64) out, @s_up varchar(64) out) as
begin
select @s_low=lower(@s), @s_up=upper(@s)
end
declare @s varchar(64), @low varchar(64), @up varchar(64)
set @s=convert(varchar(64),getdate(),106)
exec proc_case @s, @low output, @up output
select @low, @up; -- 23 oct 2007, 23 OCT 2007
Составные инструкции
Проблема: пустые составные инструкции
Пустые составные инструкции (BEGIN END) допустимы в MySQL, но не в Transact-SQL.
Пример кода MySQL
create procedure empty_block(i int)
begin
select sin(i);
begin
end;
select cos(i);
end
Решение
Пропускайте такие инструкции.
Проблема: помеченные составные инструкции
В MySQL составные инструкции можно помечать. Невозможно использовать метку окончания,
если нет метки начала. Если есть обе метки, их имена должны совпадать.
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
92
Пример кода MySQL
create procedure lab_comp()
begin
s: begin
select 'STEP 1'; -- displayed
leave s;
select 'STEP 2'; -- ignored
end;
select 'STEP 3'; -- displayed
end
Решение
Эмулируйте поведение LEAVE в помеченной составной инструкции при помощи инструкции
Transact-SQL GOTO.
Пример кода SQL Server
create procedure lab_comp as
begin
begin
select 'STEP 1'; -- displayed
goto s;
select 'STEP 2'; -- ignored
end;
s: select 'STEP 3'; -- displayed
end
Локальные переменные
Проблема: объявление переменных одинакового типа
MySQL допускает объявление нескольких переменных одного типа в одной инструкции.
Пример кода MySQL
declare x, y, z int;
Решение
Объявляйте тип каждой переменной в SQL Server.
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
93
Пример кода SQL Server
declare @x int, @y int, @z int
Проблема: DECLARE c DEFAULT
В MySQL предложение DEFAULT предоставляет значение переменной по умолчанию.
Это значение можно указать как выражение.
Пример кода MySQL
declare x, y int default sqrt(225);
declare z int default 123;
Решение
Выполните инициализацию переменной после ее объявления.
Пример кода SQL Server
declare @x int, @y int
select @x=sqrt(225), @y=sqrt(225)
declare @z int
select @z=123
Проблема: область значения локальных переменных
В MySQL область локальной переменной находится внутри блока BEGIN...END, где она
объявлена. На переменную можно ссылаться в блоках, размещенных внутри данного блока,
кроме блоков, где объявляется переменная с таким же именем.
Пример кода MySQL
create procedure var_scope()
begin
declare a, b int;
set a=5, b=7;
select a, b; -- 5 7
begin
declare a int;
set a=9;
select a, b; -- 9 7
end;
select a, b; -- 5 7
end
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
94
Решение
Решения пока нет.
Проблема: имена переменных SQL могут совпадать с именами столбцов
Если инструкция SQL содержит ссылку на столбец и объявляет локальную переменную с таким
же именем, MySQL интерпретирует ссылку как имя переменной.
Пример кода MySQL
create procedure var_field()
begin
create temporary table if not exists vf (a int, b int);
insert vf values (1,1),(1,2),(1,3);
select a, b from vf; -- 1 1, 1 2, 1 3
begin
declare a int default 7;
select a, b from vf; -- 7 1, 7 2, 7 3
end;
end
Решение
При преобразовании интерпретируйте двойные ссылки как имя переменной.
Пример кода SQL Server
create procedure var_field as
begin
create table #vf (a int, b int)
insert #vf values (1,1)
insert #vf values (1,2)
insert #vf values (1,3)
select a, b from #vf -- 1 1, 1 2, 1 3
begin
declare @a int
set @a=7
select @a, b from #vf -- 7 1, 7 2, 7 3
end;
end
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
95
Условия и обработчики
Проблема: обработка условий MySQL
Для управления условиями в MySQL определяются обработчики.
Для задания условий, которым необходима специфическая обработка, используется
инструкция DECLARE CONDITION.
Обработчики задаются инструкцией DECLARE HANDLER. Каждый обработчик обрабатывает
одно или несколько условий. При соблюдении одного из этих условий выполняется инструкция
(составная инструкция), указанная в обработчике.
Пример
create table TableCondition_A (c_a int not null);
create table TableCondition_B (c_b int not null);
create procedure ProcCondition (in par_value int, inout par_null_error
int)
begin
declare cond_a condition for sqlstate value '23000';
-- Error: 1048 SQLSTATE: 23000 (ER_BAD_NULL_ERROR)
-- Message: Column '%s' cannot be null
declare continue handler for cond_a
begin set par_null_error=par_null_error+1; end;
set par_null_error=0;
insert TableCondition_A values (par_value);
insert TableCondition_B values (par_value);
end
call ProcCondition (null, @err);
select @err; -- 2
call ProcCondition (100, @err);
select @err; -- 0
Решение
Решения пока нет.
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
96
Курсоры
Проблема: состояние курсора No Data
В MySQL требуется обработчик со значением SQLSTATE 02000 для обнаружения состояния
курсора No Data.
Пример кода MySQL
create table t1 (id char(16), data int);
create table t2 (i int);
create table t3 (id char(16), data int);
insert t1 values ('A',65),('K',75),('Q',81),('S',83),('W',87);
insert t2 values (10),(100),(20),(200),(30);
create procedure curdemo()
begin
declare done int default 0;
declare a char(16);
declare b, c int;
declare cur1 cursor for select id, data from t1;
declare cur2 cursor for select i from t2;
declare continue handler for sqlstate '02000' set done = 1;
open cur1;
open cur2;
repeat
fetch cur1 into a, b;
fetch cur2 into c;
if not done then
if b < c then
insert into t3 values (a,b);
else
insert into t3 values (a,c);
end if;
end if;
until done end repeat;
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
97
close cur1;
close cur2;
end
call curdemo();
select * from t3; -- A 10, K 75, Q 20, S 83, W 30
Решение
Используйте переменную Transact-SQL @@FETCH_STATUS для определения состояния
последней инструкции курсора FETCH.
Пример кода SQL Server
create procedure curdemo as
begin
declare @done int set @done=0
declare @a char(16)
declare @b int, @c int
declare cur1 cursor forward_only static read_only
for select id, data from t1;
declare cur2 cursor forward_only static read_only
for select i from t2;
open cur1;
open cur2;
while @done=0
begin
fetch cur1 into @a, @b;
if @@fetch_status<>0 set @done = 1
fetch cur2 into @c;
if @@fetch_status<>0 set @done = 1
if @done<>1
begin
if @b < @c
begin insert into t3 values (@a,@b); end
else
begin insert into t3 values (@a,@c); end
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
98
end
end;
close cur1 deallocate cur1
close cur2 deallocate cur2
end
Конструкции управления потоком
Проблема: инструкция IF
В MySQL и SQL Server используется разный синтаксис для инструкции IF.
Пример кода MySQL
if (1>2)
then select 'A'; select 'B';
elseif (2>3) then select 'C'; select 'D';
elseif (3>4) then select 'E'; select 'F';
else select 'G'; select 'H';
end if;
Решение
Инструкцию MySQL IF можно с легкостью эмулировать в SQL Server.
Пример кода SQL Server
if (1>2)
begin select 'A' select 'B' end
else if (2>3) begin select 'C' select 'D' end
else if (3>4) begin select 'E' select 'F' end
else begin select 'G' select 'H' end
Проблема: инструкция CASE
В MySQL и SQL Server используется разный синтаксис для инструкции CASE.
Пример кода MySQL
case int_value
when 1 then select 'A'; select 'AA';
when 2 then select 'B';
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
99
when 1 then select 'A1'; select 'A2'; -- ignored
when 3 then select 'C';
else select 'NULL';
end case;
Решение
Инструкции CASE можно эмулировать при помощи инструкций SQL Server IF.
Пример кода SQL Server
if @int_value=1 begin select 'A' select 'AA' end
else if @int_value=2 begin select 'B' end
else if @int_value=1 begin select 'A1' select 'A2' end
else if @int_value=3 begin select 'C' end
else begin select 'NULL' end
Проблема: инструкции LOOP и REPEAT
В SQL Server нет идентичных инструкций.
Пример кода MySQL
declare i int;
set i=0;
m: loop
set i:=i+1;
if (sin(i) - cos(i) < 0) then leave m; end if;
end loop;
select i; -- 4
set i=0;
repeat
set i:=i+1;
until (sin(i) - cos(i) < -1)
end repeat;
select i; -- 5
Решение
Инструкции MySQL LOOP и REPEAT можно с легкостью эмулировать при помощи инструкций
WHILE в SQL Server.
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
100
Пример кода SQL Server
declare @i int;
set @i=0;
while 1=1
begin
set @i=@i+1;
if (sin(@i) - cos(@i) < 0) break;
end;
select @i; -- 4
set @i=0;
while 1=1
begin
set @i=@i+1;
if (sin(@i) - cos(@i) < -1) break;
end
select @i; -- 5
Проблема: инструкции LEAVE и ITERATE
В SQL Server нет идентичных инструкций.
Пример кода MySQL
create procedure proc_goto(s varchar(64), a int, b int)
begin
m1: loop
if (a>b) then leave m1; end if;
set s:=concat(substring(s,1,a-1),
upper(substring(s,a,1)),substring(s,a+1));
set a:=a+1;
if (a>b) then iterate m1; end if;
set a:=a+1;
end loop;
select s;
end
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
101
call proc_goto ('abcdefghijklmnopqrstuvwxyz',5,10)
-- abcdEfGhIjklmnopqrstuvwxyz
Решение
Для эмуляции этой функции используйте инструкции Transact-SQL BREAK и CONTINUE.
Пример кода SQL Server
create procedure proc_goto (@s varchar(64), @a int, @b int) as
begin
while 1=1
begin
if (@a>@b) break
set @s=substring(@s,1,@a-1)+
upper(substring(@s,@a,1))+substring(@s,@a+1,len(@s));
set @a=@a+1;
if (@a>@b) continue
set @a=@a+1;
end
select @s
end
exec proc_goto 'abcdefghijklmnopqrstuvwxyz',5,10
-- abcdEfGhIjklmnopqrstuvwxyz
Процедуры
Проблема: инструкции DML в функциях
Функции MySQL могут содержать инструкции DML. Это не поддерживается в SQL Server.
Пример
create table TableFuncA (a int not null);
create table TableFuncB (b int not null);
create function new_func_a (par_int int) returns int
begin
delete from TableFuncA where a=par_int;
return row_count();
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
102
end
insert TableFuncA values (10), (20), (20), (30), (30), (30),
(40), (40), (40), (40);
insert TableFuncB values (20), (40), (50);
select new_func_a(b)
from TableFuncB; -- 2 4 0
select * from TableFuncA; -- 10 30 30 30
Решение
Решения пока нет.
Триггеры
В этом разделе описывается преобразование триггеров MySQL в триггеры SQL Server 2005.
Проблема: триггеры FOR EACH ROW
В MySQL поддерживаются триггеры FOR EACH ROW, которые не поддерживаются в SQL Server.
Пример кода MySQL
create table t_data (
id int not null primary key,
v varchar(128) not null, log_date datetime not null);
create table t_log (
id int null, action varchar(6) null,
v_old varchar(128) null, v_new varchar(128) null,
log_date_old datetime null, log_date_new datetime null);
create trigger trg_data_ins
after insert
on t_data
for each row
begin
declare a varchar(6);
if (new.v!='') then set a:='INSERT'; else set a:='EMPTY'; end if;
insert t_log (id,action,v_old,v_new,log_date_old,log_date_new)
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
103
values (new.id,a,null,new.v,null,new.log_date);
end
insert t_data
values (1,'A',now()),(2,'B',now()),(3,'',now()),(4,'C',now());
Решение
Для эмуляции функциональности триггера FOR EACH ROW в SQL Server можно использовать
курсор.
Пример кода SQL Server
create trigger trg_data_ins
on t_data
after insert
as
begin
declare @id int, @v varchar(128), @log_date datetime
declare for_each_row cursor forward_only static read_only
for select id, v, log_date from inserted
declare @a varchar(6);
open for_each_row
fetch for_each_row into @id, @v, @log_date
while @@fetch_status = 0
begin
if (@v!='') set @a='INSERT' else set @a='EMPTY';
insert t_log (id,action,v_old,v_new,log_date_old,log_date_new)
values (@id,@a,null,@v,null,@log_date);
fetch for_each_row into @id, @v, @log_date
end
close for_each_row
deallocate for_each_row
end
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
104
Проблема: триггеры BEFORE
В MySQL поддерживаются триггеры BEFORE. В триггерах MySQL ключевое слово BEFORE
указывает, что триггер вызывается до выполнения инструкции срабатывания триггера.
Внутри триггера можно обращаться к столбцам зависимой таблицы (таблицы, связанной
с триггером) с помощью псевдонимов OLD и NEW. OLD.имя_столбца обращается к столбцу
в имеющейся строке до ее обновления или удаления. NEW.имя_столбца обращается к
столбцу новой строки, которую нужно вставить, или имеющейся строки после обновления.
Пример кода MySQL
create trigger trg_data_upd
before update
on t_data
for each row
begin
set new.log_date:=now();
if (old.v='') then set new.v:=''; end if;
insert t_log (id,action,v_old,v_new,log_date_old,log_date_new)
values (old.id,'UPDATE',old.v,new.v,old.log_date,new.log_date);
end
update t_data set v=concat(v,'+',v);
Решение
Для эмуляции триггера BEFORE в SQL Server можно использовать триггер INSTEAD OF.
Пример кода SQL Server
create trigger trg_data_upd
on t_data
instead of update
as
begin
declare @id_old int, @v_old varchar(128), @log_date_old datetime
declare @id_new int, @v_new varchar(128), @log_date_new datetime
declare for_each_row cursor forward_only static read_only
for select id, v, log_date from deleted
open for_each_row
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
105
fetch for_each_row into @id_old, @v_old, @log_date_old
while @@fetch_status = 0
begin
select @id_new=id, @v_new=v, @log_date_new=log_date
from inserted where id=@id_old
set @log_date_new=getdate();
if (@v_old='') set @v_new='';
insert t_log (id,action,v_old,v_new,log_date_old,log_date_new)
values (@id_old,'UPDATE',@v_old,@v_new,@log_date_old,@log_date_new);
-- insted of ----------------------------------------update t_data
set v=@v_new, log_date=@log_date_new
where id=@id_old
------------------------------------------------------
fetch for_each_row into @id_old, @v_old, @log_date_old
end
close for_each_row
deallocate for_each_row
end
Режим SQL (системная переменная SQL_MODE)
Проблема: применение различных режимов SQL
Сервер MySQL может работать в различных режимах SQL и по-разному применять эти режимы
для разных клиентов. Режимы определяют, какой синтаксис SQL поддерживается в MySQL
и какие виды проверок достоверности данных выполняются.
Для смены и восстановления режима SQL в MySQL используется системная переменная
sql_mode.
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
106
Пример
SET sql_mode = '';
SELECT NOT 1 BETWEEN -5 AND 5; -- 0
SET sql_mode = 'HIGH_NOT_PRECEDENCE';
SELECT NOT 1 BETWEEN -5 AND 5; -- 1 -- (NOT 1) BETWEEN -5 AND 5
Решение
Решения пока нет.
Перенос системных функций MySQL
В этом разделе описываются сопоставление системных функций MySQL с эквивалентными
функциями SQL Server 2005 и решения для преобразования функций MySQL.
Эквивалентные функции
Следующие системные функции MySQL можно использовать так же, как и в коде SQL Server:
ASCII, LEFT, LOWER, LTRIM, REPLACE, REVERSE, RIGHT, RTRIM, SOUNDEX, SPACE,
SUBSTRING, UPPER, ABS, ACOS, ASIN, ATAN, ATAN2, CEILING, COS, COT, DEGREES, EXP,
FLOOR, LOG, LOG10, PI, POWER, RADIANS, RAND, ROUND, SIGN, SIN, SQRT, TAN, DAY,
MONTH, COALESCE, NULLIF, CAST, CONVERT.
Неподдерживаемые функции
Следующие функции MySQL невозможно эмулировать в SQL Server из-за различий
в логическом и физическом устройстве, а также в модели безопасности:
BENCHMARK, CHARSET, COERCIBILITY, COLLATION, CRC32, DATE_ADD с INTERVAL,
DATE_SUB с INTERVAL, GET_FORMAT, PERIOD_ADD, PERIOD_DIFF, SUBTIME, TIMESTAMP,
TIMESTAMPADD, TIMESTAMPDIFF, MATCH, EXTRACTVALUE, UPDATEXML, GET_LOCK,
IS_FREE_LOCK, MASTER_POS_WAIT, RELEASE_LOCK.
Эмулируемые функции
Проблема: функции с переменным числом параметров
Следующие функции в MySQL имеют переменное число параметров:
GREATEST(значение1, значение2, ...)
LEAST(значение1, значение2, ...)
INTERVAL(N, N1, N2, N3, ...)
CHAR(N, ... [USING имя_набора_символов])
ELT(N, строка1, строка2, строка3, ...)
FIELD(строка, строка1, строка2, строка3, ...)
MAKE_SET(биты, строка1, строка2, ...)
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
107
Решение
Функции с переменным числом параметров можно эмулировать при помощи функции
Transact-SQL CASE. Также можно использовать тип данных XML для передачи данных в функцию
эмуляции, но при этом придется дополнительно преобразовывать данные в формат XML и из него.
Проблема: IF(expr1, expr2, expr3)
Если expr1 равно TRUE (expr1 <> 0 и expr1 <> NULL), то IF() возвращает expr2, а в противном
случае — возвращает expr3.
Пример кода MySQL
if(@a>@b, @a, @b-@a)
Решение
Для эмуляции этой функции используйте функцию Transact-SQL CASE.
Пример кода SQL Server
case when @a > @b then @a else @b - @a end
Проблема: BIN(N)
Возвращает строковое представление двоичного значения N.
Решение
Для эмуляции этой функции в Transact-SQL используйте строковые функции и битовые
операторы.
Проблема: BIT_LENGTH(str)
Возвращает длину строки str в битах.
Решение
Для эмуляции этой функции в Transact-SQL используйте функцию DATALENGTH.
Проблема: CONCAT(строка1, строка2, …) и CONCAT_WS(разделитель, строка1, строка2, ...)
Возвращает строку, возникающую путем объединения аргументов.
Пример кода MySQL
CONCAT('A','B','C'), CONCAT_WS('#','A','B','C')
Решение
Используйте оператор SQL Server плюс (+) для объединения строк.
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
108
Пример кода SQL Server
'A'+'B'+'C',
'A'+'#'+'B'+'#'+'C'
Проблема: CONV(N, from_base, to_base)
Преобразует числа из системы счисления с одним основанием в систему счисления с другим
основанием.
Решение
Для эмуляции этой функции используйте математические функции и битовые операции
Transact-SQL.
Проблема: EXPORT_SET(bits, on, off [, separator [, number_of_bits]])
Возвращает строку, причем для каждого бита, установленного в битах значения,
возвращается строка on, а для каждого сброшенного бита — строка off.
Решение
Для эмуляции этой функции используйте математические функции и битовые операции
Transact-SQL.
Проблема: FIND_IN_SET(str, strlist)
Возвращает значение в диапазоне от 1 до N, если строка str находится в списке строк strlist,
состоящем из N подстрок.
Решение
Для эмуляции этой функции используйте функцию Transact-SQL CHARINDEX.
Проблема: FORMAT(X, D)
Преобразует число X в формат вида '#,###,###.##' с округлением до D десятичных знаков
и возвращает результат в виде строки.
Решение
Для эмуляции этой функции используйте функции Transact-SQL ROUND и CONVERT.
Проблема: HEX(N_or_S)
Если аргумент N_or_S является числом, возвращается строковое представление
шестнадцатеричного значения N, где N — очень длинное число (BIGINT). Если аргумент
N_or_S является строкой, возвращается шестнадцатеричное строковое представление
N_or_S, в котором каждый символ N_or_S представлен в виде двух шестнадцатеричных
цифр. UNHEX(S) выполняет операцию, обратную HEX(S).
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
109
Решение
Для эмуляции функции HEX(N_or_S) используйте строковые функции, функции
преобразования и битовые операции Transact-SQL.
Проблема: INSERT(str, pos, len, newstr)
Возвращает строку str, в которой подстрока, начинающаяся с положения pos и включающая
len символов, заменяется строкой newstr.
Решение
Для эмуляции этой функции используйте функции Transact-SQL REPLACE или SUBSTRING.
Проблема: LOAD_FILE(file_name)
Читает файл и возвращает его содержимое в виде строки. SQL Server не может читать
данные из внешнего файла в переменную.
Решение
Для эмуляции LOAD_FILE(file_name) используйте инструкции массовой загрузки
или расширенную хранимую процедуру.
Проблема: NOW()
Возвращает текущие дату и время.
Пример кода MySQL
NOW()
Решение
Используйте аналогичную функцию Transact-SQL GETDATE.
Пример кода SQL Server
GETDATE()
Проблема: REPEAT(str, count)
Возвращает строку, состояющую из строки str, повторенной count раз.
Пример кода MySQL
REPEAT('A', 10)
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
110
Решение
Используйте аналогичную функцию Transact-SQL REPLICATE.
Пример кода SQL Server
REPLICATE('A', 10)
Проблема: ISNULL(expr)
Если expr равно NULL, ISNULL() возвращает 1, в противном случае возвращает 0.
Пример кода MySQL
ISNULL(@a)
Решение
Для эмуляции этой функции используйте функцию Transact-SQL CASE и предложение IS NULL.
Пример кода SQL Server
CASE WHEN @a IS NULL THEN 1 ELSE 0 END
Проблема: STRCMP(expr1, expr2)
Сравнивает две строки.
Решение
Попробуйте использовать операторы сравнения Transact-SQL для эмуляции STRCMP(expr1, expr2).
Проблема: CONVERT_TZ(dt, from_tz, to_tz)
Преобразует значение даты и времени dt из часового пояса from_tz в часовой пояс to_tz
и возвращает результирующее значение. В SQL Server отсутствуют функции для часовых
поясов.
Решение
Функции для работы с часовыми поясами можно эмулировать в SQL Server с помощью
функции CLR или расширенных хранимых процедур.
Проблема: DATE_FORMAT(date, format)
Форматирует значение даты в соответствии со строкой формата. В Transact-SQL подобной
функции нет.
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
111
Решение
Для эмуляции функции DATE_FORMAT(date, format) можно использовать функции даты,
функции преобразования и строковые функции Transact-SQL.
Проблема: FROM_DAYS(N)
Дается номер дня N; возвращается значение DATE.
Решение
Для эмуляции функции FROM_DAYS(N) используйте функцию Transact-SQL CONVERT.
Проблема: MAKEDATE(year, dayofyear)
Возвращает значение даты указанного года (year) и дня в году (dayofyear).
Решение
Для эмуляции этой функции используйте функцию Transact-SQL DATEADD.
Проблема: SEC_TO_TIME(seconds)
Возвращает аргумент seconds, преобразованный в часы, минуты и секунды.
Решение
Для эмуляции этой функции используйте арифметические операторы и функции
преобразования Transact-SQL.
Проблема: TIME_TO_SEC(time)
Возвращает аргумент time, преобразованный в секунды.
Решение
Для эмуляции этой функции используйте арифметические операторы и строковые функции
Transact-SQL.
Проблема: TO_DAYS(date)
Дается дата date; возвращается номер дня (номер дня, начиная с года 0).
Решение
Для эмуляции этой функции используйте функцию Transact-SQL CONVERT.
Проблема: BIT_COUNT(N)
Возвращает число битов, установленных в аргументе N.
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
112
Решение
Для эмуляции функции MySQL BIT_COUNT(N) в Transact-SQL используйте строковые
функции и битовые операторы.
Проблема: функции шифрования и сжатия
AES_ENCRYT. AES_DECRYPT. COMPRESS. UNCOMPRESS. ENCODE. DECODE.
DES_ENCRYPT. DES_DECRYPT. ENCRYPT. MD5. OLD_PASSWORD. PASSWORD. SHA.
SHA1. UNCOMPRESSED_LENGTH.
Решение
Для эмуляции этих функций используйте функции безопасности и криптографические
функции SQL Server.
Проблема: LAST_INSERT_ID()
Возвращает первое автоматически созданное значение, которое было задано для столбца
AUTO_INCREMENT самой последней инструкцией INSERT или UPDATE для изменения
столбца.
Решение
Для эмуляции LAST_INSERT_ID() используйте функцию Transact-SQL @@IDENTITY
или SCOPE_IDENTITY.
Проблема: DEFAULT(column)
Возвращает значение по умолчанию для столбца таблицы.
Решение
Для эмуляции DEFAULT(column) используйте данные системного представления.
Проблема: INET_ATON(expr)
Дается сетевой адрес, представленный четверкой чисел, разделенных точками, в виде строки;
возвращается целое число, представляющее числовое значение адреса. INET_NTOA(expr).
Дается числовой адрес (4 или 8 байт); возвращается строка, содержащая представление
адреса в формате четырех чисел, разделенных запятыми.
Решение
Для эмуляции этих функций используйте арифметические операторы и строковые функции
Transact-SQL.
Проблема: GROUP_CONCAT(expr)
Эта функция возвращает строковый результат со сцепленными ненулевыми значениями
из группы.
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Руководство по переходу с MySQL на SQL Server 2005
113
Решение
Эту функцию можно эмулировать с использованием кода Transact-SQL, показанного
в следующем примере:
declare @v varchar(max)
set @v=''
select @v=@v+','+isnull(field_a,'') from table_1
select substring(@v,2,len(@v))
Проблема: INSTR(str, substr), POSITION(substr IN str)
Возвращает положение первого вхождения подстроки substr в строку str. LOCATE(substr, str [, pos]).
Возвращает положение первого вхождения подстроки substr в строку str, начиная с положения pos.
Решение
Для эмуляции этой функциональности используйте функцию CHARINDEX.
Заключение
Из этого руководства по миграции вы узнали о различиях между платформами баз данных
MySQL и SQL Server 2005 и действиях, необходимых для преобразования базы данных
MySQL в SQL Server.
Дополнительные сведения

Веб-сайт SQL Server

Технический центр SQL Server

Центр разработчиков SQL Server
Насколько полезным оказался для вас этот документ? Сообщите нам свое мнение. Как бы вы
оценили документ по шкале от 1 балла (очень плохой) до 5 (отличный)? Почему вы поставили
такую оценку? Например так, как показано на рисунке.

Вы поставили высокую оценку, потому что документ содержит отличные примеры
и иллюстрации, написан хорошим языком или по иной причине?

Вы поставили низкую оценку, потому что документ содержит плохие примеры, неудачные
иллюстрации или непонятно написан?
Ваш отзыв поможет нам улучшить качество выпускаемых информационных документов.
Отправить отзыв.
© Корпорация Майкрософт (Microsoft Corporation), 2008.
Download