Quantcast
Channel: SQL Server Migration Assistant (SSMA) Team's Blog
Viewing all 29 articles
Browse latest View live

How To Convert Individual Statement Using SSMA

$
0
0

You can use SSMA to convert a statement (such as PL/SQL) into T-SQL statement using SSMA. This functionality can be used, for example, to convert embedded SQL statement inside an application that connects to the database.

Use the following steps to convert individual statement:

  1. Open SSMA tool
  2. Create a New Project (or open an existing project)
  3. Connect to Oracle instance
  4. Connect to SQL Server instance
  5. Locate an Oracle Schema, Expand, Right click on Statements and Select Add Statement

  1. Type or Paste your statement in the SQL Editor on the upper right side window.

  1. Right Click on the statement item and Select Convert Schema

  1. Click Yes when prompted to Save Changes
  2. The converted statement is shown in the SQL Editor on the lower right side window. 

 

 Note: that before you convert the statement, you will need to convert your entire schema, otherwise, if your statement refers to a table and the table has not been converted, SSMA may return "identifier is not resolved" error.


A Curious Case of NUMBER truncation

$
0
0

Oracle's FLOAT  may truncate a float number beyond its binary digit limit. For example, execute the following in Oracle:

DECLARE

testvar FLOAT(5);

BEGIN

Testvar := 123.45;

DBMS_OUTPUT.put_line(to_char(testvar));

END;

 

The statement will return 120 as the number 123.45 is rounded to 120, which has the max 4 binary digit.  This case above is documented here.

 

When you convert Oracle statement containing the FLOAT to SQL Server, SSMA converts Oracle float data type to SQL Server float data type as follows:

 

BEGIN

   DECLARE

      @testvar float(5)

   SET @Testvar = 123.45

   PRINT CAST(@testvar AS varchar(max))

END

 

However, SQL Server does not perform truncation and will preserve the value. The statement above will return 123.45.

 

Please note the differences in your migration project.

A Foreign Affair

$
0
0

You may run into issue when using SSMA to connect to Oracle database containing foreign characters (non-ASCII characters) in its schema. In the example below, we have an Oracle database containing a table with Japanese name:

OracleClientConnection

The issue is caused by the Oracle client provider not able to process SQL statement containing non-ASCII characters. In order to display the table attributes, SSMA submits a separate query with table name as filtering criteria in its SQL statement. In the example above, when SQL statement submitted to the Oracle client provider containing table name Japanese character, the statement failed.

One workaround is by using OLEDB provider to connect to Oracle:

Connection

OLEDB provider is able to process the SQL statement containing non-ASCII character and show the table attributes correctly.

OLEDBConnection

Note that if you have an existing SSMA project with Oracle Client Provider to connect, you need to create a new project using OLEDB Provider.

Video: Converting Schema to SQL Server

Saving Comments During Migration

$
0
0

During migration to SQL Server, you may find that the source database schema contains some comments to describe the schema. This can be as a comment within programming code (such as Oracle PL/SQL) in procedure, function, package, view or as a comment that is part of the table/ column schema. SQL Server Migration Assistant (SSMA) migrates the full programming code, including any comments inside procedure, function, package, view, etc. However, it does not automatically migrate comment as part of table schema. This blog post shows how to re-create the comment for tables and columns in SQL Server.

Consider the following example:

--Execute the following in Oracle:CREATETABLE Orders (
    OrderID NUMBER(5),
    CustomerID NCHAR(5) ,
    EmployeeID NUMBER(5) NULL ,
    OrderDate DATENULL ,
    RequiredDate DATENULL
    );

COMMENT ONTABLE Orders IS'Customer data for the last 5 years - move to Order_archive after 5 years' ;
COMMENT ONCOLUMN Orders .EmployeeID IS'Employee Id of the person receiving the order. The value must be preserved even the employee is no longer active';
COMMENT ONCOLUMN Orders .RequiredDate IS'Date in which the product must be received at the customer site';

You can run the following query to look up the comments on Oracle table:

You can recreate the comments in SQL server using sys.sp_addextendedproperty:

-- Execute the following in SQL Server:CREATETABLE dbo.Orders (
    OrderID INTEGER,
    CustomerID NCHAR(5) ,
    EmployeeID INTEGERNULL ,
    OrderDate DATETIME2 NULL ,
    RequiredDate DATETIME2 NULL
    );EXEC sys.sp_addextendedproperty 
@name = N'Orders', 
@value = N'Customer data for the last 5 years - move to Order_archive after 5 years', 
@level0type = N'USER', @level0name = 'dbo',
@level1type = N'TABLE', @level1name = 'Orders';GOEXEC sp_addextendedproperty 
@name = N'Orders.EmployeeID', 
@value = 'Employee Id of the person receiving the order. The value must be preserved even the employee is no longer active',
@level0type = N'USER', @level0name = 'dbo',
@level1type = N'Table', @level1name = 'Orders',
@level2type = N'Column', @level2name = 'EmployeeID';GOEXEC sp_addextendedproperty 
@name = N'Orders.RequiredDate', 
@value = 'Date in which the product must be received at the customer site',
@level0type = N'USER', @level0name = 'dbo',
@level1type = N'Table', @level1name = 'Orders',
@level2type = N'Column', @level2name = 'RequiredDate';GO

You can query the extended properties as follow:

Special thanks to Eric Linneman from Microsoft Consulting Services for sharing the tip above. If you have any tips you like to share, please email us at ssmateam@microsoft.com.

Migrating Oracle to SQL Server using SSMA–Error O2SS0293: Columns list in set clause cannot be converted

$
0
0

This blog post describes SSMA error message when converting Oracle PL/SQL UPDATE statement with column group assignment.

Oracle PL/SQL allows you to perform multi column update through sub-query. Consider the following example:

CREATE TABLE ACCOUNT
   (
       ACCOUNT_ID NUMBER NOT NULL,
       ACCOUNT_OWNER VARCHAR2(30) NOT NULL
   );

UPDATE ACCOUNT
    SET (ACCOUNT_ID, ACCOUNT_OWNER) = (SELECT 1, 2 FROM dual)
    WHERE ACCOUNT_ID = 10;

SSMA does not support converting UPDATE statement with sub-query and the following conversion error message is issued:

O2SS0293: Columns list in set clause cannot be converted.

The above statement can be converted to T-SQL statement such as the following:

UPDATE    acct
SET            acct.ACCOUNT_ID = updtqry.col1,
                  acct.ACCOUNT_OWNER = updtqry.col2
FROM       ACCOUNT acct, (SELECT 1 col1, 2 col2) updtqry
WHERE    acct.ACCOUNT_ID=10;

Migrating Oracle to SQL Server Using SSMA - Emulating Oracle Package Variables

$
0
0

By Bill Ramos and Vishal Soni, Advaiya Inc.

 

Oracle supports encapsulating variables, types, stored procedures, and functions into a package. When you convert Oracle packages, you need to convert:

  • Procedures and functions - both public and private
  • Variables
  • Cursors
  • Initialization routines

This blog describes how SQL Server Migration Assistant (SSMA) for Oracle converts package variables to SQL Server.

Converting Package Variables 

To store package variables, SSMA for Oracle uses stored procedures that reside in a SysDB database along with the ssma_oracle.db_storage table. This table is filtered by SPID (session identifier) and login time. This filtering enables you to distinguish between variables of different sessions.

Few of the special procedures are mentioned below:

·         sysdb.ssma_oracle.set_pv_varchar

·         sysdb.ssma_oracle.set_pv_datetime2

