Top 10 Cool New Features in SAP® Sybase® SQL Anywhere® 16
Total Page:16
File Type:pdf, Size:1020Kb
Top 10 Cool New Features In SAP® Sybase® SQL Anywhere® 16 By: Breck Carter Introduction SAP Sybase SQL Anywhere 16 is the first new release of SAP Sybase SQL Anywhere since version 12 in 2010... that’s a pretty good track record, skipping over one version number per year for three years. It is possible that version numbers 13 and 14 were passed over for the usual reasons of triskaidekaphobia and tetraphobia (fear of the numbers 13 and 4), and it is also possible that number 15 was skipped because it’s been used by SAP Sybase ASE since, well, forever, and SAP Sybase SQL Anywhere 15 would perpetuate the myth that SQL Anywhere and ASE are somehow related. So, we’ve got SAP Sybase SQL Anywhere 16, what’s cool about it? Well, first of all, for the record, it’s got all the same cool stuff found in version 12, nothing big has been jettisoned, not even SQL Remote (so many folks fret about that, having been burned by other vendors forcing Upgrade Death Marches of dubious value). Performance is improved, but that’s not discussed in this article because (a) the performance enhancements are covered in the documentation, (b) it’s too early to tell exactly what the effects are, and (c) without a Woohoo! case study or two to drive home the point I would just be reading the Help to you. Another big new feature in SQL Anywhere 16 is the Role-Based Security Model, a breathtaking revision of GRANT and REVOKE involving seven new and replaced SQL statements, six new system procedures, six new database and server options, and a whole new way of looking at things: “Whereas before you had authorities, permissions, object-level permissions, and groups, you now have roles, system privileges, object-level privileges, and user-extended roles.” The release-defining Role-Based Security Model isn’t fully covered in this article because, frankly, it’s just too big to fit... but, one component has been plucked from within it: the two- person password change process is found only in SAP Sybase SQL Anywhere 16, nowhere else, not in Oracle or SQL Server or any other relational database. © 2013 SAP AG or an SAP affiliate company. All rights reserved. Now, here’s the Top 10 list of cool new features in SAP Sybase SQL Anywhere 16: 1. ROWs The new ROW data type is tied with ARRAY for the title of Number One Cool New Feature In SAP Sybase SQL Anywhere 16. ROW lets you DECLARE structure-like variables in SQL scripts, and pass them as single arguments in procedure CALL statements to represent multiple fields. Here’s an example: CREATE PROCEDURE p ( pr ROW ( field1 INTEGER, field2 INTEGER, field3 INTEGER ) ) BEGIN SELECT pr.field1, pr.field2, pr.field3; END; BEGIN DECLARE r ROW ( field1 INTEGER, field2 INTEGER, field3 INTEGER ); SET r.field1 = 1; SET r.field2 = 2; SET r.field3 = 3; CALL p ( r ); END; field1 field2 field3 ----------- ----------- ----------- 1 2 3 The ROW() constructor can be used to fill a row all-in-one-go like this: DECLARE r ROW ( field1 INTEGER, field2 INTEGER, field3 INTEGER ); SET r = ROW ( 1, 2, 3 ); SELECT r.field1, r.field2, r.field3; field1 field2 field3 ----------- ----------- ----------- 1 2 3 © 2013 SAP AG or an SAP affiliate company. All rights reserved. 2 ROW variables can be nested inside other ROWs, and so can calls to the ROW() constructor, like this: BEGIN DECLARE r ROW ( field1 INTEGER, s ROW ( field2 INTEGER, field3 INTEGER, field4 INTEGER ), field5 INTEGER ); SET r = ROW ( 1, ROW ( 2, 3, 4 ), 5 ); SELECT r.field1, ( r ).s.field2, ( r ).s.field3, ( r ).s.field4, r.field5; END; field1 expression expression expression field5 ----------- ----------- ----------- ----------- ----------- 1 2 3 4 5 One thing that’ll take some getting used to is the funky syntax for fields-within-fields: SELECT ( r ).s.field2 works OK, but SELECT r.s.field2 gives SQLCODE -142 Correlation name ’s’ not found. In one sense, a ROW is like a structure, but in another sense a ROW is like a row, as in a row in a table because you can use SELECT to build a ROW(): BEGIN DECLARE Dept_row ROW ( DeptID INTEGER, DeptName VARCHAR ( 20 ), DeptHeadID INTEGER ); SET Dept_row = ROW ( SELECT DepartmentID, DepartmentName, DepartmentHeadID FROM Departments WHERE DepartmentID = 100 ); SELECT Dept_row.DeptID, Dept_row.DeptName, Dept_row.DeptHeadID; END; DeptID DeptName DeptHeadID ----------- -------------------- ----------- 100 R & D 501 © 2013 SAP AG or an SAP affiliate company. All rights reserved. 3 The bad news comes in the form of SQLCODE -1599, which means “You tried to use an ARRAY or ROW type in an unsupported context. You cannot store these values in tables or read them directly from client interfaces such as ODBC, ESQL, and JDBC. You must extract the individual values you are interested in.” The good news is that message should probably contain the word “yet”, as in • “You cannot yet” SELECT an entire ROW in ISQL, • or include a ROW column in a CREATE TABLE statement, • or use CREATE DOMAIN with the ROW data type, • or pass entire ROW values to and from client applications... where “yet” means soon, or eventually. If you’re skeptical about whether or not the ROW data type will ever by supported by CREATE TABLE, consider this example; it shows the ROW() constructor being used to create a derived table containing a column “product_row” with the ROW data type: SELECT ( product.product_row ).id AS id FROM ( SELECT ROW ( Products.id, Products.name ) FROM GROUPO.Products ) AS product ( product_row ); id ----------- 300 301 302 400 401 500 501 600 601 700 The derived table “product” might not be a real CREATE TABLE table, but it works just like a table in the FROM clause, and it’s available in SAP Sybase SQL Anywhere 16.0.0 right now. Can ROW columns in CREATE TABLE be far behind? © 2013 SAP AG or an SAP affiliate company. All rights reserved. 4 2. ARRAYs The ARRAY data type is the second entry in the Top 10 Cool list, tied for Number One with ROW. Similar to ROW, the ARRAY keyword is used for both the data type and constructor: BEGIN DECLARE a ARRAY ( 5 ) OF INTEGER; SET a = ARRAY ( 97, 98, 99 ); SELECT a [[ 1 ]], a [[ 2 ]], a [[ 3 ]]; END; a[[ 1]] a[[ 2]] a[[ 3]] ----------- ----------- ----------- 97 98 99 Yes, arrays come with funky syntax too: [[double square brackets]] around index expressions instead of [] or (). Arrays can have adjustable upper bounds (just code DECLARE ARRAY OF without the ( 5 )), and you can add entries after using the ARRAY() constructor to initialize the array: BEGIN DECLARE a ARRAY OF INTEGER; SET a = ARRAY ( 1, 2 ); SELECT a [[ 1 ]], a [[ 2 ]]; SET a = ARRAY ( 3, 4, 5, 6 ); SET a [[ 5 ]] = 7; SET a [[ 6 ]] = 8; SELECT a [[ 1 ]], a [[ 2 ]], a [[ 3 ]], a [[ 4 ]], a [[ 5 ]], a [[ 6 ]]; END; a[[ 1]] a[[ 2]] ----------- ----------- 1 2 a[[ 1]] a[[ 2]] a[[ 3]] a[[ 4]] a[[ 5]] a[[ 6]] ----------- ----------- ----------- ----------- ----------- ----------- 3 4 5 6 7 8 © 2013 SAP AG or an SAP affiliate company. All rights reserved. 5 You can pass arrays in procedure calls, and the new CARDINALITY() function helps deal with variable-size arrays: CREATE PROCEDURE p ( pa ARRAY OF INTEGER ) BEGIN DECLARE i INTEGER; SET i = CARDINALITY ( pa ); SELECT pa [[ i ]]; END; BEGIN DECLARE a ARRAY OF INTEGER; SET a = ARRAY ( 1, 2 ); CALL p ( a ); SET a = ARRAY ( 1, 2, 3, 4, 5, 6 ); CALL p ( a ); END; pa[[ i]] ----------- 2 pa[[ i]] ----------- 6 Arrays can be nested within arrays, but “nested arrays” aren’t necessarily the same as “multi- dimensional arrays” because each nested array can have a different size. In other words, SAP Sybase SQL Anywhere 16 supports single-dimensional arrays which can be nested within other single-dimensional arrays, and that [[funky syntax]] lets you code [[ 1 ]] [[ 2 ]] but not [[ 1, 2 ]]: BEGIN DECLARE a ARRAY OF ARRAY OF INTEGER; SET a = ARRAY ( ARRAY ( 1, 2 ), ARRAY ( 3, 4, 5 ), ARRAY ( 6, 7, 8, 9 ) ); SELECT CARDINALITY ( a [[ 1 ]] ) AS “Cardinality 1“, CARDINALITY ( a [[ 2 ]] ) AS “2“, CARDINALITY ( a [[ 3 ]] ) AS “3“, a [[ 1 ]] [[ 2 ]], a [[ 2 ]] [[ 3 ]], a [[ 3 ]] [[ 4 ]]; END; Cardinality 1 2 3 a[[ 1]][[ 2]] a[[ 2]][[ 3]] a[[ 3]][[ 4]] ------------- ---------- ---------- ------------- ------------- ---------- 2 3 4 2 5 9 © 2013 SAP AG or an SAP affiliate company. All rights reserved. 6 In one sense, ARRAY variables behave like arrays in other languages, but in another sense they behave like single-column result sets. Here is an example showing how data from a table can be loaded into two arrays, one of them which is a nested array-within-an-array: BEGIN DECLARE D ARRAY OF INTEGER; DECLARE E ARRAY OF ARRAY OF INTEGER; DECLARE D_idx INTEGER; DECLARE E_idx INTEGER; DECLARE emp_cursor CURSOR FOR SELECT DepartmentID AS D_scalar, ARRAY_AGG ( EmployeeID ORDER BY EmployeeID ) AS E_vector FROM Employees GROUP BY DepartmentID ORDER BY DepartmentID; ------------------------------------------------- -- Fill arrays. OPEN emp_cursor; SET D_idx = 1; FETCH NEXT emp_cursor INTO D [[ D_idx ]], E [[ D_idx ]]; WHILE SQLCODE = 0 LOOP SET D_idx = D_idx + 1; FETCH NEXT emp_cursor INTO D [[ D_idx ]], E [[ D_idx ]]; END LOOP; CLOSE emp_cursor; ------------------------------------------------- -- Display arrays. SET D_idx = 1; WHILE D_idx <= CARDINALITY ( D ) LOOP MESSAGE STRING ( ‘D [[ ’, D_idx, ’ ]] = ’, D [[ D_idx ]] ); SET E_idx = 1; WHILE E_idx <= CARDINALITY ( E [[ D_idx ]] ) LOOP MESSAGE STRING ( ’ E [[ ’, D_idx, ’ ]] [[ ’, E_idx, ’ ]] = ’, E [[ D_idx ]] [[ E_idx ]] ); SET E_idx = E_idx + 1; END LOOP; SET D_idx = D_idx + 1; END LOOP; END; © 2013 SAP AG or an SAP affiliate company. All rights reserved. 7 The DECLARE CURSOR statement uses the new ARRAY_AGG function to gather all the EmployeeID column values for one GROUP BY value of DepartmentID, and return it as the “E_vector” array column in the result set.