Guide to Migrating from Microsoft Access to SQL Server 2005 SQL Server Technical Article Writers: Yuri Rusakov, Alexey Kovaliov, Eduard Kolosov Technical Reviewer: Darmadi Komo, Irena Balin Published: December 2007 Applies To: SQL Server 2005 Summary: This white paper covers migrating Microsoft Access databases to SQL Server 2005 and discusses the differences between the two platforms. SQL Server Migration Assistant for Access (SSMA Access) is the best tool for this type of migration; this paper tells you how to use it to mitigate potential problems in database conversion. Copyright The information contained in this document represents the current view of Microsoft Corporation on the issues discussed as of the date of publication. Because Microsoft must respond to changing market conditions, it should not be interpreted to be a commitment on the part of Microsoft, and Microsoft cannot guarantee the accuracy of any information presented after the date of publication. This White Paper is for informational purposes only. MICROSOFT MAKES NO WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, AS TO THE INFORMATION IN THIS DOCUMENT. Complying with all applicable copyright laws is the responsibility of the user. Without limiting the rights under copyright, no part of this document may be reproduced, stored in or introduced into a retrieval system, or transmitted in any form or by any means (electronic, mechanical, photocopying, recording, or otherwise), or for any purpose, without the express written permission of Microsoft Corporation. Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual property rights covering subject matter in this document. Except as expressly provided in any written license agreement from Microsoft, the furnishing of this document does not give you any license to these patents, trademarks, copyrights, or other intellectual property. 2007 Microsoft Corporation. All rights reserved. Microsoft, SQL Server, Visual Basic, Visual C#, Visual Studio, and Windows are either registered trademarks or trademarks of Microsoft Corporation in the United States and/or other countries. The names of actual companies and products mentioned herein may be the trademarks of their respective owners. Guide to Migrating from Microsoft Access to SQL Server 2005 Table of Contents Introduction ......................................................................................................1 Overview of Access to SQL Server 2005 Migration ............................................1 Microsoft Access Limitations ............................................................................. 2 Reasons for Migrating Access Databases to SQL Server 2005 ................................ 2 Migration Scenarios ......................................................................................... 3 Creating a Two-Tier Application.................................................................... 3 Creating a Client/Server Application ............................................................. 3 Rewriting the Access Application .................................................................. 4 Access Version Compatibility ............................................................................ 5 Migration Wizard ...............................................................................................5 Migrating Database Objects ............................................................................11 Schema Mapping ........................................................................................... 11 Type Mapping ............................................................................................... 13 Converting Schema Properties ........................................................................ 15 Default ................................................................................................... 15 Nullability ................................................................................................ 15 Allow Zero Length .................................................................................... 15 Converting Constraints .................................................................................. 15 Check Constraints .................................................................................... 16 Primary Keys ........................................................................................... 16 Foreign Keys ........................................................................................... 16 Migrating Indexes ......................................................................................... 16 Converting Expressions .................................................................................. 16 Handling Timestamps ............................................................................... 19 Naming ................................................................................................... 19 Table Migration Potential Problems.................................................................19 Access Table Does Not Have Unique Index or Primary Key ................................. 19 Access Table Unique Index Contains Multiple Null Values .................................... 20 Primary Key Includes Columns That Allow Null Values ........................................ 20 Access Table Contains Dates Out of SQL Server Range ...................................... 21 Access Table Contains Boolean Fields With Null Values ....................................... 21 Access Objects Have the Same Names as SQL Server Keywords ........................ 21 Access Objects Names Include Special Characters ............................................. 22 Hyperlink Column Jump Functionality Is Lost After Upsizing ................................ 22 Memo Column Is Indexed in Access ................................................................. 22 Jet Syntax Potential Problems.........................................................................23 SELECT Statement ........................................................................................ 23 Distinctrow Keyword ................................................................................. 23 -3- Select Into Another Database .................................................................... 23 Incompatible Use of Alias .......................................................................... 24 Logical Expressions in a Select Statement ................................................... 24 TOP N Clause ........................................................................................... 24 Multiple Dot Syntax .................................................................................. 25 Common Syntax Constructs ........................................................................... 25 Expressions ............................................................................................. 25 '&' as Concatenation Operator .................................................................... 25 '\' Operator (Integer Division) .................................................................... 25 'Mod' Operator (Modulus Division) .............................................................. 26 '^' Operator (Raise to Power) .................................................................... 26 'Eqv' and 'Imp' ......................................................................................... 26 Date Literals Declaration ........................................................................... 27 Like Operator .......................................................................................... 27 Join to View Converting Issues ........................................................................ 28 Transform…Pivot Statement ........................................................................... 28 Functions ........................................................................................................30 String Functions ............................................................................................ 30 Advanced Functions ....................................................................................... 36 Domain Aggregate Functions .......................................................................... 38 Numeric/Mathematical Functions ..................................................................... 39 Date Functions .............................................................................................. 42 Data Type Conversion Functions ..................................................................... 48 Aggregate Functions ...................................................................................... 48 Data Migration ................................................................................................51 Data Transfer Source ..................................................................................... 51 Data Transformation ...................................................................................... 51 Technology Used for the Data Migration ........................................................... 51 Transaction Boundaries .................................................................................. 51 Conclusion.......................................................................................................52 Guide to Migrating from Microsoft Access to SQL Server 2005 1 Introduction If you are considering migrating from Microsoft® Access to Microsoft SQL Server® 2005, take into account the differences between the two platforms. This white paper lists the known migration issues and describes using Microsoft SQL Server Migration Assistant for Access (SSMA Access) as the tool for migration. This white paper has the following sections: Overview of Access to SQL Server 2005 Migration. Outlines the reasons why a Microsoft Access user would want to migrate to SQL Server 2005, as well as the ways to approach this task. SSMA Access is useful in scenarios in which the Access front end will not change, but the back-end data will be moved to overcome Access limitations and to ensure better robustness and security. The section also contains suggestions for other migration scenarios. The Migration Wizard. Describes how to use the SSMA Access Migration Wizard—the easiest way to perform a migration. Migrating Database Objects. Examines how to convert objects of the Jet database engine to SQL Server 2005. (Jet is the Access database engine.) An SSMA Access user can control the way Access data types are mapped to SQL Server 2005 and how constraints, indexes, and foreign keys are transferred. As SQL expression syntax is different in SQL Server 2005 and Access, the replacements SSMA Access makes during the migration are described. Table Migration Issues. Explains solutions for various problems that can arise when converting Jet tables. For example, the linked table in Access must have a unique column; if it is missing, SSMA Access can create the required column automatically. Or, some Access columns might have names that are reserved in SQL Server 2005, which can create problems after the migration. SSMA Access provides a warning so that you know which columns are candidates for renaming. Jet Syntax Issues. Describes differences between the syntax of SELECT queries in Access and in SQL Server 2005. In most cases, SSMA Access can handle the differences automatically. For example, Access uses & as a string concatenation operator, while SQL Server 2005 uses +. SSMA Access makes all necessary replacements when converting the query. In those rare cases when you should make manual updates, this section explains how. Functions. Describes the functions implemented in the Jet database engine, and how they correspond to SQL Server 2005 functions. Data Migration. Offers an overview of the SSMA Access data migration process. Overview of Access to SQL Server 2005 Migration Microsoft Access is a database intended for small projects with few users. It is a good tool for developing business applications, because it is inexpensive and easy to use. Still, you may encounter problems when Access limitations prevent you from scaling the application when your database grows large and more users need to work with it. At that stage, you can choose the more robust and secure database solutions of SQL Server 2005. While the Access Jet database engine is continually updated with many quality functional and performance improvements, it is still a file-based, desktop-class data store. The Jet engine is not intended or architected to support more demanding business application requirements. (For a detailed comparison of Access and SQL 1 Guide to Migrating from Microsoft Access to SQL Server 2005 2 Server 2005, see Microsoft Access or SQL Server 2005: What's Right in Your Organization?) Microsoft Access Limitations Access has several inherent technical limitations. Problems (slow performance, corrupt database, application crashes) may occur if an Access application goes into the Caution or Stop zones for any one of the reasons listed in the following table. Okay Caution Stop LAN users <5 5–10 > 10 Internet users 0 1 >1 Frequency of use 1 x day 2 x day > 2 x day User permissions Read only Read/write Read/write Database size < 100 MB 100–300 MB > 300 MB Data structures Simple Moderate Complex Database schema design Good design Poor design Ad hoc Reasons for Migrating Access Databases to SQL Server 2005 Following are the main reasons for moving peripheral Access databases to a SQL Server 2005 environment: Allow multiuser access to a database. Access databases is popular among users, but can handle only a few users at a suitable performance level. When more users use the application, the Access database does not scale well. SQL Server 2005, in contrast, can handle thousands of users, making it ideal for multiuser environments. Redesign and rewrite to fewer and better applications. People outside your organization's professional IT department may have developed your Access applications. They may not have developed the code and database according to development standards, and they may have lacked sufficient knowledge or time. In these situations, the entire organization can benefit from standardizing and unifying applications and data by centralizing common processes. Interchange data with the external world. SQL Server 2005 offers better tools to communicate with other environments such as Oracle, IBM DB2, and SAP. Through the Data Transformation Services/Integration Services (DTS/SSIS) packages, you can automate data interchange with those environments or integrate them into existing applications. Better analyze and solve performance problems. Compared to Access, SQL Server 2005 gives you stronger tools, such as SQL Profiler, execution plans in Query Analyzer, the Index Tuning Wizard, and filegroups to spread data across disks. SQL Server 2005 also has a better locking mechanism built specifically for a multiuser environment. Benefit from SQL Server 2005 database security improvements. There are many benefits to using both SQL Server and Windows authentication to manage users and access to multiple databases, database roles, and for the many ways to grant permissions to the data they provide. 2 Guide to Migrating from Microsoft Access to SQL Server 2005 3 Migration Scenarios Migrating an Access database to SQL Server 2005 moves some or all data and data definitions to the server. After the data is safely transferred to SQL Server 2005, you must decide how to interact with the server-based data. The options discussed in this section suggest possible solutions. Creating a Two-Tier Application You can link server-based tables to local tables in Access and use the other existing database objects (queries, forms, reports, modules, and macros) as before. This creates a two-tier application, in which the server running SQL Server 2005 stores data, and copies of the interface are stored in Access on the users' computers. Queries run on the client tier. Locally stored forms, reports, modules, and macros provide the remaining elements of the user interface. The design of server-based tables cannot be modified from within Access. The advantage of this approach The main advantage of this approach is its low transition cost because front-end database objects do not require modifications. Users continue to interact with a familiar interface, while SQL Server 2005 provides centralized data storage, back up and recovery, a multiuser environment, an integrated security model, and other advantages. After the data is in SQL Server 2005, you can begin rewriting portions of the application by using a more robust environment such as Microsoft Visual Studio® .NET and SQL Server 2005 Reporting Services. Moving an Access application towards a more scalable and robust platform is referred to as upsizing. When the migration is complete, all data is stored on the database server, and Access continues to operate smoothly as the desktop application. The disadvantages of this approach The disadvantages are that queries are still processed locally, and a large amount of network traffic is generated. Implementation You can implement this configuration by using either the Access Upsizing Wizard or SSMA Access, but SSMA Access has more advanced functionality, including: Multiple database upsizing Schema and type mapping A Find Database wizard Query conversion User-friendly interface Improved data migration mechanism Advanced reporting More bug fixes Creating a Client/Server Application Microsoft Access introduced Microsoft Access Data Project, a new type of Access file (.adp) designed as a client/server application. Communication between the client and the server takes place through an OLE DB component architecture, which was specifically designed for efficient client/server communication. All tables and data definition objects such as views, stored procedures, and database diagrams are stored on the server. The client stores only code-based or HTML-based objects such 3 Guide to Migrating from Microsoft Access to SQL Server 2005 4 as forms, reports, modules, and macros. Most data processing takes place on the server, and only filtered data is sent to the client, thus minimizing network traffic. The advantage of this approach It results in an Access application that provides the best performance and scalability, as well as the other positive attributes of SQL Server 2005. The disadvantage of this approach It requires more development effort because Access objects such as forms, reports, queries, and code must be redesigned to work directly with SQL Server 2005. In addition, the Data Project feature may be removed in later Microsoft Access versions. Implementation This configuration is supported only by the Upsizing Wizard that is supplied as a part of Microsoft Access. Rewriting the Access Application In a small percentage of Access upsizing projects, the only possible is to migrate from Access. Perhaps your existing Access application has outgrown Access, and the program cannot meet your organization's scalability, reliability, and performance requirements. Or, you want to migrate all or part of the application to the World Wide Web. In this scenario, you use your Access application as the start of a new design. You use additional technologies such as Visual Basic® (VB), Active Server Pages (ASP), and Visual Studio .NET to rewrite the Access application. As part of the process, the data moves to SQL Server 2005. Additionally, you can migrate other data sources, such as Oracle and IBM DB2 into SQL Server 2005 for a centrally managed solution. The advantage of this approach The major advantage is the flexibility inherent in this approach. You create an application that can target computers running Windows and the Web with minimum changes. A more professional development environment, such as Visual Studio .NET, offers advantages such as team-based management, source code control, and thirdparty tools and components. In this scenario, you have a reliable, scalable, and manageable application that can move from the business unit to the enterprise level. The disadvantage of this approach The disadvantage of this approach is cost. Because you are discarding the Access application and its database, you are creating a new application with a new design, development, and implementation project. (Third-party products can help cut the cost of front-end conversion. Consider using Access ConverterTM from Microtools.) Implementation Following is an example migration sequence: 1. Migrate the Access back-end schema and data. Use either SSMA Access or the Upsizing Wizard (SSMA Access is preferable). 2. Migrate the Access forms to ASP.NET WebForms. Preserve the look and feel and the operation of the original Access forms. All Access built-in features, such as auto lookup, implicit updates, shortcuts, and tool tips can be emulated by using advanced WebForms capabilities. 3. Convert Access queries to stored procedures. SSMA Access can help convert SELECT queries. 4 Guide to Migrating from Microsoft Access to SQL Server 2005 5 4. The generated VB.NET code performs all database interactions and form navigation. If necessary, convert that code to Visual C#®.NET with any number of low-cost VB to C#.NET conversion tools. 5. Manually convert Microsoft Access VBA code to VB.NET or C#.NET. The time required to migrate Visual Basic for Applications (VBA) code depends on the volume and techniques employed. For example, applications that depend heavily on the DAO (Data Access Objects) interface to perform database operations take longer to convert than those that use built-in Access features. Access Version Compatibility Note that SSMA Access supports databases used in Access 97 and later. If you have databases from an earlier version of Access, you must convert them to a newer version. To convert, open and save the databases in Access 97 or a later version before you add them to SSMA Access. Migration Wizard If you lack SSMA Access experience and need to migrate a single database, the SSM Access Migration Wizard is the best choice for an easy and quick migration. You can configure the Migration Wizard to run every time SSMA Access starts. The first screen of the Wizard is shown in Figure 1. Figure 1: The first screen of the Migration Wizard To use the SSM Acess Migration Wizard to migrate databases 1. Step 1 of the wizard (see Figure 2), prompts for a name and location for your new SSMA Access project. You can confirm the default values or enter your own. 5 Guide to Migrating from Microsoft Access to SQL Server 2005 6 Figure 2: Create a new project 2. Next, add databases to the project, as shown in Figure 3. Figure 3: Add Access databases to the project You can locate databases manually and add them to the list of databases to migrate, or use the Find Database Wizard, shown in Figure 4, which makes database selection easier. 6 Guide to Migrating from Microsoft Access to SQL Server 2005 7 Figure 4: Use the Find Databases Wizard for easier selection 3. Select the objects to migrate. Figure 5 shows the meta-base tree from which you select objects to migrate. Figure 5: Select objects for migration 4. Create a connection to SQL Server 2005, as shown in Figure 6. (If you lack the information to create a connection to SQL Server 2005, contact your database administrator.) 7 Guide to Migrating from Microsoft Access to SQL Server 2005 8 Figure 6: Connect to SQL Server 2005 5. You can migrate an Access database to an existing database as well as to a new one. If the database you entered doesn't exist on the server running SQL Server, SSMA Access prompts you to create it, as shown in Figure 7. Figure 7: Prompt to create the specified database 6. The screen shown in Figure 8 asks whether to link tables. If you want access to data stored on the SQL Server 2005 side, you need a link to SQL Server 2005 tables instead of to your Access objects. The operation changes the Access database, but SSMA Access lets you link and unlink tables at any time. 8 Guide to Migrating from Microsoft Access to SQL Server 2005 9 Figure 8: The Migration Wizard asks whether to link tables 7. You can see the progress of the migration in the Migration Status window, shown in Figure 9. Figure 9: Check the migration progress Figure 9 also shows the same steps you would follow to convert manually. The Migration Wizard groups these actions into a single process that makes migration easier and less error prone. To check for errors during migration 1. SSMA Access converts database objects. Check the Assessment report, shown in Figure 10, which reports all conversion problems. For different views, change the window to display errors, warnings, or information messages. 9 Guide to Migrating from Microsoft Access to SQL Server 2005 10 Figure 10: Check the Assessment report to view any problems 2. Load objects into the SQL database. 3. Migrate the data. This generates the Data Migration report (Figure 11), which shows statistics about each migrated table. Figure 11: The Data Migration report shows statistics on each migrated tables 4. Link SQL tables to the Access application. Each step contains hyperlinks to show errors, warning, and information messages. You can filter the message list by using buttons on the top of the window, as shown in Figure 12. 10 Guide to Migrating from Microsoft Access to SQL Server 2005 11 Figure 12: The Error List You can continue working with project after the Migration Wizard finishes. Keep in the mind that the Migration Wizard creates a new project each time you launch it. Migrating Database Objects This section looks at how to migrate Jet database objects by means of SSMA Access. Setting the proper schema and type mapping is described first. After that, SSMA Access conversion of constraints, indexes, and expressions is covered. Schema Mapping Your first migration step is to decide on the physical structure of the target SQL Server 2005 database. In the simplest case, you can map the Access database to a SQL Server 2005 database. SSMA Access applies the selected schema-mapping method consistently when converting database objects and references to them. You can change schema mapping by using the Schema mapping tab for the database on the right of the source schema tree. Click the Modify button to change the default mapping. Figure 13: Choosing the target schema 11 Guide to Migrating from Microsoft Access to SQL Server 2005 12 After you choose your optimal schema mapping, you can start creating the target SQL Server 2005 database and its required schemas. The typical SSMA Access migration includes connecting to the source Access database and the target SQL Server 2005, then running the Convert Schema command. When the target objects are created in the SSMA Access workspace, you can save them by using the Load to Database command. Next, execute the Migrate Data command, which transfers the data from the source to the target tables, making the necessary conversions. (The data migration process is executed on the SQL Server 2005 computer.) Finally, run the Link Tables command to link migrated tables to the Access application. Each Access table is converted to a SQL Server 2005 table. All indexes and constraints defined for each table are also converted. When determining the target table's structure, SSMA Access uses type-mapping definitions. 12 Guide to Migrating from Microsoft Access to SQL Server 2005 13 Type Mapping The following table shows the default type mapping for migrating from Jet 4.0 (Access 2000 and later) to SQL Server 2005. Size in bytes (Jet 4.0) Size * 2 Jet 4.0 SQL Server 2005 Possible Custom Mapping TEXT(size) nvarchar(size) Char(size), Varchar(size), NChar(size), NVarchar(size), Varchar(max), Nvarchar(max) 1073741823 MEMO nvarchar(max) Char(size), Varchar(size), NChar(size), NVarchar(size), Varchar(max), Nvarchar(max) 1 BYTE tinyint tinyint, smallint, int, bigint, numeric(p,s), decimal(p,s), float(p), double precision, real, smallmoney, money 2 INTEGER smallint smallint, int, bigint, numeric(p,s), decimal(p,s), float(p), double precision, real, smallmoney, money 4 LONG INTEGER integer smallint, int, bigint, numeric(p,s), decimal(p,s), float(p), double precision, real, smallmoney, money 4 SINGLE Real numeric(p,s), decimal(p,s), float(p), double precision, real, smallmoney, money 8 DOUBLE float numeric(p,s), decimal(p,s), float(p), double precision, real, smallmoney, money 9 DECIMAL float tinyint, smallint, int, bigint, numeric(p,s), decimal(p,s), float(p), double precision, real, smallmoney, money 16 GUID uniqueidentifier 8 DATE datetime smalldatetime, datetime 8 CURRENCY Money numeric(p,s), decimal(p,s), float(p), double precision, real, smallmoney, money 2 YESNO tinyint tinyint, smallint, int, bigint 2147483647 LONGBINARY varbinary(max) image, binary, varbinary, varbinary(max) BINARY(size) varbinary(size) image, binary, varbinary, varbinary(max) Size 13 Guide to Migrating from Microsoft Access to SQL Server 2005 14 The next table shows the default type mapping for migrating from Jet 3.5 (Access 97 and previous versions) to SQL Server 2005. Size in bytes (Jet 3.5) size Jet 3.5 SQL Server 2005 Possible Custom Mapping TEXT(size) varchar(size) Char(size), Varchar(size), NChar(size), NVarchar(size), Varchar(max), Nvarchar(max) 1073741823 MEMO varchar(max) Char(size), Varchar(size), NChar(size), NVarchar(size), Varchar(max), Nvarchar(max) 1 BYTE tinyint tinyint, smallint, int, bigint, numeric(p,s), decimal(p,s), float(p), double precision, real, smallmoney, money 2 INTEGER smallint smallint, int, bigint, numeric(p,s), decimal(p,s), float(p), double precision, real, smallmoney, money 4 LONG INTEGER integer smallint, int, bigint, numeric(p,s), decimal(p,s), float(p), double precision, real, smallmoney, money 4 SINGLE real numeric(p,s), decimal(p,s), float(p), double precision, real, smallmoney, money 8 DOUBLE float numeric(p,s), decimal(p,s), float(p), double precision, real, smallmoney, money 16 GUID uniqueidentifier 8 DATE datetime smalldatetime, datetime 8 CURRENCY money numeric(p,s), decimal(p,s), float(p), double precision, real, smallmoney, money 2 YESNO tinyint tinyint, smallint, int, bigint 2147483647 LONGBINARY varbinary(max) image, binary, varbinary, varbinary(max) BINARY(size) varbinary(size) image, binary, varbinary, varbinary(max) Size Type mapping can be defined for all databases and for each table separately by using the Type mapping tab on the right of the source schema tree. To do this, click the Edit button for the particular source type, as shown in Figure 14). 14 Guide to Migrating from Microsoft Access to SQL Server 2005 15 Figure 14: Choosing the source type Note Access and SQL Server 2005 have different default data types for decimal without parameters. You must map the Access decimal data type to SQL decimal(18, 2) (not just decimal) on the Type mapping tab. Converting Schema Properties This section has suggestions for converting a number of column attributes. Default Jet default expressions on columns are mapped to SQL Server 2005 default expressions on columns. Nullability The Jet nullability column property is mapped directly to SQL Server 2005 NULL column property. Allow Zero Length If the Allow zero length column property is set to false on text/memo columns in Jet, it is mapped to a check constraint with a constraint name "c_ssma_disallow_zero_length" on the varchar/nvarchar columns in SQL Server 2005. For example, the following code shows how to convert the Allow zero length column property on column c1 in table table1: Create table table1(c1 nvarchar(10), c_ssma_disallow_zero_length constraint check(len(c1) >0)) Converting Constraints This section describes how to convert the constraints of an Access table. 15 Guide to Migrating from Microsoft Access to SQL Server 2005 16 Check Constraints Check constraints (column-level or table-level) are expressions that should be parsed and converted to SQL. (For details see Converting Expressions.) Primary Keys Jet primary keys are mapped directly to SQL Server 2005 primary keys. Foreign Keys Jet foreign keys are mapped directly to SQL Server 2005 foreign keys. Exception: SQL Server 2005 does not allow the Jet functionality of linking text and memo columns with different size via a foreign key constraint. To overcome that, SSMA Access schema type mapping is changed to enable the creation of the foreign key constraint on the SQL Server 2005 side. Both columns participating in the foreign key constraint are mapped to the same SQL Server 2005 type according to the bigger Jet type. Migrating Indexes Jet indexes are mapped directly to SQL Server 2005 indexes. Exceptions: In cases where the MEMO column is indexed on the Jet side, the index is not created on the SQL Server 2005 side since SQL Server 2005 does not support indexing nvarchar (max) or varchar (max). Tables that do not have a unique index and that do not have a primary key are upsized, but an identity column is added to create a unique index. Converting Expressions To convert expressions, apply these rules in sequence: 1. Remove any leading = character in a Jet expression. For example: Create table foo(x1 int default =5) in Jet is converted to Create table foo(x1 int 5) for SQL Server 2005. 2. Replace a double quote (") with a single quote ('). For example: "abc" in Jet is converted to 'abc' for SQL Server 2005. 3. Double any embedded single quotes. For example: "a'a" in Jet is converted to 'a"'c' for SQL Server 2005. The quote in the middle of "a'a" is doubled to create 'a"c'. 4. Replace # around dates with single quotes. For example #1/6/2006# in Jet is converted to '1/6/2006' for SQL Server 2005. 16 Guide to Migrating from Microsoft Access to SQL Server 2005 17 5. Replace the function tokens found inside the expression according to the following table. Jet function token Replace with SQL Server 2005 function token Yes -1 On -1 True -1 No 0 Off 0 False 0 Mod % Sgn( Sign( chr( Char( Chr$( Char( Asc( ascii( str$( str( int( floor( Cint( convert(smallint, Clng( convert(int, csng( convert(real, cdbl( convert(float, Cstr( convert(varchar, ccur( convert(money, cvdate( convert(datetime, space$( space( lcase( lower( lcase$( lower( ucase( upper( ucase$( upper( len( datalength( Ltrim$( Ltrim( Rtrim$( Rtrim( Right$( Right( Mid( substring( Mid$( substring( Now() getdate() 17 Guide to Migrating from Microsoft Access to SQL Server 2005 18 Jet function token Replace with SQL Server 2005 function token Date() convert(datetime,convert(varchar,getdate(),1)) year( datepart(yy, month( datepart(mm, Day( datepart(dd, weekday( datepart(dw, Hour( datepart(hh, minute( datepart(mi, second( datepart(ss, time() convert(datetime, convert(varchar,getdate(),14)) 6. Use the next table to replace the format tokens inside datepart(),dateadd() datediff() functions. Jet strings format part of datepart(),dateadd() datediff() functions Replace with SQL Server 2005 format "yyyy" Yy "q" Qq "m" Mm "y" Dy "d" Dd "w" Dw "ww" Wk "h" Hh "n" Mi "s" Ss "yy" Yy "qq" Qq "mm" Mm "dy" Dy "dd" Dd "dw" Dw "wk" Wk "hh" Hh "mi" Mi "ss" Ss 18 Guide to Migrating from Microsoft Access to SQL Server 2005 19 Handling Timestamps After you upsize the performance of record editing, performance may degrade for some column types. This is because Access must check whether each column was changed before committing the changed data. To fix this, add a timestamp column by using SSMA. You can control this addition in Project Settings, as shown in Figure 15. Figure 15: Adjust timestamp handling in Project Settings Naming SQL Server 2005 supports spaces and nonalphanumeric characters in object names, as long they are surrounded by square brackets in DDL statements. Table Migration Potential Problems This section covers typical situations in which migration problems can arise. It includes SSMA Access handling or user solutions. Access Table Does Not Have Unique Index or Primary Key If a table without a unique index is upsized, it will be uneditable after the upsizing. If the table does not have a primary key or unique index, the destination script displays the following message: "Table <table name> does not have a primary key or unique index and therefore cannot be edited from within Access." If the table does not have an auto number index, SSMA Access can automatically create a new column called ssma_rowid and create a primary key on that column. You will see the following warnings in the destination code: "A new identity column 'SSMA_RowID' was created for the primary key." "Primary key 'SSMA_PK$Table1' was created for the identity column." You can enable or disable the automatic generation of a primary key column in Project Settings, as shown in Figure 16. 19 Guide to Migrating from Microsoft Access to SQL Server 2005 20 Figure 16: Create a primary key in Project Settings Access Table Unique Index Contains Multiple Null Values Data containing multiple null values in an Access table column that has a unique index cannot be transferred to SQL Server 2005. This is because a SQL Server 2005 unique index does not allow multiple nulls. During data migration you will receive the following error message: "Cannot insert duplicate key row in object <table name> with unique index <index name>." Primary Key Includes Columns That Allow Null Values In Access, a primary key can include columns with the Required field set to false. This is not allowed in SQL Server 2005. By default, SSMA Access produces the following warning: "Column <column name> of the primary key is nullable, which SQL Server 2005 does not allow. The nullable flag was removed from the target column to avoid problems during loading database objects into SQL Server 2005. If there are rows that contain NULL values, you might encounter problems during data migration." Control SSMA behavior in this situation with Project Settings, as shown in Figure 17. 20 Guide to Migrating from Microsoft Access to SQL Server 2005 21 Figure 17: Warn when the primary key includes nullable columns Your choices are: Warning: (Set by default.) All columns with a NOT NULL attribute will form the primary key. Error: SSMA Access generates an error and does not convert the table. No message: Tables are converted as is, ignoring possible application problems. Access Table Contains Dates Out of SQL Server Range The SQL Server 2005 datetime type accepts dates only in the range of 1 Jan 1753 to 31 Dec 9999. Access, in contrast, accepts dates in the range of 1 Jan 100 to 31 Dec 9999. This can cause data transfer to fail. SSMA Access changes an incorrect value to nearest date limit. For example, SSMA Access migrates 1/01/1700 as 1/01/1753. Access Table Contains Boolean Fields With Null Values After linking a table that has Boolean fields containing nulls, the table cannot be edited in Access. SSMA Access displays the following warning: "The bit column 'Checked' has no default value. To avoid problems with null values in Access applications, the default value '0' was added to target column" Access Objects Have the Same Names as SQL Server Keywords SQL Server 2005 can accept objects (such as tables, columns, indexes, schemas) that have the same names as SQL Server 2005 keywords—if you surround the object names with quotation marks in the DDL statement. All queries that reference these objects must include the quotation marks around names as well. Therefore, Access queries that use names without quotation marks can fail. 21 Guide to Migrating from Microsoft Access to SQL Server 2005 22 SSMA Access tries to avoid the problem by adding square brackets and displaying the warning message: "Column <column name> has a name that might cause problems for the Access application to function correctly against SQL Server 2005." Access Objects Names Include Special Characters SQL Server 2005 can accept object (for example, tables, columns, indexes, schemas) names that include special characters (space, &, +, *) if you surround the names with quotation marks in the DDL statement. All queries that reference these objects must include the quotation marks around names as well. That means that it is possible that Access queries that do not have the quotation marks will fail. SSMA Access tries to avoid the problem by adding square brackets and displaying the warning message: "Column <column name> has a name that might cause problems for the Access application to function correctly against SQL Server 2005." Hyperlink Column Jump Functionality Is Lost After Upsizing After upsizing, Jet hyperlink columns are treated the same as regular memo columns and loose their jump functionality. This is because the hyperlink is a Jet column flag that is read from SQL Server 2005 after the upsizing. Since SQL does not have that flag, the information is lost. In this situation SSMA Access displays the following warning: "The hyperlink column <column name> was converted to a text column and, as a result, is no longer a link." Memo Column Is Indexed in Access Access supports indexing the memo column, but SQL Server 2005 does not support indexing nvarchar(max). If you use the default type mapping, SSMA Access displays the following warning: "Index <column name> is on a memo column and cannot be created on SQL Server 2005 with the current type mapping settings." Figure 18 shows how to control this situation in Project Settings (similar to the way you handle primary keys with nulls). 22 Guide to Migrating from Microsoft Access to SQL Server 2005 23 Figure 18: Options for handling index memo columns Jet Syntax Potential Problems The current version of SSMA Access can convert only SELECT statements into Transact-SQL views. INSERT, UPDATE, and DELETE query conversion is not implemented. This section describes the syntax difference between the two platforms. If SSMA Access can handle an issue, it is marked with "SSMA Access support = Yes" in the statement descriptions in this section and the solution is explained. If SSMA Access cannot make the automatic conversion, the solution for manual handling is included. SELECT Statement This section describes how some incompatible clauses of the SELECT statement can be handled during the migration. Distinctrow Keyword Issue: Jet SQL can use the Distinctrow keyword, but Transact-SQL doesn't have such a keyword. SSMA Access support:Yes Solution:Emulate with a subquery. Example: Jet SELECT Distinctrow <FieldsList> FROM Table SQL Server 2005 SELECT <FieldsList> FROM (SELECT distinct * FROM Table) Table Select Into Another Database Issue: Jet SQL syntax is different from Transact-SQL. SSMA Access support: No 23 Guide to Migrating from Microsoft Access to SQL Server 2005 24 Solution: Modify syntax so that it is more like Transact-SQL. Example: Jet SELECT Suppliers.* INTO Suppliers IN 'Backup.mdb' FROM Suppliers; SQL Server 2005 SELECT Suppliers.* INTO BackupDB..Suppliers FROM Suppliers; Incompatible Use of Alias Issue: Jet SQL allows the use of an alias in the same statement in which it is defined. SSMA Access support: No Solution: Use the full expression instead of an alias. Example: Jet SELECT (Price * discount) AS saving, (Price – saving) AS NewPrice FROM Products SQL Server 2005 SELECT (Price * discount) AS saving, (Price – Price * discount) AS NewPrice FROM Products Logical Expressions in a Select Statement Issue: Jet SQL interprets two expressions with = between them in the SELECT statement as Boolean expressions. SSMA Access support: Yes Solution: Use a CASE statement to emulate similar behavior. Keep in the mind that the Boolean type in the Access has the numeric value -1. Example 1: Jet SELECT Sum(discount = 0.8) FROM Products SQL Server 2005 SELECT Sum(Case discount when 0.8 then -1 Else 0) FROM Products Example 2: Jet SELECT Sum(<logical expression>) FROM Products SQL Server 2005 SELECT Sum(CASE when <logical expression> then -1 ELSE 0) FROM Products TOP N Clause Issue: Jet SQL calls the TOP operator using WITH TIES by default. SSMA Access support: Yes Solution: Add WITH TIES to the Transact-SQL statement. Example: 24 Guide to Migrating from Microsoft Access to SQL Server 2005 25 Jet SELECT top 3 * FROM Products Order by SomeField SQL Server 2005 SELECT top 3 With Ties * FROM Products Order by SomeField Multiple Dot Syntax Issue: Jet SQL allows multiple dot identifiers. SSMA Access support: No Solution: Add aliases to all fields and use these aliases in the top-level query. Example: Jet SELECT x.a.AAAA, x.b.AAAA FROM [SELECT a.AAAA, b.AAAA FROM table1 a Inner Join Table2 b On a.ID = b.ID]. AS x SQL Server 2005 SELECT x.Field1, x.Field2 FROM [SELECT a.AAAA as Field1, b.AAAA as Field2 FROM table1 a Inner Join Table2 b On a.ID = b.ID]. AS x Common Syntax Constructs This section covers converting incompatible operators in the SELECT statement expressions. Expressions Access Jet SQL has expressions similar to Transact-SQL expressions. Most operators can move to SQL Server 2005 without any conversion. These include comparison operators (<, >, =, >=, <=, <>, between), logical operators (And, Or, Xor), and arithmetic operators (+, -, *, /). The others are described next. '&' as Concatenation Operator Issue: Jet can use & as a string concatenation operator while SQL Server 2005 uses only the + character for string concatenation. SSMA Access support: No Solution: Convert any & character used for concatenation to + in SQL Server 2005. Example: Jet SELECT * FROM table1 WHERE c1 = 'a' & 'b' SQL Server 2005 SELECT * FROM table1 WHERE c1 = 'a' + 'b' '\' Operator (Integer Division) Issue: Jet has an integer division operator, but Transact-SQL does not. SSMA Access support: No Solution: Use just the division operator /, but make Dividend and Divisor rounded and reduced to an integer type. Example: 25 Guide to Migrating from Microsoft Access to SQL Server 2005 26 Jet a \ b SQL Server 2005 Cast(Round(@a, 0) as int) / Cast(Round(@b, 0) as int) 'Mod' Operator (Modulus Division) Issue: Jet has a different operator for modulus division. SSMA Access support: Yes Solution: Use the Transact-SQL operator % but Dividend and Divisor should be rounded and reduced to an integer type. Example: Jet a mod b SQL Server 2005 Cast(Round(@a, 0) as int) % Cast(Round(@b, 0) as int) '^' Operator (Raise to Power) Issue: Jet has a different operator to raise to a power. SSMA Access support: Yes Solution: Use the Transact-SQL function Power(a, b) to emulate the expression. Example: Jet a ^ b SQL Server 2005 Power(@a, @b) 'Eqv' and 'Imp' Issue: Transact-SQL does not have Eqv nor Imp operators. SSMA Access support: Yes Solution: Emulate these expressions. But because Transact-SQL does not have Boolean variables, you must convert boolean values into bit. Example 1 Jet SELECT (a > b) eqv (b < c) SQL Server 2005 SELECT CASE (Case when a > b Then 1 else 0 end) WHEN (Case WHEN b < c Then 1 else 0 end) then 1 ELSE 0 END Example 2 Jet SELECT (a > b) imp (b < c) SQL Server 2005 SELECT CASE (Case when a > b Then 1 ELSE 0 END) WHEN (Case WHEN b < c Then 1 else 0 end) then 1 ELSE 0 END 26 Guide to Migrating from Microsoft Access to SQL Server 2005 27 Example 3 Jet SELECT * From SomeTable where (a > b) eqv (b < c) SQL Server 2005 SELECT * From SomeTable Where (Case when a > b Then 1 ELSE 0 end) = (Case when b < c Then 1 ELSE 0 END) Example 4 Jet SELECT * From SomeTable where (a > b) imp (b < c) SQL Server 2005 SELECT * From SomeTable Where (Case when a > b Then 1 ELSE 0 end) <> (Case when b < c Then 1 ELSE 0 END) Date Literals Declaration Issue: Jet SQL encloses date literals in # symbols, but SQL Server 2005 can only use ' (apostrophe). SSMA Access support: Yes Solution: Replace # symbol with ' (apostrophe) in the date literals. Example: Jet #03-22-2006# SQL Server 2005 '03-22-2006' Like Operator Issue: Jet SQL has two Like operators: Alike and Like. The former works with SQL Server 2005 Compatible Syntax (ANSI 92) (in Access 2002 and later versions). Replace it with the Like keyword during conversion to SQL Server 2005. The latter has different syntax in patterns. SSMA Access support: Yes Solution: Replace the keyword alike with like, or modify the pattern according to the following table. Jet SQL Transact-SQL ? _ # [0-9] * % [<charlist>] [<charlist>] [!<charlist>] [^<charlist>] ^ \ (backslash) In the table, <charlist> is a sequence of characters (such as ABC) or a character range (A-Z). 27 Guide to Migrating from Microsoft Access to SQL Server 2005 28 Example: Jet a like '1234*', a alike '1234%' (in the Access 2002 and higher) SQL Server 2005 @a like '1234%' Join to View Converting Issues Converting Access Query with Joins to SQL View can result in a problem with field name duplication. For example: Create view SomeView As Select a.Fleld1, b.field1 From a Inner join b On a.ID = b.ID To avoid this, add aliases to the query field: CREATE view SomeView AS SELECT a.Fleld1 AS a_Field1, b.field1 AS b_Field1 FROM a Inner join b On a.ID = b.ID Transform…Pivot Statement The solutions for converting TRANSFORM…PIVOT statements use a source statement in the following form as an example: TRANSFORM "aggfunction" "selectstatement" PIVOT "pivotfield" [IN ("value1"[, "value2"[, ...]])] The following code examples show ways to convert these statements into Transact-SQL commands. All three example cases assume that the parameter aggfunction is neither the First() nor Last() function. Case 1. The PIVOT clause contains IN(…) part. Convert the following statement: TRANSFORM aggrfunction(Col1) SELECT <Col3,..., ColN> FROM Table AS t GROUP BY <Col3,..., ColN> ORDER BY <Column list> PIVOT (Col2) in (<col2_value1,col2_value2,...,col2_valueN>) To the following code: SELECT * FROM ( 28 Guide to Migrating from Microsoft Access to SQL Server 2005 29 SELECT <Col3,..., ColN>,Col1,Col2 FROM Table ) T PIVOT ( aggrfunction (Col1) FOR Col2 IN([col2_value1],[col2_value2],...,[col2_valueN]) ) T ORDER BY <Column list> Case 2. The PIVOT clause does not contain IN(…) part and Col2 data type is a natural number. Convert the following statement: TRANSFORM aggrfunction(Col1) SELECT <Col3,..., ColN> FROM Table AS t GROUP BY <Col3,..., ColN> ORDER BY <Column list> PIVOT (Col2); To the following code: declare @colunm_list nvarchar(max) SET @colunm_list= '' SELECT @colunm_list=@colunm_list+ CASE when rnum = 1 then quotename(ID) ELSE ',' +quotename(ID) END FROM (SELECT ROW_NUMBER() over(order by ID asc) as rnum, id FROM (SELECT distinct(Col2) as ID FROM "Table" )T ) t1 exec (' SELECT * FROM ( SELECT <Col3,..., ColN>,Col1,Col2 FROM "Table" ) T PIVOT (aggrfunction(Col1) FOR Col2 N('+@colunm_list+') ) T ORDER BY <Column list>') Case 3. The PIVOT clause does not contain IN(…) part and Col2 data type is a real number. Access replaces , in real numbers with _. 29 Guide to Migrating from Microsoft Access to SQL Server 2005 30 TRANSFORM aggrfunction(Col1) SELECT <Col3,..., ColN> FROM Table AS t GROUP BY <Col3,..., ColN> ORDER BY <Column list> PIVOT (Col2); The following code emulates this Access feature: declare @colunm_list nvarchar(max) SET @colunm_list= '' SELECT @colunm_list=@colunm_list+ CASE when rnum = 1 then quotename(replace(cast(ID asvarchar(100)),'.','_')) ELSE ',' +quotename(replace(cast(ID AS varchar(100)),'.','_')) END FROM ( SELECT ROW_NUMBER() over(order by ID asc) AS rnum, id FROM ( SELECT distinct(Col2) AS ID FROM "Table" )T ) t1 exec (' SELECT * FROM ( SELECT <Col3,..., ColN>,Col1, REPLACE(cast(Col2 as varchar(100)),'.','_') as Col2 FROM "Table" ) T PIVOT ( aggr_function(Col1) FOR Col2 IN('+@colunm_list+') ) T ORDER BY <Column list>') Functions Many standard Access functions have no direct correspondence in SQL Server 2005. This section gives guidance on converting these functions. If SSMA Access can handle a potential problem, the explanations for each function are marked: "SSMA Access support = Yes" and the solution is explained. If SSMA Access cannot make the automatic conversion, the solution for manual handling is included. String Functions Some string functions can be moved to SQL Server 2005 without any modification, including Left[$](), Right[$](), LTrim[$](), RTrim[$](), Space[$](), Len(). 30 Guide to Migrating from Microsoft Access to SQL Server 2005 31 Some string functions can have $ at the end of the name. They can be skipped. Issue: The Jet ASC function returns the NUMBER code that represents the specific character. SQL Server 2005 has the ASCII function with similar functionality. SSMA Access support: Yes Solution: Replace the ASC function with ASCII. Example: Jet ASC('A') SQL Server 2005 ASCII('A') Issue: The Jet CHR function returns the character based on the NUMBER code. Transact-SQL has the CHAR function with similar functionality. SSMA Access support: Yes Solution: Replace the CHR and CHR$ functions with CHAR. Example: Jet CHR[$](65) SQL Server 2005 CHAR(65) Issue: The Jet LCASE function converts a string to lower case. The Transact-SQL LOWER function has similar functionality. SSMA Access support: Yes Solution: Replace the LCASE and LCASE$ functions with LOWER. Example: Jet LCASE[$]('ABCDEFG') SQL Server 2005 LOWER('ABCDEFG') Issue: The Jet UCASE function converts a string to all upper case. The UPPER Transact-SQL has a function has similar functionality. SSMA Access support: Yes Solution: Replace UCASE with UPPER. Example: Jet UCASE[$]('abcdefg') SQL Server 2005 UPPER('abcdefg') 31 Guide to Migrating from Microsoft Access to SQL Server 2005 32 Issue: The Jet LEFT function extracts a substring from a string, starting from the leftmost character. Transact-SQL has a function with the same name and similar functionality. SSMA Access support: Yes Solution: Remove the $ character if it is in the function name. Example: Jet LEFT[$]('String', Number) SQL Server 2005 LEFT('String', Number) Issue: The Jet RIGHT function extracts a substring from a string starting from the right-most character. Transact-SQL has a function with the same name and similar functionality. SSMA Access support: Yes Solution: Remove the $ character if it is in the function name. Example: Jet RIGHT[$]('String', Number) SQL Server 2005 RIGHT('String', Number) Issue: The Jet LTRIM function removes leading spaces from a string. Transact-SQL has a function with the same name and similar functionality. SSMA Access support: Yes Solution: Remove the $ character if it is in the function name. Example: Jet LTRIM[$]('String') SQL Server 2005 LTRIM('String') Issue: The Jet RTRIM function removes trailing spaces from a string. Transact-SQL has a function with the same name and similar functionality. SSMA Access support: Yes Solution: Remove the $ character if it is in the function name. Example: Jet RTRIM[$]('String') SQL Server 2005 RTRIM('String') Issue: The Jet LEN function returns the length of the specified string. Transact-SQL has a function with the same name and similar functionality. 32 Guide to Migrating from Microsoft Access to SQL Server 2005 33 SSMA Access support: Yes Solution: No changes required. Example: Jet LEN('String') SQL Server 2005 LEN('String') Issue: The Jet SPACE function returns a string with a specified number of spaces. Transact-SQL has a function with the same name and similar functionality. SSMA Access support: Yes Solution: Remove the $ character if it is in the function name. Example: Jet SPACE[$](Number) SQL Server 2005 SPACE(Number) Issue: The Jet STR function returns a string representation of a number. TransactSQL has a function STR but it works differently. Use LTRIM() with STR() or use CAST(). SSMA Access support: Yes Solution: Add the LTRIM function or replace the STR function with CAST. Example: Jet STR[$](123456) SQL Server 2005 LTRIM(STR(123456)) Or CAST(123456 as vachar) Issue: The Jet TRIM() function removes leading and trailing spaces from a string. TransactSQL does not have such a function, but you can emulate it by using LTRIM(RTRIM()). SSMA Access support: Yes Solution: Replace the TRIM function with LTRIM and RTRIM. Example: Jet TRIM[$](" asdf ") SQL Server 2005 LTRIM(RTRIM(' asdf ')) Issue: Jet SQL has the FORMAT function but Transact-SQL does not have anything similar. 33 Guide to Migrating from Microsoft Access to SQL Server 2005 34 SSMA Access support: No Solution: Write a UDF to emulate this function. Example: Jet FORMAT("12345.678", "#, ##0.00") SQL Server 2005 No equivalent (emulated as UDF Format_*) Issue: The Jet INSTR function returns the position of the first occurrence of a string in another string. The CHARINDEX Transact-SQL function has similar functionality. SSMA Access support: Yes (partial) Solution: Replace the INSTR function with CHARINDEX for the cases shown in the following code examples. Keep in mind that the optional parameter start position is first in the Access function definition. The conversion depends on the format of INSTR. Format 1: Jet INSTR(String, subString) SQL Server 2005 CHARINDEX(substring String) Format 2: Jet INSTR(startposition, String, subString) SQL Server 2005 CHARINDEX(substring, String, startposition) Format 3: Jet INSTR(startposition, String, subString, ComparisionType) SQL Server 2005 no equivalent Format 4: Jet INSTR(String, subString, ComparisionType) SQL Server 2005 no equivalent Issue: The Jet MID function extracts a substring from a string (starting at any position). The Transact-SQL SUBSTRING function has similar functionality. SSMA Access support: Yes Solution: Replace the MID function with SUBSTRING. Example: Jet 34 Guide to Migrating from Microsoft Access to SQL Server 2005 35 MID[$](String, StartPosition, numberOfChararcters) SQL Server 2005 SUBSTRING(String, StartPosition, numberOfChararcters) Example 2: Jet MID[$](String, StartPosition) SQL Server 2005 SUBSTRING(String, StartPosition, Len('String') – StartPosition + 1) Issue: The Jet REPLACE function replaces a sequence of characters in a string with another set of characters. Transact-SQL has the same function with similar functionality. SSMA Access support: Yes (partial) Solution: Keep the REPLACE function for the cases shown in the following code examples. The conversion depends on the format of the original call. Format 1: Jet REPLACE(String, Find, Replacement) SQL Server 2005 REPLACE (String, Find, Replacement) Format 2: Jet REPLACE(String, Find, Replacement, Start) SQL Server 2005 Replace(SubString(String, Start, Len(String) - start + 1), Find,Replacement) Format 3: Jet REPLACE(String, Find, Replacement, Start, Count) SQL Server 2005 no equivalent (emulated as UDF Replace5) Format 4: Jet REPLACE(String, Find, Replacement, Start, Count, ComparisionType) SQL Server 2005 no equivalent 35 Guide to Migrating from Microsoft Access to SQL Server 2005 36 Issue: Jet SQL has the STRCONV function, but Transact-SQL does not have anything similar. SSMA Access support: No Solution: Write a UDF to emulate this function. Example: Jet STRCONV(Text, ConversionType[, LCID]) SQL Server 2005 No equivalent Advanced Functions Issue: The Jet SQL ISDATE function returns TRUE if the expression is a valid date. Otherwise, it returns FALSE. Transact-SQL has the ISDATE function but it doesn't have a Boolean type. Therefore, the function syntax is slightly different. SSMA Access support: Yes Solution: The SQL Server function returns an integer value (not Boolean). Therefore, it should be checked explicitly. Example: Jet ISDATE(expression) SQL Server 2005 ISDATE(expression) <> 0 Issue: The Jet SQL ISNULL function returns TRUE if the expression is a null value. Otherwise, it returns FALSE. Transact-SQL has the ISNULL function, but it has another function. SSMA Access support: Yes Solution: Use the SQL Server is null expression. Example: Jet ISNULL(expression) SQL Server 2005 expression is null Issue: The Jet SQL ISNUMERIC function returns TRUE if the expression is a valid number. Otherwise, it returns FALSE. Transact-SQL has the ISNUMERIC function but it does not have a Boolean type. Therefore, the syntax of the function call is slightly different. SSMA Access support: Yes Solution: The SQL Server function returns an integer value (not Boolean), so the comparison with 0 (zero) should be added in WHERE conditions. Example 1: Jet Select * From SomeTable Where ISNUMERIC(expression) SQL Server 2005 36 Guide to Migrating from Microsoft Access to SQL Server 2005 37 Select * From SomeTable Where ISNUMERIC(expression) <> 0 Example 2: Jet Select ISNUMERIC(expression) SQL Server 2005 Select ISNUMERIC(expression) Issue: The Jet NZ function lets you return a value when a variant is null. The Transact-SQL ISNULL function has similar functionality. SSMA Access support: Yes Solution: Replace the NZ function with ISNULL. Example 1: Jet NZ(expression1, expression2) SQL Server 2005 ISNULL(expression1, expression2) Example 2: Jet NZ(expression1) SQL Server 2005 ISNULL(expression1, '') Issue: The Jet IIF function returns one value if a specified condition evaluates to TRUE, and another value if it evaluates to FALSE. Transact-SQL does not have a similar function, but it can be emulated by using a CASE statement. SSMA Access support: Yes Solution: Emulate the IIF function with a CASE statement. Example: Jet IIF(condition, statement_if_true [, statement_if_false]) SQL Server 2005 CASE WHEN condition THEN statement_if_true [ELSE statement_if_false] END Issue: The Jet SWITCH function evaluates a list of expressions and returns the corresponding value for the first expression in the list that is TRUE. Transact-SQL does not have such a function, but it can be emulated with a CASE statement. SSMA Access support: No Solution: Emulate the SWITCH function with a CASE statement. Example: Jet 37 Guide to Migrating from Microsoft Access to SQL Server 2005 38 SWITCH(condition1, statement1 … [,conditionN, statementN]) SQL Server 2005 CASE WHEN condition1 THEN statement1 … [ WHEN conditionN THEN statementN ] ELSE null END Issue: Jet SQL has the CHOOSE function, but Transact-SQL does not have anything similar. SSMA Access support: No Solution: Write a UDF to emulate this function. Example: Jet Choose(position, value1, value2, ... value_n ) SQL Server 2005 No equivalent Issue: The Jet SQL CURRENTUSER function returns the name of the current Access user. The Transact-SQL CURRENT_USER function has similar functionality. SSMA Access support: Yes Solution: Replace the CURRENTUSER function with CURRENT_USER. Example: Jet CURRENTUSER() SQL Server 2005 CURRENT_USER Domain Aggregate Functions Access has the domain aggregate functions (DAvg, DCount, DFirst, DLast, DLookup, DMin, DMax, DSum). Their main syntax is: DFunctionName(expression, domain [, criteria]) SSMA Access support: No. These functions can be converted in common cases into SELECT statements as dynamic SQL only as in the following code: Declare @Str Varchar(1000) Set @Str = 'SELECT FunctionName(' + expression ' Where ' + + ') FROM ' + domain + <criteria> Exec (@Str) The correspondence between Access functions and SQL Server 2005 functions is shown in the following table. Jet Function (DFunctionName) DAvg() SQL Server 2005 (FunctionName) Avg() 38 Guide to Migrating from Microsoft Access to SQL Server 2005 Jet Function (DFunctionName) 39 SQL Server 2005 (FunctionName) DCount() Count() DFirst() No equivalent DLast() No equivalent DLookup() Skipped (use only expression in SELECT clause) DMin() Min() DMax() Max() DSum() Sum() Numeric/Mathematical Functions You can move some numeric/mathematical functions to SQL Server 2005 without any modification, such as Abs(), Avg(), Cos(), Exp(), Log(), and Round(). Issue: The Jet ABS function returns the absolute value of a number. Transact-SQL has a function with the same name and similar functionality. SSMA Access support: Yes Solution: No changes required. Example: Jet ABS(ABC) SQL Server 2005 ABS(@ABC) Issue: The Jet ATN function returns the arctangent of a number. The Transact-SQL ATAN function has similar functionality. SSMA Access support: Yes Solution: Replace ATN with ATAN. Example: Jet ATN(ABC) SQL Server 2005 ATAN(@ABC) Issue: The Jet COS function returns the cosine of an angle. Transact-SQL has a function with the same name and similar functionality. SSMA Access support: Yes Solution: No changes needed. Example: Jet COS(ABC) 39 Guide to Migrating from Microsoft Access to SQL Server 2005 40 SQL Server 2005 COS(@ABC) Issue: The Jet EXP function returns e raised to the nth power, where e = 2.71828183. Transact-SQL has a function with the same name and similar functionality. SSMA Access support: Yes Solution: No changes required. Example: Jet EXP(ABC) SQL Server 2005 EXP(@ABC) Issue: The Jet FIX function returns the integer portion of a number. Transact-SQL does not have a similar function, but you can emulate it by using CAST(). SSMA Access support: Yes Solution: Replace FIX with CAST. Example: Jet FIX(123.456) SQL Server 2005 CAST(123.456 as integer) Issue: The Jet INT function returns the integer portion of a number. The Transact-SQL FLOOR function has similar functionality. SSMA Access support: Yes Solution: Replace INT with FLOOR. Example: Jet INT(123.456) SQL Server 2005 FLOOR(123.456) Issue: Jet has the LOG function. Transact-SQL has a function with the same name and similar functionality. SSMA Access support: Yes Solution: No changes needed. Example: Jet LOG(ABC) SQL Server 2005 40 Guide to Migrating from Microsoft Access to SQL Server 2005 41 LOG(@ABC) Issue: Jet has the RND function. The Transact-SQL RAND function has similar functionality. SSMA Access support: Yes Solution: Replace RND with RAND(). Example: Jet RND SQL Server 2005 RAND() Issue: The Jet ROUND function returns a number rounded to a specified number of decimal places. Transact-SQL has a function with the same name and similar functionality. But the absence of the second parameter in SQL Server 2005 is not allowed. SSMA Access support: Yes Solution: If the second parameter is absent, in SQL Server 2005 specify the value 0 (zeo) for the second parameter of the ROUND function. Example: Jet ROUND(ABC, 2) SQL Server 2005 ROUND(@ABC, 2) Issue: The Jet SIN function returns the sine of an angle. Transact-SQL has a function with the same name and similar functionality. SSMA Access support: Yes Solution: No changes required. Example: Jet SIN(ABC) SQL Server 2005 SIN(@ABC) Issue: The Jet SGN function returns the sign of a number (represented as an integer). The Transact-SQL SIGN function has similar functionality. SSMA Access support: Yes Solution: Replace SGN with SIGN. Example: Jet SGN(123.456) SQL Server 2005 41 Guide to Migrating from Microsoft Access to SQL Server 2005 42 SIGN(123.456) Issue: The Jet TAN function returns the tangent of a number. Transact-SQL has a function with the same name and similar functionality. SSMA Access support: Yes Solution: No changes required. Example: Jet TAN(ABC) SQL Server 2005 TAN(@ABC) Issue: Jet SQL has the VAL function, but Transact-SQL does not have anything similar. VAL accepts a string as input and returns the numbers found in that string. SSMA Access support: No Solution: Write a UDF to emulate this function. Example: Jet VAL (" 34 10 Main Street ") SQL Server 2005 No equivalent Date Functions Some Access date functions use date parts. To convert them to SQL Server 2005 definitions, use the following table. Access definition Explanation SQL Server 2005 possible equivalents 'yyyy' Year year, yyyy, yy 'q' Quarter quarter, q, qq 'm' Month month, mm, mm 'y' Day of the year dayofyear, dy, y 'd' Day day, dd,. D 'w' Weekday weekday, dw 'ww' Week week, wk, ww 'h' Hour hour, hh 'n' Minute minute, mi, n 's' Second second, ss, s You can convert some functions to SQL Server 2005 according to the table (DateAdd(), DateDiff(), DatePart()), but they have more advanced functionality in Access. If you do not have additional parameters, you can convert them according to the previous table. 42 Guide to Migrating from Microsoft Access to SQL Server 2005 43 Some Access date functions, such as Day(), Month(), Year(), can be moved into SQL Server 2005 without any modification. Issue: The Jet DATEADD function returns a date after which a certain time/date interval has been added. SQL has a function with the same name and similar functionality. SSMA Access support: Yes Solution: Replace the Jet SQL interval definition with a Transact-SQL one. Example: Jet DATEADD('interval', Number, date) SQL Server 2005 DATEADD(interval, Number, date) Issue: The Jet DATEDIFF function returns the difference between two date values, based on the interval specified. Transact-SQL has a function with the same name and similar functionality. SSMA Access support: Yes Solution: Replace the Jet SQL interval definition with a Transact-SQL one. Example: Jet DATEDIFF('interval', date1, date2) SQL Server 2005 DATEDIFF(interval, date1, date2) Issue: The Jet DATEPART function returns a specified part of a given date. Transact-SQL has a function with the same name and similar functionality. SSMA Access support: Yes Solution: Replace the Jet SQL interval definition with a Transact-SQL one. Example: Jet DATEPART('interval', date) SQL Server 2005 DATEPART(interval, date) Issue: The Jet DAY function returns the day of the month (a number from 1 to 31) given a date value. Transact-SQL has a function with the same name and similar functionality. SSMA Access support: Yes Solution: No changes required. Example: Jet DAY(date) SQL Server 2005 43 Guide to Migrating from Microsoft Access to SQL Server 2005 44 DAY(date) Issue: The Jet MONTH function returns the month (a number from 1 to 12) given a date value. Transact-SQL has a function with the same name and similar functionality. SSMA Access support: Yes Solution: No changes required. Example: Jet MONTH(date) SQL Server 2005 MONTH(date) Issue: The Jet YEAR function returns a four-digit year (a number from 1900 to 9999) given a date value. Transact-SQL has a function with the same name and similar functionality. SSMA Access support: Yes Solution: No changes required. Example: Jet YEAR(date) SQL Server 2005 YEAR(date) Issue: The Jet NOW function returns the current system date and time. The Transact-SQL GETDATE function has similar functionality. SSMA Access support: Yes Solution: Replace NOW with GETDATE. Example: Jet NOW() SQL Server 2005 GETDATE() Issue: The Jet DATESERIAL function returns a date given a year, month, and day value. Transact-SQL does not have this function, but you can use DATEADD to emulate it. SSMA Access support: Yes Solution: Replace DATESERIAL with expression as shown in the following example. The year should be 4-digit only. Example: Jet DateSerial(A, B, C) SQL Server 2005 44 Guide to Migrating from Microsoft Access to SQL Server 2005 45 DATEADD(day, Round(Cast(C as Integer) – 1, 0), DATEADD(month, Round(Cast(B as Integer) - 1, 0), CAST(Str(Cast((A) as Integer) +'0101') as datetime))) Issue: The Jet HOUR function returns the hour of the day (a number from 0 to 23) given a time value. Transact-SQL does not have this function, but you can use DATEPART to emulate it. SSMA Access support: Yes Solution: Replace HOUR with DATEPART. Example: Jet HOUR(NOW()) SQL Server 2005 DATEPART(hour, GETDATE()) Issue: The Jet MINUTE function returns the minute of the hour (a number from 0 to 59) given a time value. Transact-SQL does not have this function, but you can use DATEPART to emulate it. SSMA Access support: Yes Solution: Replace MINUTE with DATEPART. Example: Jet MINUTE(NOW()) SQL Server 2005 DATEPART(minute, GETDATE()) Issue: The Jet MONTHNAME function returns a string representing the month given a number from 1 to 12. Transact-SQL does not have this function, but you can emulate it by using DATENAME. SSMA Access support: Yes Solution: Replace MONTHNAME with DATENAME. Example: Jet MONTHNAME(MonthNumber) SQL Server 2005 DATENAME(month, cast('1900' + Right('0' + (LTrim(Str(MonthNumber))), 2) + '01' as datetime)) Issue: The Jet SECOND function returns the second of the minute (a number from 0 to 59) given a time value. Transact-SQL does not have this function, but you can emulate it by using DATEPART. SSMA Access support: Yes Solution: Replace SECOND with DATEPART. Example: 45 Guide to Migrating from Microsoft Access to SQL Server 2005 46 Jet SECOND (NOW()) SQL Server 2005 DATEPART(second, GETDATE()) Issue: Jet has a DATE function that returns the date only. Transact-SQL does not have such a function. SSMA Access support: Yes Solution: Replace DATE with an expression as shown in the following example. Example: Jet DATE() SQL Server 2005 CONVERT(datetime,CONVERT(varchar,GETDATE(),1)) Issue: Jet has a DATEVALUE function. Transact-SQL does not have such a function. SSMA Access support: No Solution: Write a UDF to emulate this function. Example: Jet DATEVALUE("Jun 30") SQL Server 2005 No equivalent Issue: The Jet TIME function returns the time only. Transact-SQL does not have such a function. SSMA Access support: No Solution: Use the following expression: select convert(datetime, '12/30/1899 ' + convert(varchar,getdate(),14)) to emulate this function Issue: The Jet TIMESERIAL function returns time only. Transact-SQL does not have such a function. SSMA Access support: No Solution: Write a UDF to emulate TIMESERIAL. The datetime value should have the date set as 12/30/1899. Example: Jet TIMESERIAL(hoursexpression, minuteexpression, secondexpression) SQL Server 2005 No equivalent 46 Guide to Migrating from Microsoft Access to SQL Server 2005 47 Issue: The Jet TIMEVALUE function returns the time only. Transact-SQL does not have such a function. SSMA Access support: No Solution: Write UDF to emulate TIMEVALUE. The datetime value should have date set as 12/30/1899. Example: Jet TIMEVALUE("3:12:54 PM") SQL Server 2005 No equivalent Issue: The Jet WEEKDAY function returns a number representing the day of the week (a number from 1 to 7) given a date value. Transact-SQL does not have this function, but you can use DATEPART to emulate it. SSMA Access support: Yes (partial) Solution: Replace WEEKDAY with DATEPART if you do no have an optional parameter defined, or create a UDF with the same name to emulate full functionality. Format 1: Jet WEEKDAY(NOW()) SQL Server 2005 DATEPART(weekday, GETDATE()) Format 2: Jet WEEKDAY(NOW(), firstdayofweek) SQL Server 2005 No equivalent (emulated as UDF) Issue: The Jet WEEKDAYNAME function returns a string representing the day of the week given a number from 1 to 7. Transact-SQL does not have such a function. SSMA Access support: No Solution: Write a UDF to emulate this function. Example: Jet WEEKDAYNAME (Number [, abbreviate [, firstdayiofweek]]) SQL Server 2005 No equivalent (emulated as UDF) Issue: Jet has the DateAddW function (wrote on Basic) that adds work days to a date. Transact-SQL does not have a similar function. SSMA Access support: No Solution: Write a UDF to emulate DateAddW. 47 Guide to Migrating from Microsoft Access to SQL Server 2005 48 Example: Jet DATEADDW (Date, days) SQL Server 2005 No equivalent (emulated as UDF) Data Type Conversion Functions You can convert most data type conversion functions as CAST functions, as the following table shows. Note that if you convert into integer types, the values should be rounded. Jet SQL Transact-SQL CByte(expression) CAST (ROUND(expression, 0) as tinyint) CCur(expression) CAST (expression as money) CDate(expression) CAST (expression as datetime) CDbl(expression) CAST (expression asfloat) CDec(expression) CAST (expression as decimal) CInt(expression) CAST (ROUND(expression, 0) as smallint) CLng(expression) CAST (ROUND(expression, 0) as integer) CSng(expression) CAST (expression as real) CStr(expression) CAST (expression as varchar) CVar(expression) CAST (expression as sql_variant) CVDate(expression)* CAST (CAST (expression as datetime) as sql_variant) * This is an old variant of the CDate() function. It converts an expression into the datetime type but returns it as a variant type. SSMA Access support: Yes (partialy) SQL Server 2005 does not have a Boolean type, therefore you cannot convert function CBool without analyzing the code where it is used. Aggregate Functions You can move most aggregate functions (Avg(), Count(), Min(), Max(), Sum()) without any modification. Issue: The Jet AVG function returns the average (arithmetic mean) of a set of numeric values in a select query. Transact-SQL has a function with the same name and similar functionality. SSMA Access support: Yes Solution: No changes required. Example: Jet AVG(expression) SQL Server 2005 48 Guide to Migrating from Microsoft Access to SQL Server 2005 49 AVG(expression) Issue: The Jet COUNT function returns the number of records in a select query. Transact-SQL has a function with the same name and similar functionality. SSMA Access support: Yes Solution: No changes required. Example: Jet COUNT(expression) SQL Server 2005 COUNT(expression) Issue: The Jet MIN function returns the minimum value in a set of numeric values in a select query. Transact-SQL has a function with the same name and similar functionality. SSMA Access support: Yes Solution: No changes required. Example: Jet MIN(expression) SQL Server 2005 MIN(expression) Issue: The Jet MAX function returns the maximum value in a set of numeric values in a select query. Transact-SQL has a function with the same name and similar functionality. SSMA Access support: Yes Solution: No changes required. Example: Jet MAX(expression) SQL Server 2005 MAX(expression) Issue: The Jet SUM function returns the sum of a set of numeric values in a select query. Transact-SQL has a function with the same name and similar functionality. SSMA Access support: Yes Solution: No changes required. Example: Jet SUM(expression) SQL Server 2005 SUM(expression) 49 Guide to Migrating from Microsoft Access to SQL Server 2005 50 Issue: The Jet FIRST function returns the first value that was inserted into a table from the result set of a query. Transact-SQL does not have such a function. SSMA Access support: No Solution: In this situation, many conditions must be emulated. Note that there is no guarantee that the order of unsorted records in Transact-SQL will be the same as in the original table; therefore, the first element may be different. You can use a Top 1 subquery to extract the first value. (If you have one First() function as a field, there is no need to use a subquery.) If the SELECT statement has conditions, duplicate them in the subquery as well. The Jet FIRST function can be emulated only when the source statement does not include the GROUP BY clause. It is possible that this emulation will work differently after data migration if the table has one or more indexes. Example 1: Jet SELECT FIRST(expression), <other_aggregate_functions> from SomeTable SQL Server 2005 SELECT (SELECT Top 1 expression From SomeTable) as first, <other_aggregate_functions> From SomeTable Example 2: Jet SELECT FIRST(expression) from SomeTable SQL Server 2005 SELECT Top 1 expression From SomeTable Issue: The Jet LAST function returns the last value that was inserted into a table from the result set of a query. Transact-SQL does not have such a function. SSMA Access support: No Solution: In this situation, many conditions must be emulated. Note that there is no guarantee that the order of unsorted records in Transact-SQL will be the same as in the original table; therefore, the last element may be different. You can use a Top 1 subquery to retrieve last value, but the same functionality can be emulated only if the last inserted record can be found. This is often an identity field. If there is one Last() function as a field, the subquery is unnecessary. If the SELECT statement has conditions, these should be duplicated in the subquery as well. This function can be emulated only when the source statement does not have a GROUP BY clause. Example: Jet SELECT LAST(expression), <other_aggregate_functions> From SomeTable SQL Server 2005 SELECT (SELECT Top 1 expression From SomeTable Order by IdentityField Desc) as first, <other_aggregate_functions> 50 Guide to Migrating from Microsoft Access to SQL Server 2005 51 From SomeTable Example 2: Jet SELECT LAST(expression) From SomeTable SQL Server 2005 SELECT Top 1 expression From SomeTable Order by IdentityField Desc Data Migration This section covers aspects of the data migration that is performed by SSMA Access. Generally, data is transferred without any transformation from the Jet store into the SQL Server 2005 database during data migration. The connection is established from SSMA Access to Access/Jet and to SQL Server 2005. Since you cannot assume that SQL Server 2005 can connect back to the .mdb file, solutions that are based on linked servers are not applicable. Data Transfer Source SSMA Access moves the data from the source table to the destination table. Currently, moving data from an Access/Jet linked table to SQL Server 2005 is not supported. If you have already linked the table and want to retransfer the data, you must unlink the table by using the SSMA Access command before you can transfer the data. It is possible that in the future the moving of data from a linked table will be supported. Data Transformation SSMA Access does not change the transfer data and relies on the implicit data conversion done by ADO.NET. The only exception is the date range. Date values that are earlier than the SQL Server 2005 limit—1 Jan 1753—are converted to 1 Jan 1753 and a warning is generated. SSMA Access reads each date column value and checks that the value is not before 1 Jan 1753. If it is, SSMA Access uploads to the server the date 1 Jan 1753 instead of the underlying value. Technology Used for the Data Migration During development, after much evaluation of various technologies such SSIS and a linked table data pump (insert into linked_table from select * from source_table), it was decided that the SQL Server Migration Assistant would use the OleDbConnection class to read the source and System.Data.SqlClient.SqlBulkCopy to write to the destination (bulk copy write). This proved to be reliable, simple, and highly performing. Transaction Boundaries There are no functional requirements on transaction boundaries when uploading data to SQL Server 2005. SSMA Access groups multiple rows in a single transaction for better performance; it is up to the in-house development team to find the correct number of rows for each transaction. Our initial finding yields that 1,000 rows in a single transaction is a good starting point. 51 Guide to Migrating from Microsoft Access to SQL Server 2005 52 Conclusion You now know the algorithms that SSMA Access uses to perform conversions and can better understand the processes that are executed when the SSMA Access Migration Wizard upsizes a database. For those rare cases when SSMA Access does not handle a particular migration issue, you have approaches to manual conversion. If you need help on SSMA Access or have a question about migrating from Access to SQL Server 2005, send us an e-mail at acc2sql@microsoft.com. For more information: http://www.microsoft.com/sql/solutions/migration/default.mspx Did this paper help you? Please give us your feedback. Tell us on a scale of 1 (poor) to 5 (excellent), how would you rate this paper and why have you given it this rating? For example: Are you rating it high due to having good examples, excellent screenshots, clear writing, or another reason? Are you rating it low due to poor examples, fuzzy screenshots, unclear writing? This feedback will help us improve the quality of white papers we release. Send feedback. 52