·         sysdb.ssma_oracle.set_pv_float

 

At the beginning of each procedure SSMA places a call to the sysdb.ssma_oracle.db_check_init_package procedure, which checks if the package is initialized and will initialize it if needed. Each initialization procedure cleans the storage table and sets default values for each package variable.

 

Consider the following example for converting several package variables.

 

CREATEORREPLACEPACKAGE MY_PACKAGE

IS

 spacevarchar(1) := ' ';

 unitname varchar(128) := 'My Simple Package';

 curd date := sysdate;

END;

 

The SSMA converts it into the following Transact-SQL code:

 

CREATEPROCEDURE dbo.MY_PACKAGE$SSMA_Initialize_Package

AS

   EXECUTE sysdb.ssma_oracle.db_clean_storage

   EXECUTE sysdb.ssma_oracle.set_pv_varchar

      'PROSEWARE',

      'DBO',

      'MY_PACKAGE',

      'SPACE',

      ' '

   EXECUTE sysdb.ssma_oracle.set_pv_varchar

      'PROSEWARE',

      'DBO',

      'MY_PACKAGE',

      'UNITNAME',

      'My Simple Package'

   DECLARE

      @temp datetime2

   SET @temp = sysdatetime()

   EXECUTE sysdb.ssma_oracle.set_pv_datetime2

      'PROSEWARE',

      'DBO',

      'MY_PACKAGE',

      'CURD',

      @temp

 

Emulating Get and Set Package Variable Methods with SSMA

Oracle uses ‘Get’ and ‘Set’ methods for the package variables, to avoid letting other subprograms read and write them directly. If there is a requirement to keep some variables available between subprogram calls in the same session, these variables are treated like global variables.

 

To overcome this scoping rule, SSMA for Oracle uses stored procedures like sysdb.ssma_oracle.set_pv_varchar for each variable type.  For accessing these variables, SSMA uses a set of transaction-independent GET and SET procedures and functions.

 

Data type in Oracle

SSMA conversion

Varchar

sysdb.ssma_oracle.set_pv_varchar

Date

sysdb.ssma_oracle.set_pv_datetime2

Char

sysdb.ssma_oracle.set_pv_varchar

Int

sysdb.ssma_oracle.set_pv_float

Float

sysdb.ssma_oracle.set_pv_float

 

To distinguish between variables from different sessions, SSMA stores the variables along with their SPID (session identifier) and the session’s login time. Thus the GET and SET procedures keeps the variables independent from the sessions running them. 

 

References

For more information, check out the Migrating Oracle to SQL Server 2008 White Paper.

For Oracle Package information, refer to the Oracle Database PL/SQL User’s Guide and Reference – Using PL/SQL Packages.



SSMA @TechEd Video


Improving Performance of SSMA Migration Assessment

$
0
0

When performing migration assessment for a large schema (with thousands of objects), you can use the following to help improve performance:

  1. Run SSMA application on hardware with x64 bit Windows and memory of at least 4 GB.
  2. Force load the schema information prior performing migration assessment. SSMA, by default, perform “lazy loading” operation by reading minimum schema information from the source database when connecting. During the assessment or conversion operation, it requests additional information to the source database “on-demand”. For full assessment of the entire schema, this results in multiple requests to the server. Depending on the network latency and server status at the time of the request, this may results in significant addition to the time it takes to perform assessment.

To fully load the schema, you can follow these steps:

  1. Create/Open SSMA project
  2. Connect to the source database
  3. Save project

saveproject

  1. Specify schema(s) to load and save (note: in addition to the schema you want to perform assessment, you must also include all others you refer in your schema, including (for Oracle) SYS and SYSTEM)

savemetadata

Converting Oracle UDT to SQL Server TVP

$
0
0

Oracle supports User Defined Type (UDT) which include object type and collection. This data type is not supported in SQL Server and SSMA does not support conversion of Oracle UDT. You may consider using SQL Server TVP when migrating your Oracle database to SQL Server.

The following provides use scenarios of UDT and examples on how to recreate the statements in SQL Server:

PL/SQL user defined type is converted to user defined table type

PL/SQLT-SQL
CREATE TYPE person_ot AS OBJECT (
   firstname VARCHAR(100),
   lastname VARCHAR(100),
   hiredate DATE
);

CREATE TYPE person_ot AS TABLE
(
   rowid uniqueidentifier DEFAULT NEWID(),
   firstname VARCHAR(100),
   lastname VARCHAR(100),
   hiredate DATETIME2,
   PRIMARY KEY (rowid)
)

CREATE TYPE productcategory_ot AS OBJECT
(
   category VARCHAR2(50),
   owner person_ot
);

CREATE TYPE productcategory_ot AS TABLE
(
   rowid uniqueidentifier DEFAULT NEWID(),
   category VARCHAR(50),
   owner uniqueidentifier
)

Oracle variable declared as user defined type is converted to sql server variable of user defined table type

PL/SQL

T-SQL

DECLARE person_var person_ot;

DECLARE @person_var person_ot

Input argument as user defined type will be converted to sql server table value parameter (TVP)

PL/SQL

T-SQL

CREATE PROCEDURE showname(person_in IN person_ot, fullname OUT VARCHAR2)
IS
BEGIN
   Fullname := person_in.firstname  || ' '
               person_in.lastname;
END;

CREATE PROCEDURE showname(@person_in person_ot READONLY, @fullname VARCHAR(200))
AS
SELECT @fullname = firstname + ' ' + lastname FROM @person_in;

Output argument as user defined type is converted to retuned data set 

PL/SQL

T-SQL

CREATE OR REPLACE PROCEDURE createperson (firstname IN VARCHAR2, lastname in VARCHAR2, person_out OUT person_ot)
IS
BEGIN
  person_out := person_ot(firstname, lastname, SYSDATE);
END;

 

-- sample statement to use the stored procedure
DECLARE
   person person_ot;
BEGIN
   createperson ('fname', 'lname', person);
   DBMS_OUTPUT.PUT_LINE(person.firstname);
END;

CREATE PROCEDURE createperson (@firstname VARCHAR(100), @lastname VARCHAR(100))
AS
DECLARE @person_out person_ot
INSERT INTO @person_out (firstname, lastname, hiredate) VALUES (@firstname, @lastname, GETDATE())
-- return the object type output as result set
SELECT * FROM @person_out
GO


-- sample statement to use the stored procedure
DECLARE @person person_ot
INSERT INTO @person
EXECUTE createperson 'fname','lname'
SELECT firstname FROM @person

Object table is created out of schema definition of the user defined table type 

PL/SQL

T-SQL

CREATE TABLE obtblperson OF person_ot;

DECLARE @person_ot person_ot

SELECT * INTO obtblperson FROM @person_ot

Oracle table column with user defined type is converted into a seperate table. For object type, the main table column is converted into uniqueidentifier column with foreign key relationship to the sub table. For collection, the sub table is created with a foreign key column referring to the primary key of the main table.

PL/SQL

T-SQL

CREATE TABLE tblemployee_ot
(
   id NUMBER,
   employee person_ot,
   role VARCHAR2(100),
   CONSTRAINT tblemployee_ot_pk PRIMARY KEY (id)
);

CREATE TABLE tblemployee_ot
(
   id INT,
   employee uniqueidentifier,
   role VARCHAR(100),
   CONSTRAINT tblemployee_ot_pk PRIMARY KEY (id)
);

CREATE TABLE tblemployee_ot$employee
(
   rowid uniqueidentifier DEFAULT NEWSEQUENTIALID(),
   firstname VARCHAR(100),
   lastname VARCHAR(100),
   hiredate VARCHAR(20),
   PRIMARY KEY (rowid)
)

ALTER TABLE tblemployee_ot ADD CONSTRAINT fk_employee FOREIGN KEY (employee) REFERENCES t85575343$employee (rowid)

CREATE TABLE tblemployee_nt
(
   id NUMBER,
   employee person_nt,
   role VARCHAR2(100),
   CONSTRAINT tblemployee_nt_pk PRIMARY KEY (id)
);

ALTER TABLE tblemployee_ot ADD CONSTRAINT fk_employee FOREIGN KEY (employee) REFERENCES t85575343$employee (rowid)

CREATE TABLE tblemployee_nt
(
   id INT,
   role VARCHAR(100),
   CONSTRAINT tblemployee_nt_pk PRIMARY KEY (id)
);

CREATE TABLE tblemployee_nt$employee
(
   rowid uniqueidentifier DEFAULT NEWSEQUENTIALID(),
   firstname VARCHAR(100),
   lastname VARCHAR(100),
   hiredate VARCHAR(20),
   employee$id INT REFERENCES tblemployee_nt (id),
   PRIMARY KEY (rowid)
)

Member method is converted into procedure or function

PL/SQL

T-SQL

CREATE OR REPLACE TYPE BODY person_ot
AS
   MEMBER PROCEDURE update_hiredate (SELF IN OUT NOCOPY person_ot) IS
   BEGIN
     SELF.hiredate := SYSDATE;
   END;
END;

-- sample statement using the type member method
DECLARE
   person person_ot;
BEGIN
   person := person_ot('fname','lname',NULL);
   DBMS_OUTPUT.PUT_LINE('hiredate: ' || to_char(person.hiredate));
   person.update_hiredate;
   DBMS_OUTPUT.PUT_LINE('hiredate: ' || to_char(person.hiredate));
END;

ALTER TYPE person_ot ADD MEMBER PROCEDURE update_hiredate (SELF IN OUT NOCOPY person_ot);

CREATE PROCEDURE person_ot$proc_update_hiredate (@person_ot person_OT READONLY)
AS
DECLARE @person_ot_out person_ot
INSERT INTO @person_ot_out SELECT * FROM @person_ot
UPDATE @person_ot_out SET hiredate = getdate()
SELECT * FROM @person_ot_out
GO

-- sample statement to use the stored procedure
DECLARE
  @person person_ot;
BEGIN
  INSERT INTO @person (firstname, lastname, hiredate)
     VALUES ('fname','lname', NULL)

  SELECT 'hiredate: ' + hiredate FROM @person

  DECLARE @person_ot$proc_update_hiredate person_ot

  INSERT INTO @person_ot$proc_update_hiredate
  EXECUTE person_ot$proc_update_hiredate @person

  UPDATE old SET old.hiredate = new.hiredate
  FROM @person old
  JOIN @person_ot$proc_update_hiredate new on old.rowid = new.rowid

  SELECT 'hiredate: ' + hiredate FROM @person
END

Constructor method is converted into procedure

PL/SQL

T-SQL

CONSTRUCTOR FUNCTION person_ot
(
   firstname IN VARCHAR2,
   lastname IN VARCHAR2
)
RETURN SELF AS RESULT
IS
BEGIN
  SELF.firstname := firstname;
  SELF.lastname := lastname;
  SELF.hiredate := SYSDATE;
END;
 

CREATE PROCEDURE person_ot$constructor (@firstname VARCHAR(100), @lastname VARCHAR(100))
DECLARE @self person_ot
INSERT INTO @self (firstname, lastname, hiredate)
VALUES (@firstname, @lastname, GETDATE())
SELECT * FROM @self;
GO

-- sample statement to use the stored procedure
DECLARE @person person_ot
INSERT INTO @person
EXECUTE person_ot$constructor 'Anton', 'Okrut'
SELECT * FROM @person

Migrating Oracle to SQL Server using SSMA–Error O2SS0041 Illegal Identifier

$
0
0

When converting Oracle schema to SQL Server using SSMA, you may encounter an error when your table contains a DATE column with default value. This blog post describes the reason for the error and what you should do when you encounter this error.

Consider the following example

-- Oracle source table:
CREATE TABLE TEST.T1
(
      COL1 DATE DEFAULT to_date('01/02/2010 00:00:00', 'MM/DD/YYYY HH24:MI:SS'),
      COL2 DATE DEFAULT sysdate
);

-- Converted table using SSMA:
CREATE TABLE
[dbo].[t1]
(
   /*
   *   SSMA error messages:
   *   O2SS0041: Identifier 'sysdb.ssma_oracle.to_date2('01/02/2010 00:00:00', 'MM/DD/YYYY HH24:MI:SS')' cannot be prefixed with a database name in this context.
   */
   [COL1] datetime2(0)  NULL,
   [COL2] datetime2(0) DEFAULT sysdatetime()  NULL
)

SSMA converts Oracle’s to_date function with an emulator function (stored in SYSDB database when you install SQL Server Migration Assistant Extension Pack): sysdb.ssma_oracle.to_date.

The emulation function is used to ensure the date is stored according to the specified format. For example:

-- Oracle original statement
SELECT to_date('01/02/2010 00:00:00', 'DD/MM/YYYY HH24:MI:SS') FROM DUAL;

-- converting using SQL’s CAST statement will result in the following (using default SQL_Latin1_General_CP1_CI_AS collation)
SELECT CAST('01/02/2010 00:00:00' as datetime)
-- result: 2010-01-02 00:00:00.000 (January 2, 2010)

-- converting using SSMA emulator will result in the same value with Oracle (regardless database collation setting)
SELECT sysdb.ssma_oracle.to_date2('01/02/2100 00:00:00', 'DD/MM/YYYY HH24:MI:SS')
-- result: 2100-02-01 00:00:00.0000000 (February 1, 2010)

However, when to_date is used as default value in the table definition, the expression refers to the emulator function in a separate database – which is not permitted in SQL Server:

USE test2
GO
CREATE FUNCTION  dbo.fn_const(@const INT) RETURNS INT
AS
BEGIN
    RETURN @const
END
GO
USE test
go
CREATE FUNCTION  dbo.fn_const(@const INT) RETURNS INT
AS
BEGIN
    RETURN @const
END
Go
CREATE TABLE tbl1 (Col1 INT DEFAULT dbo.fn_const(1))
-- successfully created
CREATE TABLE tbl2 (col1 INT DEFAULT test2.dbo.fn_const(1))
/*
Msg 128, Level 15, State 1, Line 1
The name "test2" is not permitted in this context. Valid expressions are constants, constant expressions, and (in some contexts) variables. Column names are not permitted.
*/

When you encounter the SSMA error, you can proceed with the conversion and add the default value post conversion:

ALTER TABLE [dbo].[t1] ADD DEFAULT CAST('02/01/2010 00:00:00' AS DATETIME2) FOR [COL1]

Note that you have to make sure to set the default value with string format consistent with your collation setting.

Migrating Oracle Materialized View to SQL Server

$
0
0

By Gowri Shanker and Welly Lee.

This blog post discusses approaches to migrate Oracle Materialized View to SQL Server. We compare Materialized View with SQL Server Indexed View, discuss scenarios supported by Indexed View and provide suggestions you can consider for the non-supported scenarios.

Converting Materialized View to SQL Server

Oracle supports database object called Materialized View, which unlike a normal view, stores the result set of the query defining the view. The tables/views referred in the query are collectively called master tables. A materialized view can be described as a replica of the master table(s) from a single point in time. The data in the materialized view can be updated from the master tables through a process called Refresh. Oracle provides different refresh modes and interval options like automatic periodic refresh and on demand refresh for this purpose.

Common usage scenarios for materialized view include:

  1. Replicating data in a replication environment
  2. Caching result set of expensive queries in a data warehouse environment
  3. Tuning complex and long running queries to improve execution/response time.

A materialized view can be read-only, updateable and writable. Based on the environment they are used in, Oracle offers different types of materialized views including Primary Key materialized view (including sub-query materialized view), Object materialized view, ROWID materialized view, Complex Materialized view (like materialized join view and materialized aggregate view)etc.

SQL Server has Indexed view that can provide similar functionalities as a Materialized view. SQL Server supports creating an index on a view. Creating an index on a view, results in storage of logical data from the view into physical index files thereby materializing the query results.

The following is an example for creating indexed view:

OracleSQL Server

CREATE TABLE MAT_VIEW_MASTER_TABLE
(
COL1 NUMBER PRIMARY KEY,
COL2 VARCHAR2(25)
);

CREATE TABLE dbo.MAT_VIEW_MASTER_TABLE
(
COL1 INT PRIMARY KEY,
COL2 VARCHAR(25)
);

CREATE MATERIALIZED VIEW MAT_VIEW_1  
AS
SELECT COL1, COL2 FROM MAT_VIEW_MASTER_TABLE;

CREATE VIEW dbo.MAT_VIEW_1 WITH SCHEMABINDING
AS
SELECT COL1, COL2 FROM dbo.MAT_VIEW_MASTER_TABLE
GO

CREATE UNIQUE CLUSTERED INDEX MAT_VIEW_INDX_1 ON dbo.MAT_VIEW_1 (COL1)
GO

One key advantage of using Index View to convert Materialized view is that indexed views are dynamically refreshed by SQL Server itself whenever the base tables are updated so you do not need to define any refresh modes/periods. You should consider using Indexed View to convert Oracle Materialized View to SQL Server, however, please note the following requirements for Indexed View during conversion:

Referencing underlying database object(s)

Unlike Materialized View which can refer to any base table, view or another materialized view, SQL Indexed view can only refer to base tables. Moreover, Index view must be created with schema binding option to the underlying base table and the base table must be in the same database as the indexed view.

OracleSQL Server

CREATE VIEW VIEW_2
AS
SELECT COL1, COL2 FROM MAT_VIEW_MASTER_TABLE WHERE COL1 >= 1 AND COL1 <= 10;

 

CREATE MATERIALIZED VIEW MAT_VIEW_2
AS
SELECT COL1, COL2 FROM  VIEW_2 WHERE COL1 >=5 AND COL1 <= 8;

CREATE VIEW dbo.MAT_VIEW_2 WITH SCHEMABINDING
AS
/* Creating indexed view on another view is not supported.
Instead, convert materialized view into an indexed view by referring TO the base table directly.
*/
SELECT COL1, COL2 FROM dbo.MAT_VIEW_MASTER_TABLE
WHERE COL1 >= 5 AND COL1 <= 8
GO

CREATE UNIQUE CLUSTERED INDEX MAT_VIEW_INDX_2 ON dbo.MAT_VIEW_2 (COL1)
GO

Column with type of text, ntext, image can’t be referenced in the view.

Query Definition

The * or table_name.* syntax to specify columns is not allowed in SELECT statement of the view. Column names must be explicitly stated.

OracleSQL Server

CREATE MATERIALIZED VIEW MAT_VIEW_3
AS
SELECT * FROM MAT_VIEW_MASTER_TABLE
WHERE COL1 >=5 AND COL1 <= 8;

CREATE VIEW dbo.MAT_VIEW_3 WITH SCHEMABINDING
AS
/* Indexed View does not support query statement with SELECT *
Expand the SELECT * to refer to the column name of the table
*/
SELECT COL1, COL2 FROM dbo.MAT_VIEW_MASTER_TABLE
WHERE COL1 >= 5 AND COL1 <= 8
GO

CREATE UNIQUE CLUSTERED INDEX MAT_VIEW_INDX_3 ON dbo.MAT_VIEW_3 (COL1)
GO

The SELECT statement cannot contain:

  • Common Table Expression (CTE)
  • UNION, EXCEPT or INTERSECT operators
  • Sub-queries
  • Outer or self joins
  • TOP clause
  • ORDER BY clause
  • DISTINCT keyword
  • COUNT (COUNT_BIG(*) is allowed.)
  • AVG, MAX, MIN, STDEV, STDEVP, VAR, or VARP aggregate functions

If GROUP BY is specified, the select list must contain a COUNT_BIG(*) expression, and the view definition cannot specify HAVING, ROLLUP, CUBE, or GROUPING SETS

OracleSQL Server

CREATE MATERIALIZED VIEW MAT_VIEW_4
AS
SELECT SUM(COL1) AS TOTAL, COL2 AS COL2 FROM MAT_VIEW_MASTER_TABLE
GROUP BY COL2;

CREATE VIEW dbo.MAT_VIEW_4 WITH SCHEMABINDING
AS
/* SELECT statement with GROUP BY must include COUNT_BIG(*) expression
*/
SELECT SUM(COL1) AS TOTAL, COL2 AS COL2, COUNT_BIG(*) AS CBIG FROM dbo.MAT_VIEW_MASTER_TABLE
GROUP BY COL2
GO

CREATE UNIQUE CLUSTERED INDEX MAT_VIEW_INDX_4 ON dbo.MAT_VIEW_4 (COL2)
GO

Index Creation

In order to create an indexed view, a unique clustered must first be created. Additional non-clustered index(es) can be created. If the index is dropped, the stored result set is removed and the view is processed as a normal view.

If the SELECT statement in the view definition specifies a GROUP BY clause, the key of the unique clustered index can reference only columns specified in the GROUP BY clause.

OracleSQL Server

CREATE MATERIALIZED VIEW MAT_VIEW_5
AS
SELECT SUM(COL1) AS TOTAL, COL2 AS COL2 FROM MAT_VIEW_MASTER_TABLE
GROUP BY COL2;

CREATE VIEW dbo.MAT_VIEW_5 WITH SCHEMABINDING
AS
SELECT SUM(COL1) AS TOTAL, COL2 AS COL2, COUNT_BIG(*) AS CBIG FROM dbo.MAT_VIEW_MASTER_TABLE
GROUP BY COL2
GO

/* Index is created on the column referred in the GROUP BY
*/
CREATE UNIQUE CLUSTERED INDEX MAT_VIEW_INDX_5 ON dbo.MAT_VIEW_5 (COL2)
GO

 

Special Case: NEVER REFRESH Materialized View

There may be cases where Oracle Materialized view could be setup with NEVER REFRESH clause. This prevents the view from being refreshed by any refresh mechanisms. Such cases can be converted to standalone tables in SQL Server.

OracleSQL Server

CREATE MATERIALIZED VIEW MAT_VIEW_6 NEVER REFRESH
AS
SELECT COL1, COL2 FROM MAT_VIEW_MASTER_TABLE;

SELECT COL1, COL2 INTO MAT_VIEW_6 FROM MAT_VIEW_MASTER_TABLE

Concluding Thought

Materialized View should be converted to Index View during migration to SQL Server. In addition to providing dynamic data refresh advantage, creating an indexed view can also improve query against the underlying table(s). SQL Server query processor can refer to the indexed view to determine the query plan even if the query does not explicitly refer to the view. In the case where the Materialized View can’t be converted to Indexed View, you should consider simplify the query, else create a standalone table and create a stored procedure to synchronize values in the table

One last note, Oracle creates an internal table with the same name as the materialized view for storing the snapshot. SSMA for Oracle actually loads this and converts it as a standalone table. If the approach of converting materialized view to standalone table is not the one followed, then you need to exclude this internal table when converting Oracle schema using SSMA

Reference

SQL Server Books Online: Creating Indexed View

Migrating Oracle ANYDATA to SQL Server

$
0
0

By Welly Lee, Pinaki Bag, and Jayakumar Tanneru.

Oracle has an object data type called anydata. This data type supports wide range of data types. For example when creating a table with a column defined as anydata type, the column can store many types of data from string to numeric . SSMA does not support migration of anydata and when migrating Oracle database containing the type, SSMA raise a migration error O2SS0005: Source datatype not recognized.

SQL Server has a similar data type called sql_variant. sql_variant provides simpler data management and provide additional capabilities:

  1. Oracle anydata is an object type that includes static and member procedures and functions. Using anydata type requires the use of convert function to store and an utility function to retrieve the value. sql_variant stores data value directly and values can be retrieved without explicit conversion.

    Oracle

    SQL Server

    CREATE TABLE tbl1 (col1 anydata);

    CREATE TABLE tbl1 (col1 sql_variant)

    INSERT INTO tbl1 (col1) VALUES (sys.anydata.convertnumber(123.4));

    INSERT INTO tbl1 (col1) VALUES (123.4)

    INSERT INTO tbl1 (col1) VALUES (sys.anydata.convertvarchar2('abc'));

    INSERT INTO tbl1 (col1) VALUES ('abc')

    INSERT INTO tbl1 (col1) VALUES (sys.anydata.convertdate(sysdate));

    INSERT INTO tbl1 (col1) VALUES (getdate())


    SELECT * FROM tbl1;

    COL1()
    -------------------------------
    ANYDATA()
    ANYDATA()
    ANYDATA() 

    /* anydata values can be retrieving by using function such as described in this article */

    SELECT getData(col1) FROM tbl1;

    GETDATA(COL1)
    ---------------------------------
    123.4
    abc
    21-JUN-11

    SELECT * FROM tbl1

    Col1
    --------------------
    123.4
    abc
    2011-06-21 00:00:00.001

    /* note that a sql_variant data type must first be cast to its base data type value before participating in operations such as addition and subtraction. For example: */

    DECLARE @var sql_variant
    SET @var = 2
    SELECT CONVERT(int,@var) - 1
  2. Index cannot be created on the column with anydata type. sql_variant column can be included in the index (as long as the value does not exceed 900 bytes).

    -- Sample SQL Server statement:
    CREATE INDEX idx_test ON tbl1 (col1)
  3. sql_variant can be assigned a default value. This data type can also have NULL as its underlying value, but the NULL values will not have an associated base type.

    -- Sample SQL Server statements:
    CREATE TABLE tbl2 (col1 int, col2 sql_variant DEFAULT 'some value')
    CREATE TABLE tbl3 (col1 int, col2 sql_variant DEFAULT NULL)

For many cases, sql_variant can be used to replace anydata type when migrating Oracle to SQL Server. However, note the following limitation:

  1. sql_variant supports smaller size and fewer data types. sql_variant can have a maximum length of 8016 bytes. This includes both the base type information and the base type value. The maximum length of the actual base type value is 8,000 bytes. sql_variant also have limitation for supporting the following types:
    Oracle Data TypeComparable SQL Server Data Type
    rawvarbinary(max)
    blobvarbinary(max)
    cblobvarchar(max)
    bfileFILESTREAM storage
    user defined typeuser defined type
    timestamptimestamp/datetime2
    interval 
    spatial (geography/geometry)spatial (geography/geometry)
    xmltypexml
  2. ODBC does not fully support sql_variant. Therefore, queries of sql_variant columns are returned as binary data when you use Microsoft OLE DB Provider for ODBC (MSDASQL).

If you are unable to use sql_variant due to the technical limitation above, you may consider to migrate the anydata as separate columns based on its individual types (SQL Server 2008 supports Sparse Column to optimize storing data across multiple columns with many NULL values). Alternatively, you can also consider to convert anydata to xml type (note the limitations of xml data type)

-- Sample SQL Server Statements:
CREATE TABLE tbl1 (col1 xml)
INSERT INTO tbl1 VALUES ('<root><data>123.4</data><datatype>decimal(13,5)</datatype></root>')
INSERT INTO tbl1 VALUES ('<root><data>abc</data><datatype>varchar(max)</datatype></root>')
INSERT INTO tbl1 VALUES ('<root><data>'+cast(getdate() as varchar(max))+'</data><datatype>datetime</datatype></root>')

SELECT col1.value('(/root/data)[1]','varchar(max)') from tbl1  -- returning data values
SELECT col1.value('(/root/datatype)[1]','varchar(max)') from tbl1  -- returning data types

REFERENCE

SQL Server 2008R2 Books Online : sql_variant

Emulating Records and Collections via CLR UDT

$
0
0

        By Bill Ramos and Vishal Soni, Advaiya Inc.

This blog covers how the SQL Server Migration Assistant (SSMA) for Oracle uses the SQL Server Common Language Runtime (CLR) User-Defined Types (UDT) for emulating Oracle Records and Collections. 

In this blog, we will cover the following topics related to CLR UDTs:

o    Declaring Record or Collection Types and Variables

o    Constructor Calls Conversions

o    Referencing and Assigning Record and Collection Elements

o    Collection Built-in Methods

o    Project Settings for Records

Note: The content for this blog is extracted and refined from the Migrating Oracle to SQL Server 2008 White Paper

Declaring Record or Collection Types and Variables

SSMA creates three CLR-based UDTs:

·         CollectionIndexInt

·         CollectionIndexString

·         Record

The CollectionIndexInt type is intended for emulating collections indexed by integer, such as VARRAYs, nested tables, and integer key based associative arrays. The CollectionIndexString type is used for associative arrays indexed by character keys. The Oracle record functionality is emulated by the Record type.

All declarations of the record or collection types are converted to this Transact-SQL declaration:

declare @Collection$TYPE varchar(max) = ’<type definition>’ 

Here <type definition> is a descriptive text uniquely identifying the source PL/SQL type.

Consider the following example:

Oracle

 

Declare

TYPE Manager ISRECORD (mgrid integer, mgrname varchar2(40), hiredate date);

TYPE Manager_table isTABLEOF Manager INDEXBYPLS_INTEGER;

 

Mgr_rec Manager;

Mgr_table_rec Manager_table;

Begin

     mgr_rec.mgrid := 1;

     mgr_rec.mgrname := 'Mike';

     mgr_rec.hiredate := sysdate;

 

     select empno, ename, hiredate

     BULKCOLLECTINTO mgr_table_rec

     from emp;

End;

 

SQL Server

BEGIN

   DECLARE

      @CollectionIndexInt$TYPE varchar(max) = ' TABLE INDEX BY INT OF ( RECORD ( MGRID INT , MGRNAME STRING , HIREDATE DATETIME ) )'

 

   DECLARE

      @Mgr_rec$mgrid int,

      @Mgr_rec$mgrname varchar(40),

      @Mgr_rec$hiredate datetime2(0),

      @Mgr_table_rec dbo.CollectionIndexInt = dbo.CollectionIndexInt ::[Null].SetType(@CollectionIndexInt$TYPE)

 

   SET @mgr_rec$mgrid = 1

   SET @mgr_rec$mgrname = 'Mike'

   SET @mgr_rec$hiredate = sysdatetime()

   SET @mgr_table_rec = @mgr_table_rec.RemoveAll()

   SET @mgr_table_rec = @mgr_table_rec.AssignData(sysdb.ssma_oracle.fn_bulk_collect2CollectionComplex(

      (

         SELECTCAST(EMP.EMPNO AS int) AS mgrid, EMP.ENAME AS mgrname, EMP.HIREDATE AS hiredate

         FROM dbo.EMP

         FORXMLPATH

      )))

END

GO

 

Here, since the Manager table is associated with a numeric index (INDEXBYPLS_INTEGER), the corresponding T-SQL declaration used is of type @CollectionIndexInt$TYPE.

 

Oracle

TYPE Manager_table isTABLEOF Manager INDEXBYPLS_INTEGER;

 


 

SQL

@CollectionIndexInt$TYPE varchar(max) = ' TABLE INDEX BY INT OF ( RECORD ( MGRID INT , MGRNAME STRING , HIREDATE DATETIME ) )'

 

If the table was associated with a character set index, like VARCHAR2, the corresponding T-SQL declaration would be of type@CollectionIndexString$TYPE.

 

Oracle:

TYPE Manager_table isTABLEOF Manager INDEXBYVARCHAR2(40);

SQL:

@CollectionIndexString$TYPE varchar(max) = ' TABLE INDEX BY STRING OF ( RECORD ( MGRID INT , MGRNAME STRING , HIREDATE DATETIME ) )'

 

The Oracle record functionality is emulated by the Record type only.

Each of the types, CollectionIndexInt, CollectionIndexString, and Record, has a static property [Null] returning an empty instance. The SetType method is called to receive an empty object of a specific type (as seen in the above example).

Constructor Calls Conversions

Constructor notation can be used only for nested tables and VARRAYs, so all the explicit constructor calls are converted using the CollectionIndexInt type. Empty constructor calls are converted via SetType call invoked on null instance of CollectionIndexInt. The [Null] property returns the null instance. If the constructor contains a list of elements, special method calls are applied sequentially to add the value to the collection.

For example:

Oracle

 

DECLARE

   TYPE nested_type ISTABLEOFVARCHAR2(20);

   TYPE varray_type ISVARRAY(5) OFINTEGER;

   v1 nested_type;

   v2 varray_type;

BEGIN

   v1 := nested_type('Arbitrary','number','of','strings');

   v2 := varray_type(10, 20, 40, 80, 160);

END;

SQL Server

 

BEGIN

 

   DECLARE

      @CollectionIndexInt$TYPE varchar(max) = ' VARRAY OF INT',

      @CollectionIndexInt$TYPE$2 varchar(max) = ' TABLE OF STRING',

      @v1 dbo.CollectionIndexInt,

      @v2 dbo.CollectionIndexInt

 

   SET @v1 = dbo.CollectionIndexInt ::[Null].SetType(@CollectionIndexInt$TYPE$2).AddString('Arbitrary').AddString('number').AddString('of').AddString('strings')

 

   SET @v2 = dbo.CollectionIndexInt ::[Null].SetType(@CollectionIndexInt$TYPE).AddInt(10).AddInt(20).AddInt(40).AddInt(80).AddInt(160)

 

END

GO

Referencing and Assigning Record and Collection Elements

Each of the UDTs has a set of methods working with elements of the various data types. For a detailed list of all the methods, please refer Migrating Oracle to SQL Server 2008 White Paper(‘Migrating Oracle Records and Collections’ section).

Collection Built-in Methods

A detailed list of various built-in collection methods is available in the Migrating Oracle to SQL Server 2008 White Paper(‘Migrating Oracle Records and Collections’ section).

BULK COLLECT operation

SSMA converts BULK COLLECT INTO statements into SQL Server SELECT … FOR XML PATH statement, whose result is wrapped into one of the following functions:

sysdb.ssma_oracle.fn_bulk_collect2CollectionSimple sysdb.ssma_oracle.fn_bulk_collect2CollectionComplex

 

The choice depends on the type of the target object. These functions return XML values that can be parsed by the CollectionIndexInt, CollectionIndexString, and Record types. A special AssignData function assigns XML-based collection to the UDT.

SSMA recognizes three kinds of BULK COLLECT INTO statements:

1.       The collection containing elements with scalar types, and the SELECT list containing one column:

Oracle

SELECT column_name_1

  BULK COLLECT INTO <collection_name_1>  FROM <data_source>

SQL Server

SET @<collection_name_1>  = @<collection_name_1>.AssignData(sysdb.ssma_oracle.fn_bulk_
collect2CollectionSimple((select column_name_1 from <data_source> for xml path)))

 

For example:

Oracle Code:

select empno, ename, hiredate

     BULKCOLLECTINTO mgr_table_rec

 

Results into the following T_SQL statements:

SQL Code:

SELECTCAST(EMP.EMPNO AS int) AS mgrid, EMP.ENAME AS mgrname, EMP.HIREDATE AS hiredate

      FROM dbo.EMP

FORXMLPATH

 

2.       The collection containing elements with record types, and the SELECT list containing one column:

Oracle

SELECT column_name_1[, column_name_2...]

  BULK COLLECT INTO <collection_name_1>  FROM <data_source>

 

SQL Server

SET @<collection_name_1> = @<collection_name_1>.AssignData(sysdb.ssma_oracle.fn_bulk_
collect2CollectionComplex((select column_name_1 as [collection_name_1_element_field_name_1], column_name_2 as [collection_name_1_element_field_name_2] from <data_source> for xml path)))

 

3.       The collection containing elements with scalar type, and the SELECT list containing multiple columns:

Oracle

SELECT column_name_1[, column_name_2 ...]

  BULK COLLECT INTO <collection_name_1>[, <collection_name_2> ...]

  FROM <data_source>

 

SQL Server:

;with bulkC as (select column_name_1 [collection_name_1_element_field_name_1], column_name_2 [collection_name_1_element_field_name_2] from <data_source>)

select @<collection_name_1> = @<collection_name_1>.AssignData(sysdb.ssma_oracle.fn_bulk_
collect2CollectionSimple((select [collection_name_1_element_field_name_1] from bulkC for xml path))),

@<collection_name_2> = @<collection_name_2>.AssignData(sysdb.ssma_oracle.fn_bulk_
collect2CollectionSimple ((select [collection_name_1_element_field_name_2] from bulkC for xml path)))

Project Settings for Records

When the result of the Oracle query is saved in a PL/SQL record variable, you have two options depending on the SSMA setting for Convert record as a list of separated variables. If the value of this setting is Yes (the default), then SSMA does not create an instance of the Record type. Instead, it splits the record into the constituting fields by creating a separate Transact-SQL variable per each record field. If the setting is No, the record is instantiated and each field is assigned a value using Set methods.

clip_image002

References

For more information, check out the following references:

 

Converting Oracle Sequence to SQL Server "Denali"

$
0
0

Updated 2/7/2012 Jiafei Yuan - Microsoft SQL Server Migration Assistant (SSMA) for Oracle v5.2.  The information provided below is still valid for SSMA for Oracle v5.2, but SQL Server "Denali" is changed to 2012.  Users should download the lastest SSMA for Oracle]

One of the new feature in SQL Server Migration Assistant (SSMA) for Oracle v5.1 is the support for converting Oracle sequence to SQL Server “Denali” sequences. Although the functionalities are similar with Oracle’s sequence, there are a few differences. This blog article describes the differences and how SSMA handle those during conversion.

Data Type

SQL Server, by default, uses INTEGER data type to define sequence value. The maximum number supported with INTEGER type is 2147483647. Oracle supports 28 digit of integer value in its sequence implementation. On the other hand, SQL Server supports different data types when creating sequence.  When migrating Sequence from Oracle, SSMA migrate Sequence from Oracle by creating sequence object in SQL Server with type of NUMERIC(28). This is to ensure that the converted sequence can store all possible values from the original sequence object in Oracle.

OracleSQL Server
CREATE SEQUENCE MySequence;CREATE SEQUENCE MySequence AS numeric (28,0) 
CREATE TABLE MyTable (id NUMBER, text VARCHAR2(50));CREATE TABLE MyTable (id float, text VARCHAR(50))

INSERT INTO MyTable (id, text)
VALUES (MySequence.NEXTVAL,  'abc');

INSERT INTO MyTable (id, text) VALUES (NEXT VALUE FOR MySequence, 'abc')
UPDATE MyTable SET id=MySequence.NEXTVAL WHERE id = 1;UPDATE MyTable SET id= NEXT VALUE FOR MySequence WHERE id = 1
Starting Value

Unless explicitly defined, SQL Server create sequence with starting number of the lowest number in the data type range. For example, when using simple CREATE SEQUENCE MySequence, SQL Server “Denali” creates a sequence with starting value of -2147483648, as supposed in Oracle which uses default starting value of 1.

Another migration challenge is how to maintain continuity after the database migration, so the next sequence generated after migration to SQL Server is consistent with that of Oracle. SSMA creates SQL Server sequence using START WITH property using Oracle sequence's last_number property to resolve this challenge. 

OracleSQL Server
CREATE SEQUENCE MySequence; -- last_number is 10

CREATE SEQUENCE MySequence AS numeric (28,0)   START WITH 10;

Maximum CACHE Value

Oracle supports 28 digit of positive integer for CACHE. SQL Server supports up to 2147483647 for CACHE property value (even when the SEQUENCE is created with data type of NUMERIC(28)).

SSMA sets CACHE to the maximum supported value if the CACHE value in Oracle is set greater than 2147483647.

OracleSQL Server
CREATE SEQUENCE MySequence CACHE 2147483648;

CREATE SEQUENCE MySequence AS numeric (28,0)   START WITH 10 CACHE 2147483647;

ORDER|NOORDER Property

SQL Server does not support ORDER|NOORDER property in sequence.  SSMA ignores this property when migrating sequence object.

OracleSQL Server
CREATE SEQUENCE MySequence NOORDER;

CREATE SEQUENCE MySequence AS numeric (28,0)   START WITH 10;

CURRVAL

SQL Server does not support obtaining current value of a sequence. You can lookup current_value attribute from sys.sequences. However, note that the current_value represent global value of sequence (across all sessions). Oracle's CURRVAL returns the current value for each session. Consider the following example:

Session 1 (Oracle)Session 2 (Oracle)

SELECT MySequence.nextval FROM dual;

NEXTVAL
------------
1

 

SELECT MySequence.currval FROM dual;

CURRVAL
------------
1

 
 

SELECT MySequence.nextval FROM dual;

NEXTVAL
------------
2

 

SELECT MySequence.currval FROM dual;

CURRVAL
------------
2

SELECT MySequence.currval FROM dual;

CURRVAL
------------
1

 

The current_value from sys.sequence record the latest value across all session. Hence, in the example above, the current_value is the same for any sessions (current_value = 2).

When converting  PL/SQL statement containing CURRVAL to SQL Server Denali, SSMA generates the following error:

*   SSMA error messages:
*   O2SS0490: Conversion of identifier <sequence name> for CURRVAL is not supported.

When you encounter this error, you should consider rewriting your statement by storing next sequence value into a variable then read the variable value as current value. For example:

OracleSQL Server

CREATE PROCEDURE create_employee (Name_in IN NVARCHAR2,  EmployeeID_out OUT NUMBER) AS
BEGIN

   INSERT INTO employees (employeeID, Name)
   VALUES (employee_seq.nextval, Name_in);

   SELECT employee_seq.currval INTO EmployeeID_out FROM dual;

END;

CREATE PROCEDURE create_employee @Name_in NVARCHAR(50),  @EmployeeID_out INT OUT AS

   SET @EmployeeID_out = NEXT VALUE FOR employee_seq

   INSERT INTO employees (employeeID, Name)
   VALUES (@EmployeeID_out, @Name_in)

If you are using CURRVAL extensively in your application and rewriting all statements with CURRVAL is not possible, a alternative approach is to convert Oracle Sequence to SSMA custom sequence emulator. When migrating to SQL Server prior to "Denali", SSMA converts Oracle sequence using custom sequence emulator. You can use this conversion approach when migrating to SQL Server "Denali" (which support conversion of CURRVAL) by changing the SSMA project setting (Tools > Project Settings > General > Conversion > Sequence Conversion).

image


Microsoft SQL Server Migration Assistant (SSMA) 5.2 is Now Available

$
0
0

Automating Database Migration to SQL Server 2012

SQL Server Migration Assistant (SSMA) v5.2 is now available. SSMA simplifies database migration process from Oracle/Sybase/MySQL and Microsoft Access to SQL Server and SQL Azure. SSMA automates all aspects of migration including migration assessment analysis, schema and SQL statement conversion, data migration as well as migration testing to reduce cost and reduce risk of your database migration project. 

The new version of SSMA - SSMA 5.2 provides the following major enhancements:

  • Support conversion of Oracle %ROWTYPE parameters with NULL default
  • Support conversion of Sybase’s Rollback Trigger
  • Better user credential security to support Microsoft Access Linked Tables

Download SQL Server Migration Assistant (SSMA) v.5.2

Launch the download of the SSMA for Oracle.

Launch the download of the SSMA for Sybase.

Launch the download of the SSMA for MySQL.

Launch the download of the SSMA for Access.

Microsoft SQL Server Migration Assistant (SSMA) v5.3 is now available.

$
0
0

SSMA simplifies database migration process from Oracle/Sybase/MySQL and Microsoft Access to SQL Server and SQL Azure. SSMA automates all aspects of migration including migration assessment analysis, schema and SQL statement conversion, data migration as well as migration testing to reduce cost and reduce risk of your database migration project. 

The new version of SSMA - SSMA 5.3 provides the following major enhancements:

  • Support of Migration to MS SQL Server 2014.
  • Improved conversion mechanism when migrating to Azure.
  • New features in the Migration GUI.
  • No requirement to get a License key to start using SSMA.

 

Download SQL Server Migration Assistant (SSMA) v.5.3 :

 

Launch the download of the SSMA for Oracle.

Launch the download of the SSMA for Sybase.

 

Launch the download of the SSMA for MySQL.

 

Launch the download of the SSMA for Access.

 

 

 

The SSMA product team is available to answer your questions and provide limited technical support. Contact the team at ssmahelp@microsoft.com

 

Latest Update - Microsoft SQL Server Migration Assistant (SSMA) v6.0 is now available.

$
0
0

SSMA simplifies database migration process from Oracle/Sybase/MySQL and Microsoft Access to SQL Server and SQL Azure. SSMA automates all aspects of migration including migration assessment analysis, schema and SQL statement conversion, data migration as well as migration testing to reduce cost and reduce risk of your database migration project. 

 

The new version of  SSMA, Version  6.0 provides the following major enhancements:

 

  • Materialized View support for Oracle

  • Memory Optimized tables for Oracle
  • Improved Azure SQL DB code conversion
  • Extension pack functionality moved to schema to support Azure SQL DB
  • Performance improvements tested for databases with over 10k objects
  • UI improvements for dealing with large number of objects
  • Highlighting of “well known” LOB schemas (so they can be ignored in conversion)
  • Conversion speed improvements
  • Show object counts in UI
  • Report size reduction by more than 25%
  • Improved error messages for unparsed constructs.

 

 Download SQL Server Migration Assistant (SSMA) v.6.0

 

SSMA for Access:  http://www.microsoft.com/en-us/download/details.aspx?id=43690

SSMA for MySQL: http://www.microsoft.com/en-us/download/details.aspx?id=43688

SSMA for Oracle:  http://www.microsoft.com/en-us/download/details.aspx?id=43689

SSMA for Sybase: http://www.microsoft.com/en-us/download/details.aspx?id=43691

 

 

On the closing note , Yes ! We've heard several of your valuable feedbacks / inputs. Thank you... and we're rolling out with the SSMA for DB2 very soon. Watch out this space for more information.

 

The SSMA product team is available to answer your questions and provide technical support related to SSMA. Contact the team at ssmahelp@microsoft.com

Securing MS Linked Tables Connection Strings During Migration

$
0
0

Microsoft Access stores all the connection strings for the respective linked tables in a system table called MSysObjects.  As seen below, the connection strings contain clear-text used id and password.  With the release for SSMA for Access 5.2, when creating link tables during migration, users will now have the option to not store the user id and password for the linked tables.

A new setting for linked tables can be found under the Project Settings menu.    By default, the Store user credentials setting is set to false, thus user id and password will not be persisted in the connection string of a linked table.  Switching the setting to true would provide the option to store the user id and password in the connection strings during the creation of linked tables.

It is important to note that after securing the connection string, MS Access users will have to enter the required user id and password whenever the linked tables are referenced in the MS Access Database application.  Below shows the prompt presented by MS Access.

 

 

 

Procedures/Functions with ROWTYPE Parameters Defaulted to NULL

$
0
0

The %ROWTYPE attribute in Oracle defines the particular record type of a row in a table.   A common usage of %ROWTYPE attribute is to have variables declared as ROWTYPE of a table to transfer data in and out of a procedure or function.  An IN ROWTYPE parameter of a function or procedure can be set with a default value.  Often, the IN ROWTYPE parameter is defaulted to NULL.  For example,

PROCEDURE proc_foo_rowtype( 
row_a employees%ROWTYPE DEFAULT NULL )
IS
BEGIN
DBMS_OUTPUT.PUT_LINE('ID = ' || NVL(TO_CHAR(row_a.employeeID), 'NULL'));
DBMS_OUTPUT.PUT_LINE('NAME = ' || NVL(TO_CHAR(row_a.firstName), 'NULL'));
END proc_foo_rowtype;

Given the example above, employee table has two rows: employeeID and firstName.  When the convert record as a list of separated variables (found under Record conversion in Project Settings for SSMA for Oracle) is set to Yes, SSMA will create separate parameters for each row of the employees table.

PROCEDURE dbo.PROC_FOO_ROWTYPE 
@row_a$EMPLOYEEID float(53) = NULL,
@row_a$FIRSTNAME nvarchar(max) = NULL
AS
BEGIN
PRINT 'ID = ' + isnull(CAST(@row_a$EMPLOYEEID AS varchar(max)), 'NULL')
PRINT 'NAME = ' + isnull(CAST(@row_a$FIRSTNAME AS varchar(max)), 'NULL')
END

Note that when the ROWTYPE parameter is defaulted to NULL, SSMA will also have the converted parameters default to NULL as shown above.     

Now, let’s have a little fun by having a ROWTYPE parameter in a nested procedure.  Here’s an example:

PROCEDURE PROC_FOO_OUTER 
IS
empRow employees%ROWTYPE;
 procedure proc_foo_inner( 
row_a IN employees%ROWTYPE default null)
IS

BEGIN
DBMS_OUTPUT.PUT_LINE(‘First name = ' || NVL(TO_CHAR(row_a.FirstName), 'NULL'));
DBMS_OUTPUT.PUT_LINE(‘Last Name = ' || NVL(TO_CHAR(row_a.LastName), 'NULL'));
END proc_foo_inner;
BEGIN 
empRow.LastName := 'Smith';
empRow.FirstName := 'John';

proc_foo_inner();
proc_foo_inner(empRow);

END PROC_FOO_OUTER;
                        

This example is quite straightforward.    Let’s assume there is an employee table with FirstName and LastName columns of nvarchar2(20) and nvarchar2(40) respectively.   The executing this procedure in Oracle would the following result:

First name = NULL

Last name = NULL

First name = John

Last name = Smith

 Now, let’s convert this procedure to SQL Server 2012 using SSMA for Oracle.  We will set the following settings in SSMA as such

  • ·         local modules conversion is set to Inline
  • ·         convert record as a list of separated variables set to Yes

The first setting is to convert the inner procedure into nested block Begin..End.  The second setting will create separate variables for FirstName and LastName.

Below is the result of the conversion.  There are two nested blocks corresponding to the respective inner procedures.  Each nested block contains its own variables for LastName and FirstName.   For the block representing proc_foo_inner(), the two variables are set to NULL.  For the block representing proc_foo_inner(empRow), the variables are set to the proper empRow values.

PROCEDURE dbo.PROC_FOO_OUTER 
AS
BEGIN

DECLARE
@empRow$LASTNAME nvarchar(40),
@empRow$FIRSTNAME nvarchar(20),


SET @empRow$LASTNAME = 'Smith'
SET @empRow$FIRSTNAME = 'John'

BEGIN /* proc_foo_inner() */
DECLARE
@proc_foo_inner$row_a$LASTNAME nvarchar(max)

DECLARE
@proc_foo_inner$row_a$FIRSTNAME nvarchar(max)

SET @proc_foo_inner$row_a$LASTNAME = NULL
SET @proc_foo_inner$row_a$FIRSTNAME = NULL

BEGIN
PRINT 'Last name = ' + isnull(CAST(@proc_foo_inner$row_a$FIRSTNAME AS varchar(max)), 'NULL')
PRINT 'First Name = ' + isnull(CAST(@proc_foo_inner$row_a$LASTNAME AS varchar(max)), 'NULL')
END
END
BEGIN /* proc_foo_inner(empRow) */ 
DECLARE
@proc_foo_inner$row_a$LASTNAME$2 nvarchar(max)

DECLARE
@proc_foo_inner$row_a$FIRSTNAME$2 nvarchar(max)


SET @proc_foo_inner$row_a$LASTNAME$2 = @empRow$LASTNAME
SET @proc_foo_inner$row_a$FIRSTNAME$2 = @empRow$FIRSTNAME

BEGIN
PRINT 'Last name = ' + isnull(CAST(@proc_foo_inner$row_a$FIRSTNAME$2 AS varchar(max)), 'NULL')
PRINT 'First Name = ' + isnull(CAST(@proc_foo_inner$row_a$LASTNAME$2 AS varchar(max)), 'NULL')
END
END
END
Viewing all 29 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>