SnowConvert: Transact DDLs

Übersetzungsreferenz für alle DDL-Anweisungen, denen das Wort CREATE vorangestellt ist.

Index

Applies to
  • [x] SQL Server

  • [x] Azure Synapse Analytics

Warnung

Derzeit wird die Anweisung _ Create Index _ nicht konvertiert, aber geparst. Wenn Ihr Quellcode außerdem Anweisungen Create Index enthält, werden diese im _ Assessment Report _ berücksichtigt.

Beispiel für Index erstellen

 CREATE INDEX my_index_name ON my_table (column1, column2);
Copy

Bemerkung

Da Snowflake aus architektonischen Gründen keine Indizes unterstützt, wird SnowConvert den gesamten Code für die Erstellung von Indizes entfernen. Snowflake erstellt automatisch Mikropartitionen für jede Tabelle, die die Leistung von DML Operationen beschleunigen. Der Benutzer muss sich nicht um die Erstellung oder Verwaltung dieser Mikropartitionen kümmern.

Normalerweise reicht dies aus, um eine sehr gute Abfrageleistung zu erzielen. Es gibt jedoch Möglichkeiten, diese zu verbessern, indem Sie Gruppierungsschlüssel für Daten erstellen. Auf der offiziellen Seite von Snowflake finden Sie weitere Informationen über Mikropartitionen und Data Clustering.

Materialisierte Ansicht

Applies to
  • [x] Azure Synapse Analytics

Beschreibung

In Snowconvert werden materialisierte Ansichten in dynamische Tabellen in Snowflake umgewandelt. Um dynamische Tabellen richtig zu konfigurieren, müssen zwei wesentliche Parameter definiert werden: TARGET_LAG und WAREHOUSE. Wenn diese Parameter in den Konfigurationsoptionen nicht angegeben werden, verwendet Snowconvert während der Konvertierung die voreingestellten Werte, wie im folgenden Beispiel gezeigt.

Für weitere Informationen über materialisierte Ansichten klicken Sie hier.

Einzelheiten zu den erforderlichen Parametern für dynamische Tabellen finden Sie hier.

Beispielhafte Quellcode-Muster

SqlServer

 CREATE MATERIALIZED VIEW sales_total
AS
SELECT SUM(amount) AS total_sales
FROM sales;
Copy

Snowflake

 CREATE OR REPLACE DYNAMIC TABLE sales_total
--** SSC-FDM-0031 - DYNAMIC TABLE REQUIRED PARAMETERS SET BY DEFAULT **
TARGET_LAG='1 day'
WAREHOUSE=UPDATE_DUMMY_WAREHOUSE
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"oracle"}}'
AS
SELECT SUM(amount) AS total_sales
FROM
sales;
Copy

Bekannte Probleme

Zur Zeit sind keine Fehler bekannt.

Prozeduren

Applies to
  • [x] SQL Server

  • [x] Azure Synapse Analytics

Bemerkung

Einige Teile des Ausgabecodes wurden aus Gründen der Übersichtlichkeit weggelassen.

1. CREATE PROCEDURE Translation

Snowflake CREATE PROCEDURE ist in SQL-Syntax definiert, während seine inneren Anweisungen in JavaScript definiert sind.

Quellcode:

 -- Additional Params: -t JavaScript
CREATE PROCEDURE HumanResources.uspGetAllEmployees
     @FirstName NVARCHAR(50),
     @Age INT
AS
    -- TSQL Statements and queries...
GO
Copy

Übersetzter Code:

 CREATE OR REPLACE PROCEDURE HumanResources.uspGetAllEmployees (FIRSTNAME STRING, AGE INT)
RETURNS STRING
LANGUAGE JAVASCRIPT
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
EXECUTE AS CALLER
AS
$$
    // SnowConvert Helpers Code section is omitted.
$$;
Copy

DATA TYPE des Parameters

Die Datentypen der Parameter werden in Snowflake-Äquivalente übersetzt. Siehe auch Datentypen.

EXEC-Hilfsfunktion

Um Anweisungen aus einer Prozedur in der Umgebung SnowFlake ausführen zu können, müssen diese Anweisungen vorverarbeitet und so angepasst werden, dass sie ihre Ausführung in mehreren Variablen widerspiegeln, die für die Ausgangssprache spezifisch sind.

SnowConvert übersetzt automatisch die unterstützten Anweisungen und verwendet eine EXEC-Hilfsfunktion. Dieser Anbieter bietet Zugriffs- und Aktualisierungsfunktionen für viele Variablen, die simulieren, wie die Ausführung dieser Anweisungen in ihrer ursprünglichen Umgebung ablaufen würde.

Sie können zum Beispiel feststellen, dass in den migrierten Prozeduren ein Codeblock immer hinzugefügt wird. Im nächsten Abschnitt werden wir die Grundstruktur dieses Codes erklären. Bitte denken Sie daran, dass wir ständig nach neuen und verbesserten Möglichkeiten suchen, um die Transformationen und alle benötigten Hilfsfunktionen zu rationalisieren.

Struktur

Die Grundstruktur der Hilfsfunktion EXEC ist wie folgt:

  1. Abschnitt Variablendeklaration: Hier werden die verschiedenen Variablen oder Objekte deklariert, die Werte im Zusammenhang mit der Ausführung der Anweisungen innerhalb der Prozedur enthalten. Dazu gehören Werte wie die Anzahl der Zeilen, die von einer Anweisung betroffen sind, oder sogar das Resultset selbst.

  2. fixBind-Funktionsdeklaration: Dies ist eine Hilfsfunktion, die verwendet wird, um Bindungen zu fixieren, wenn sie vom Typ „Date“Funktion sind.

  3. EXEC-Funktionsdeklaration: Dies ist die wichtigste EXEC-Hilfsfunktion. Sie erhält die auszuführende Anweisung, das Array der Bindungen (im Grunde die Variablen oder Parameter, die durch die Ausführung geändert werden können und während der Ausführung der Prozedur Datenpermanenz erfordern), das noCatch-Flag, das bestimmt, ob ERROR_HANDLERS verwendet werden muss, und die catchFunction-Funktion zur Ausführung von benutzerdefiniertem Code, wenn bei der Ausführung der Anweisung eine Ausnahme auftritt. Der Body der Funktion EXEC ist sehr einfach: Führen Sie die Anweisung aus und speichern Sie alle wertvollen Daten, die bei ihrer Ausführung anfallen, innerhalb eines Fehlerbehandlungsblocks.

  4. ERROR VARS: Der EXEC-Catch-Block richtet eine Liste von Fehlervariablen ein, wie z. B. MESSAGE_TEXT, SQLCODE, SQLSTATE, PROC_NAME und ERROR_LINE, die zum Abrufen von Werten aus benutzerdefinierten Funktionen verwendet werden können, um die Verhaltensweise der integrierten SQL Server-Funktionen ERROR_LINE, ERROR_MESSAGE, ERROR_NUMBER, ERROR\_PROCEDURE und ERROR\_STATE zu emulieren. Nachdem alle diese Variablen auf einen Wert gesetzt wurden, ist die benutzerdefinierte Funktion UPDATE_ERROR_VARS dafür zuständig, einige Umgebungsvariablen mit den Fehlerwerten zu aktualisieren, um im SQL-Bereich Zugriff auf sie zu haben.

Code

Der folgende Codeblock stellt die EXEC-Hilfsfunktion innerhalb einer Prozedur dar:

    var _RS, ROW_COUNT, _ROWS, MESSAGE_TEXT, SQLCODE = 0, SQLSTATE = '00000', ERROR_HANDLERS, NUM_ROWS_AFFECTED, INTO;
   var fixBind = function (arg) {
      arg = arg == undefined ? null : arg instanceof Date ? arg.toISOString() : arg;
      return arg;
   };
   var fetch = (count,rows,stmt) => (count && rows.next() && Array.apply(null,Array(stmt.getColumnCount())).map((_,i) => rows.getColumnValue(i + 1))) || [];
   var EXEC = (stmt,binds = [],noCatch = false) => {
      binds = binds ? binds.map(fixBind) : binds;
      for(var stmt of stmt.split(";").filter((_) => _)) {
         try {
            _RS = snowflake.createStatement({
                  sqlText : stmt,
                  binds : binds
               });
            _ROWS = _RS.execute();
            ROW_COUNT = _RS.getRowCount();
            NUM_ROWS_AFFECTED = _RS.getNumRowsAffected();
            return {
               THEN : (action) => !SQLCODE && action(fetch(_ROWS))
            };
         } catch(error) {
            let rStack = new RegExp('At .*, line (\\d+) position (\\d+)');
            let stackLine = error.stackTraceTxt.match(rStack) || [0,-1];
            MESSAGE_TEXT = error.message.toString();
            SQLCODE = error.code.toString();
            SQLSTATE = error.state.toString();
            snowflake.execute({sqlText: `SELECT UPDATE_ERROR_VARS_UDF(?,?,?,?,?)`,binds: [stackLine[1], SQLCODE, SQLSTATE, MESSAGE_TEXT, PROC_NAME]});
            throw error;
         }
      }
   };
Copy

Einfaches EXEC-Beispiel

Dies ist ein einfaches Beispiel für einen EXEC-Aufruf innerhalb einer gespeicherten Prozedur

Quellcode

 -- Additional Params: -t JavaScript
CREATE PROCEDURE dbo.EXEC_EXAMPLE_1
AS
	EXECUTE('SELECT 1 AS Message');
GO
Copy
 -- =============================================
-- Example to execute the stored procedure
-- =============================================
EXECUTE dbo.EXEC_EXAMPLE_1
GO
Copy

Erwarteter Code

 CREATE OR REPLACE PROCEDURE dbo.EXEC_EXAMPLE_1 ()
RETURNS STRING
LANGUAGE JAVASCRIPT
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
EXECUTE AS CALLER
AS
$$
	// REGION SnowConvert Helpers Code
	var _RS, ROW_COUNT, _ROWS, MESSAGE_TEXT, SQLCODE = 0, SQLSTATE = '00000', OBJECT_SCHEMA_NAME  = 'dbo', ERROR_HANDLERS, NUM_ROWS_AFFECTED, PROC_NAME = arguments.callee.name, DOLLAR_DOLLAR = '$' + '$';
	function* sqlsplit(sql) {
		var part = '';
		var ismark = () => sql[i] == '$' && sql[i + 1] == '$';
		for(var i = 0;i < sql.length;i++) {
			if (sql[i] == ';') {
				yield part + sql[i];
				part = '';
			} else if (ismark()) {
				part += sql[i++] + sql[i++];
				while ( i < sql.length && !ismark() ) {
					part += sql[i++];
				}
				part += sql[i] + sql[i++];
			} else part += sql[i];
		}
		if (part.trim().length) yield part;
	};
	var formatDate = (arg) => (new Date(arg - (arg.getTimezoneOffset() * 60000))).toISOString().slice(0,-1);
	var fixBind = function (arg) {
		arg = arg == undefined ? null : arg instanceof Date ? formatDate(arg) : arg;
		return arg;
	};
	var EXEC = (stmt,binds = [],severity = "16",noCatch = false) => {
		binds = binds ? binds.map(fixBind) : binds;
		for(var stmt of sqlsplit(stmt)) {
			try {
				_RS = snowflake.createStatement({
						sqlText : stmt,
						binds : binds
					});
				_ROWS = _RS.execute();
				ROW_COUNT = _RS.getRowCount();
				NUM_ROWS_AFFECTED = _RS.getNumRowsAffected();
				return {
					THEN : (action) => !SQLCODE && action(fetch(_ROWS))
				};
			} catch(error) {
				let rStack = new RegExp('At .*, line (\\d+) position (\\d+)');
				let stackLine = error.stackTraceTxt.match(rStack) || [0,-1];
				MESSAGE_TEXT = error.message.toString();
				SQLCODE = error.code.toString();
				SQLSTATE = error.state.toString();
				snowflake.execute({
					sqlText : `SELECT UPDATE_ERROR_VARS_UDF(?,?,?,?,?,?)`,
					binds : [stackLine[1],SQLCODE,SQLSTATE,MESSAGE_TEXT,PROC_NAME,severity]
				});
				throw error;
			}
		}
	};
	// END REGION

	EXEC(`SELECT 1 AS Message;`);
$$;
Copy

EXEC innerhalb einer gespeicherten Prozedur mit einem Parameter

In diesem Beispiel befindet sich der EXEC-Befehl innerhalb einer gespeicherten Prozedur und erhält einen Parameterwert

Quellcode

 -- Additional Params: -t JavaScript
CREATE PROCEDURE dbo.EXEC_EXAMPLE_2
	@p1 varchar(50) = N''
AS
	EXEC ('SELECT ' + @p1);
GO
Copy
 -- =============================================
-- Example to execute the stored procedure
-- =============================================
EXECUTE dbo.EXEC_EXAMPLE_2 N'''Hello World!'''
GO
Copy

Erwarteter Code

CREATE OR REPLACE PROCEDURE dbo.EXEC_EXAMPLE_2 (P1 STRING DEFAULT '')
RETURNS STRING
LANGUAGE JAVASCRIPT
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
EXECUTE AS CALLER
AS
$$
	// SnowConvert Helpers Code section is omitted.

	EXEC(`SELECT
   ${P1};`);
$$;
Copy

EXEC ruft eine gespeicherte Prozedur mit einem Parameter auf

In diesem Beispiel ruft EXEC eine andere gespeicherte Prozedur auf und fügt einen Parameter hinzu

Quellcode

 -- Additional Params: -t JavaScript
CREATE PROCEDURE dbo.EXEC_EXAMPLE_3
	@p1 varchar(50) = N''
AS
	EXEC EXEC_EXAMPLE_2 @p1
GO
Copy
 -- =============================================
-- Example to execute the stored procedure
-- =============================================
EXECUTE dbo.EXEC_EXAMPLE_3 N'''Hello World!'''
GO
Copy

Erwarteter Code

 CREATE OR REPLACE PROCEDURE dbo.EXEC_EXAMPLE_3 (P1 STRING DEFAULT '')
RETURNS STRING
LANGUAGE JAVASCRIPT
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
EXECUTE AS CALLER
AS
$$
	// SnowConvert Helpers Code section is omitted.

	EXEC(`CALL EXEC_EXAMPLE_2(?)`,[P1]);
$$;
Copy

Parameter mit Standardwert.

In SqlServer kann es Parameter mit einem Standardwert geben, falls diese beim Aufruf einer Prozedur nicht angegeben werden.

Beispiel

 CREATE PROCEDURE PROC_WITH_DEFAULT_PARAMS1
@PARAM1 INT = 0, @PARAM2 INT = 0, @PARAM3 INT = 0, @PARAM4 INT = 0
AS
BEGIN
    .
    .
    .
END
Copy

In Snowflake ist dies übersetzt mit

 CREATE OR REPLACE PROCEDURE PROC_WITH_DEFAULT_PARAMS1(param1 int default 0, param2 int default 0, param3 int default 0, param4 int default 0)
RETURNS TABLE()
LANGUAGE SQL
EXECUTE AS CALLER
AS
$$
    .
    .
    .
$$;
Copy
 CALL PROC_WITH_DEFAULT_PARAMS1(param2 => 10, param4 => 15);
Copy

CURSOR-Hilfsfunktion

 CREATE OR REPLACE PROCEDURE PROC1()
RETURNS STRING
LANGUAGE JAVASCRIPT
EXECUTE AS CALLER
AS
$$
	  var CURSOR = function (stmt, binds) {
	  var statementObj, result_set, total_rows, isOpen = false, self = this, row_count;
	
	  this.CURRENT = new Object;
	
	  var fetch = (count,rows,stmt) => (count && rows.next() && Array.apply(null,Array(stmt.getColumnCount())).map((_,i) => rows.getColumnValue(i + 1))) || [];
	
	  var fixBind = function (arg) {
	      arg = arg == undefined ? null : arg instanceof Date ? formatDate(arg) : arg;
	      return arg;
	   };
	
	  this.OPEN = function(openParameters) {
		  if (result_set == undefined) {
			try {
				if (openParameters) binds = openParameters;
				if (binds instanceof Function) binds = binds();
				var finalBinds = binds && binds.map(fixBind);
				var finalStmt = stmt instanceof Function ? stmt() : stmt;
				statementObj = snowflake.createStatement({
					sqlText : finalStmt,
					binds : finalBinds
				});
				result_set = statementObj.execute();
				total_rows = statementObj.getRowCount();
				isOpen = true;
				row_count = 0;
			} catch(error) {
				RAISE(error.code,"error",error.message);
			}
			else {
				isOpen = true;
			}
		  }
	          
	      return this;
	  };
	      
	  this.CURSOR_ROWS = function () {
	      return total_rows;
	  };
	
	  this.FETCH_STATUS = function() {
	      if(total_rows > row_count)
	          return 0;
	      else
	          return -1;
	  };
	
	  this.FETCH_NEXT = function() {
		  self.res = [];
	      if (isOpen) {
			  self.res = fetch(total_rows,result_set,statementObj);
			  if (self.res)
				  row_count++;
		  }
		  return self.res && self.res.length > 0;
	  };
	
	  this.INTO = function () {
	      return self.res;
	  };
	
	  this.CLOSE = function () {
	      isOpen = false;
	  };
	
	  this.DEALLOCATE = function() {
	      this.CURRENT = row_count = result_set_table = total_rows = result_set = statementObj = self = undefined;
	  };
  };
  
  var COL1, COL2;
  var sql_stmt = ``;
	
  let c = new CURSOR(`SELECT COL1, COL2 FROM TABLE1;`,() => []);
    
  c.OPEN();
  c.FETCH_NEXT();
  [COL1, COL2] = c.INTO();
  while ( c.FETCH_STATUS()) {
        
        
        sql_stmt = `INSERT INTO TABLE2 (COL1, COL2) VALUES (` + COL1+ `, ` + COL2 + `)`;
		
        snowflake.createStatement({
            sqlText : sql_stmt
         }).execute();
  }

  c.CLOSE();
  c.DEALLOCATE();

  return 'sucess';
$$;
Copy

Insert Into EXEC-Hilfsfunktion

Die Insert Into Exec-Hilfsfunktion erzeugt eine Funktion namens Insert insertIntoTemporaryTable(SQL). Mit dieser Funktion kann die Transformation für INSERT INTO TABLE_NAME EXEC(...) von TSQL in Snowflake die Verhaltensweise der ursprünglichen Anweisung imitieren, indem die Daten in eine temporäre Tabelle eingefügt und dann wieder in die ursprüngliche INSERT-Anweisung eingefügt werden.

Weitere Informationen darüber, wie der Code für diese Anweisung geändert wird, finden Sie im Abschnitt „Insert Into Exec“

Bemerkung

Dieser generierte Code für INSERT INTO EXEC kann bei der Verarbeitung von EXECUTE-Anweisungen, die mehrere Abfragen enthalten, Leistungsprobleme verursachen.

   function insertIntoTemporaryTable(sql) {
    var table = "SnowConvertPivotTemporaryTable";
    return EXEC('CREATE OR REPLACE TEMPORARY TABLE ${table} AS ${sql}');
  }
  
  insertIntoTemporaryTable(`${DBTABLES}`)
  EXEC(`INSERT INTO MYDB.PUBLIC.T_Table SELECT * FROM MYDB.PUBLIC.SnowConvertPivotTemporaryTable`);
  EXEC(`DROP TABLE SnowConvertPivotTemporaryTable`)
Copy

LIKE-Hilfsfunktion

Für den Fall, dass ein ähnlicher Ausdruck in einer Prozedur gefunden wird, zum Beispiel

 CREATE PROCEDURE ProcedureLike @VariableValue VARCHAR(50) AS
BEGIN
	IF @VariableValue like '%c%'
	BEGIN
		Select AValue from ATable;
	END;
END;
Copy

Da das Innere der Prozedur in Javascript umgewandelt wird, wird der LIKE-Ausdruck einen Fehler auslösen. Um dies zu vermeiden und die Funktionalität zu erhalten, wird eine Funktion am Anfang der Prozedur hinzugefügt, wenn ein ähnlicher Ausdruck gefunden wird.

   function LIKE(expr,pattern,esc,cs) {
    function fixPattern(pattern,esc) {
      const specials = '/.*+?|(){}[]\\'.split('');
      var newPattern = "";
      var fix = (c) => specials.includes(c) ? '\\' + c : c;
      for(var i = 0;i < pattern.length;i++) {
        var c = pattern[i];
        if (c === esc) {
          newPattern += pattern[i + 1]
          i++
        } else if (c === '%') {
          newPattern += ".*?"
        } else if (c === '_') {
          newPattern += "."
        } else if (c === '[' || ']') {
          newPattern += c
        } else newPattern += fix(c)
      }
      return newPattern;
    }
    return new RegExp(`^${fixPattern(pattern,esc)}$`,cs ? '' : 'i').exec(expr) != null;
  }
Copy

Mit dieser Funktion können wir die Funktionalität des LIKE-Ausdrucks von SQL replizieren. Schauen wir uns die verschiedenen Anwendungsfälle an

 -- Additional Params: -t JavaScript
CREATE PROCEDURE ProcedureLike @VariableValue VARCHAR(50) AS
BEGIN
	IF @VariableValue like '%c%'
	BEGIN
		Select AValue from ATable;
	END;
	IF @VariableValue not like '%c%'
	BEGIN
		Select BValue from BTable;
	END;
  IF @VariableValue like '%c!%%' escape '!'
	BEGIN
		Select CValue from CTable;
	END;
END;
Copy

Im letzten Code gibt es ein normales „Like“, ein „Not Like“ und ein „Like“ mit Escape. Die Transformation ist

 CREATE OR REPLACE PROCEDURE ProcedureLike (VARIABLEVALUE STRING)
RETURNS STRING
LANGUAGE JAVASCRIPT
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
EXECUTE AS CALLER
AS
$$
	// SnowConvert Helpers Code section is omitted.

	if (LIKE(VARIABLEVALUE,`%c%`)) {
		{
			EXEC(`		Select
		   AValue
		from
		   ATable`);
		}
	}
	if (!LIKE(VARIABLEVALUE,`%c%`)) {
		{
			EXEC(`		Select
		   BValue
		from
		   BTable`);
		}
	}
	if (LIKE(VARIABLEVALUE,`%c!%%`,`!`)) {
		{
			EXEC(`		Select
		   CValue
		from
		   CTable`);
		}
	}
$$;
Copy

Beachten Sie, dass die Likes in Funktionsaufrufe umgewandelt werden

 LIKE(VARIABLEVALUE,`%c%`)
!LIKE(VARIABLEVALUE,`%c%`)
LIKE(VARIABLEVALUE,`%c!%%`,`!`)
Copy

Die in der Funktion LIKE enthaltenen Parameter sind die folgenden:

  • Der Ausdruck, der gerade ausgewertet wird.

  • Das Vergleichsmuster

  • Wenn vorhanden, ist das Escape-Zeichen ein optionaler Parameter.

Select-Hilfsfunktion

Erzeugt eine Funktion namens SELECT, wenn ein skalarer Wert auf eine Variable gesetzt werden muss

 -- Additional Params: -t JavaScript
CREATE PROCEDURE MAX_EMPLOYEE_ID
AS
BEGIN
   DECLARE @VARIABLE INT 
   SET @VARIABLE = (SELECT MAX(EMPLOYEE_ID) FROM EMPLOYEES);
   RETURN @VARIABLE
END;
Copy

In diesem Fall wird der folgende Code mit der SELECT-Hilfsfunktion erzeugt

 CREATE OR REPLACE PROCEDURE MAX_EMPLOYEE_ID ()
RETURNS STRING
LANGUAGE JAVASCRIPT
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
EXECUTE AS CALLER
AS
$$
   // SnowConvert Helpers Code section is omitted.

   let VARIABLE;
   VARIABLE = SELECT(`   MAX(EMPLOYEE_ID) FROM
   EMPLOYEES`);
   return VARIABLE;
$$;
Copy

Die SELECT-Hilfsfunktion kann auch verwendet werden, um einen aus einer Abfrage abgerufenen Wert in einen lokalen Wert einzufügen. Die Hilfsfunktion wurde speziell entwickelt, um die gleiche Verhaltensweise des SQL Servers SELECT @local_variable zu unterstützen. Der Parameter args steht für jede Operation, die auf alle lokalen Variablen innerhalb des „Select“ angewendet wird. Siehe auch SELECT @Variable. Beispiel:

 -- Additional Params: -t JavaScript
CREATE PROCEDURE [PROCEDURE1] AS

DECLARE @VAR1 int;
DECLARE @VAR2 int;
select @VAR1 = col1 + col2, @VAR2 += col1 from table1;

GO
Copy

In diesem Fall werden die Variablenzuweisungen in JavaScript Lambdas übersetzt, um die Verhaltensweise von SQL Server zu emulieren.

CREATE OR REPLACE PROCEDURE PROCEDURE1 ()
RETURNS STRING
LANGUAGE JAVASCRIPT
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
EXECUTE AS CALLER
AS
$$
// SnowConvert Helpers Code section is omitted.

let VAR1;
let VAR2;
SELECT(`   col1 + col2,
   col1
   from
   table1`,[],(value) => VAR1 = value,(value) => VAR2 += value);
$$;
Copy

RAISERROR-Hilfsfunktion

Dieses Hilfsmittel wird generiert, wenn ein RAISERROR-Aufruf im Quellcode verwendet wird. Beispiel:

 var RAISERROR = (message,severity,state) => {
    snowflake.execute({
      sqlText : `SELECT UPDATE_ERROR_VARS_UDF(?,?,?)`,
      binds : [message,severity,state]
    });
    var msg = `Message: ${message}, Level: ${severity}, State: ${state}`;
    throw msg;
  };
Copy

RAISERROR führt das Programm UPDATE_ERROR_VARS_UDF aus, um den Wert der Fehlermeldung, den Schweregrad und den Status als Umgebungsvariablen zu speichern, für den Fall, dass sie durch den Aufruf einer der in ERROR eingebauten Funktionen verwendet werden müssen. Schließlich wird die Fehlermeldung in demselben Format ausgegeben wie bei SQL Server.

Identitätsfunktion-Hilfsfunktion

Dieses Hilfsfunktion wird immer dann generiert, wenn die Identitätsfunktion für ein „Select Into“ innerhalb einer Prozedur verwendet wird.

  var IdentityHelper = (seed,increment) => {
      var sequenceString = "`CREATE OR REPLACE SEQUENCE SnowConvert_Temp_Seq START = ${seed} INCREMENT = ${increment}`";
      return EXEC(sequenceString);
Copy

Die Parameter für diese Hilfsfunktion sind die gleichen wie die der Originalfunktion. Es wurde erstellt, um eine Sequenz zu erzeugen, die die Verhaltensweise der Identitätsfunktion in TSQL nachahmt. Die Änderungen am ursprünglichen Code sind:

  • Ein zusätzlicher Methodenaufruf der Funktion IdentityHelper mit denselben Parametern, die im Quellcode zu finden sind.

  • Und der Aufruf der IDENTITY_UDF ein Funktionsentwurf, um den nächsten Wert in der Folge zu erhalten.

    IdentityHelper(1,1)
   EXEC(`CREATE TABLE PUBLIC.department_table3 AS SELECT IDENTITY_UDF() /*** MSC-WARNING - MSCEWI1046 - 'identity' FUNCTION MAPPED TO 'IDENTITY_UDF', FUNCTIONAL EQUIVALENCE VERIFICATION PENDING ***/ as Primary_Rank
from PUBLIC.department_table`);
Copy

Genau wie in TSQL werden die Standardwerte (1,1) verwendet, wenn keine Parameter angegeben werden.

CALL Prozedur-Hilfsfunktion

Diese Hilfsfunktion wird immer dann generiert, wenn ein Aufruf einer zuvor benutzerdefinierten Funktion erfolgt, die durch den Übersetzungsprozess nun zu einer Prozedur geworden ist.

    var CALL = (sql,binds = [],...args) => {
      EXEC("CALL " + sql,binds);
      _ROWS.next();
      return (_ROWS.getColumnValue(1))[0];
   };
Copy

Der Zweck dieser Hilfsfunktion ist es, die Logik für den Aufruf von Prozeduren so zu kapseln, als ob sie Funktionen wären.

Bitte bedenken Sie, dass diese Funktionalität eingeschränkt ist, da Prozeduren nicht innerhalb von Abfragen wie SELECT aufgerufen werden können.

Anwendungsbeispiel, unter der Annahme, dass FooSelfAssign(@PAR INT) in eine Prozedur übersetzt wurde:

 // Input code
DECLARE @VAR1 INT = FooSelfAssign(1);
DECLARE @VAR4 INT = FooSelfAssign(FooSelfAssign(FooSelfAssign(FooSelfAssign(4))));
Copy
 // Output code
let VAR1 = CALL(`FooSelfAssign(1)`)
let VAR4 = CALL(`FooSelfAssign(?)`,[CALL(`FooSelfAssign(?)`,[CALL(`FooSelfAssign(?)`,[CALL(`FooSelfAssign(4)`)])])]);
Copy

Beachten Sie, dass die Übersetzung für VAR1 sehr einfach ist, während bei VAR4 der äußerste CALL eine Liste mit den restlichen CALLs als Bindungen enthält.

Jeder nachfolgende CALL wird in eine Bindung übersetzt, wenn er in einem anderen CALL enthalten ist.

2. Variables

DECLARE @Variable

Quellcode

     DECLARE @product_list VARCHAR(MAX) = ' ';
    DECLARE @Variable1 AS VARCHAR(100), @Variable2 AS VARCHAR(100);
Copy

Übersetzter Code

    let PRODUCT_LIST = ` `;
   let VARIABLE1;
   let VARIABLE2;
Copy

DECLARE @Variable Tabelle

In diesem Fall wird DECLARE verwendet, um eine Variablentabelle zu deklarieren. Sehen wir uns ein Beispiel an.

 -- Additional Params: -t JavaScript
CREATE PROCEDURE PROC1
AS
BEGIN
DECLARE @VariableNameTable TABLE   
 ( 
 [Col1] INT NOT NULL,
 [Col2] INT NOT NULL 
 );
INSERT INTO @VariableNameTable Values(111,222);
Select * from @VariableNameTable;
END

Exec PROC1;
Copy

Wenn wir diesen Code in SQL Server ausführen, erhalten wir das folgende Ergebnis

Sehen wir uns nun die Transformation in Snowflake an

 CREATE OR REPLACE PROCEDURE PROC1 ()
RETURNS STRING
LANGUAGE JAVASCRIPT
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
EXECUTE AS CALLER
AS
$$
 // SnowConvert Helpers Code section is omitted.

 {
  EXEC(`CREATE OR REPLACE TEMPORARY TABLE T_VariableNameTable
(
   Col1 INT NOT NULL,
   Col2 INT NOT NULL
)`);
  EXEC(`INSERT INTO T_VariableNameTable Values(111,222)`);
  EXEC(`Select
   *
from
   T_VariableNameTable`);
 }
 EXEC(`CALL PROC1()`);
$$;
Copy

Beachten Sie, dass die Zeilen 61 bis 67 die Ergebnisse der Anweisungen innerhalb der Prozedur sind.

Die Tabelle Deklarationsvariable wird in eine temporäre Tabelle umgewandelt. Beachten Sie, dass im Namen das Zeichen @ durch T_ ersetzt wurde.

Wenn wir diesen Code in Snowflake ausführen, erhalten wir kein Ergebnis. Es wird lediglich „null“ angezeigt. Das liegt daran, dass das letzte Select jetzt in der Hilfsfunktion von EXEC enthalten ist. Woher wissen wir also, dass die Tabelle vorhanden ist?

Da sie als temporäre Tabelle innerhalb der Prozedur in einem EXEC erstellt wurde, können wir einen Select auf diese Tabelle außerhalb der Prozedur ausführen.

 Select * from PUBLIC.T_VariableNameTable;
Copy

Wenn wir diese Anweisung ausführen, erhalten wir das folgende Ergebnis

SET @Variable

Jetzt wird die Set-Variable je nach dem Ausdruck, der auf der rechten Seite steht, umgewandelt.

Wenn der Ausdruck eine Transformation hat, wird er in seine JavaScript-Entsprechung umgewandelt.

Beispiel

 -- Additional Params: -t JavaScript
CREATE PROCEDURE PROC1
AS
BEGIN
	SET @product_list2 = '';
    SET @product_list = '';
    SET @var1 += '';
    SET @var2 &= '';
    SET @var3 ^= '';
    SET @var4 |= '';
    SET @var5 /= '';
    SET @var6 %= '';
    SET @var7 *= '';
    SET @var8 -= '';
    SET @ProviderStatement = 'SELECT * FROM TABLE1
WHERE COL1 = '+@PARAM1+ ' AND COL2 = ' + @LOCALVAR1;
    SET @NotSupported = functionValue(a,b,c);
END
    
Copy

Übersetzter Code

 CREATE OR REPLACE PROCEDURE PROC1 ()
RETURNS STRING
LANGUAGE JAVASCRIPT
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
EXECUTE AS CALLER
AS
$$
	// SnowConvert Helpers Code section is omitted.
	
	PRODUCT_LIST2 = ``;
	PRODUCT_LIST = ``;
	VAR1 += ``;
	VAR2 &= ``;
	VAR3 ^= ``;
	VAR4 |= ``;
	VAR5 /= ``;
	VAR6 %= ``;
	VAR7 *= ``;
	VAR8 -= ``;
	PROVIDERSTATEMENT = `SELECT
   *
FROM
   TABLE1
WHERE
   COL1 = ${PARAM1}
   AND COL2 = ${LOCALVAR1};`;
	NOTSUPPORTED = SELECT(`   !!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'functionValue' NODE ***/!!!
   functionValue(a, b, c)`);
$$;
Copy

Wie Sie im Beispiel sehen können, ist der Wert der NOTSUPPORTED-Variable kommentiert, da sie vorerst nicht umgewandelt wird. Beachten Sie, dass dies bedeutet, dass die Transformation noch nicht abgeschlossen ist.

Andere Arten von Sets werden kommentiert, zum Beispiel die folgenden

 -- Additional Params: -t JavaScript
CREATE PROCEDURE PROC1
AS
BEGIN
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
;

SET NOCOUNT ON
;

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
;

SET NOCOUNT OFF
;
END
Copy

Übersetzter Code

CREATE OR REPLACE PROCEDURE PROC1 ()
RETURNS STRING
LANGUAGE JAVASCRIPT
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
EXECUTE AS CALLER
AS
$$
// SnowConvert Helpers Code section is omitted.

/*** SSC-EWI-0040 - THE STATEMENT IS NOT SUPPORTED IN SNOWFLAKE ***/
/*SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED*/
;
/*** SSC-EWI-0040 - THE STATEMENT IS NOT SUPPORTED IN SNOWFLAKE ***/
/*SET NOCOUNT ON*/
;
/*** SSC-EWI-0040 - THE STATEMENT IS NOT SUPPORTED IN SNOWFLAKE ***/
/*SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED*/
;
/*** SSC-EWI-0040 - THE STATEMENT IS NOT SUPPORTED IN SNOWFLAKE ***/
/*SET NOCOUNT OFF*/
;
$$;
Copy

SELECT @Variable

Im Moment wird die SELECT @variable in ein einfaches Select umgewandelt, wobei die Variablenzuweisungen entfernt werden und die Ausdrücke auf der rechten Seite des Operators bleiben. Die Zuweisungsoperationen der lokalen Variablen im Select werden durch arrow-Funktionen ersetzt, die die gleiche Verhaltensweise der Operation repräsentieren, die bei der Zuweisung der lokalen Variablen in SQL Server durchgeführt wird.

Eingabe
 -- Additional Params: -t JavaScript
CREATE PROCEDURE PROC1 AS
DECLARE @VAR1 int;
DECLARE @VAR2 int;
SELECT @VAR1 = COL1 + COL2, @VAR2 = COL3 FROM TABLE1;
GO
Copy
Ausgabe
CREATE OR REPLACE PROCEDURE PROC1 ()
RETURNS STRING
LANGUAGE JAVASCRIPT
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
EXECUTE AS CALLER
AS
$$
// SnowConvert Helpers Code section is omitted.

let VAR1;
let VAR2;
SELECT(`   COL1 + COL2,
   COL3
   FROM
   TABLE1`,[],(value) => VAR1 = value,(value) => VAR2 = value);
$$;
Copy

3. Statements translation

SELECT

Grundform

Die SELECT-Grundform hat keine Bindungen, so dass die Übersetzung die Erstellung eines Aufrufs der EXEC-Hilfsfunktion mit einem Parameter impliziert.\ \ Zum Beispiel:

 -- Source code:
SELECT * FROM DEMO_TABLE_1;
Copy
 // Translated code:
EXEC(`SELECT * FROM DEMO_TABLE_1`);
Copy

IF

Quellcode

 IF Conditional_Expression
   -- SQL Statement
ELSE IF Conditiona_Expression2
   -- SQL Statement
ELSE
   -- SQL Statement
Copy

Übersetzter Code

 if (Conditional_Expression) {
    // SQL Statement
} else if (Conditional_Expression2) {
    // SQL Statement
} else{
    // SQL Statement
}
Copy

WHILE

Quellcode

 WHILE ( Conditional_Expression )
BEGIN
   -- SQL STATEMENTS
END;
Copy

Übersetzter Code

 while ( Conditional_Expression )
{
  // SQL STATEMENTS
}
Copy

EXEC / EXECUTE

Quellcode

 -- Execute simple statement
Exec('Select 1');

-- Execute statement using Dynamic Sql
Exec('Select ' + @par1 + ' from [db].[t1]');

-- Execute Procedure with parameter
EXEC db.sp2 'Create proc [db].[p3] AS', @par1, 1
Copy

Übersetzter Code

 -- Execute simple statement
EXEC(`Select 1`);

-- Execute statement using Dynamic Sql
EXEC(`Select ${PAR1} from MYDB.db.t1`);

-- Execute Procedure with parameter
EXEC(`CALL db.sp2(/*** SSC-EWI-0038 - THIS STATEMENT MAY BE A DYNAMIC SQL THAT COULD NOT BE RECOGNIZED AND CONVERTED ***/
'Select * from MYDB.db.t1', ?, 1, Default)`,[PAR1]);
Copy

THROW

Die Transformation für THROW stellt sicher, dass der Catch-Block, der den Fehler empfängt, Zugriff auf die in der ursprünglichen Anweisung angegebenen Informationen hat.

Zum Beispiel:

 -- Case 1
THROW

-- Case 2
THROW 123, 'The error message', 1

-- Case 3
THROW @var1, @var2, @var3
Copy

Wird umgewandelt in:

 // Case 1
throw {};

// Case 2
throw { code: 123, message: "The error message", status: 1 };

// Case 3
throw { code: VAR1, message: VAR2, status: VAR3 };
Copy

RAISERROR

Die SQL Server-Funktion RAISERROR wird in Snowflake nicht unterstützt. SnowConvert identifiziert alle Verwendungen, um eine Hilfsfunktion zu erzeugen, die die ursprüngliche Verhaltensweise nachahmt. Beispiel:

From
 -- Additional Params: -t JavaScript
CREATE OR ALTER PROCEDURE  RAISERRORTEST AS
BEGIN
    DECLARE @MessageTXT VARCHAR = 'ERROR MESSAGE';
    RAISERROR (N'E_INVALIDARG', 16, 1);
    RAISERROR ('Diagram does not exist or you do not have permission.', 16, 1);
    RAISERROR(@MessageTXT, 16, 1);
END
GO
Copy
Bis
CREATE OR REPLACE PROCEDURE RAISERRORTEST ()
RETURNS STRING
LANGUAGE JAVASCRIPT
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
EXECUTE AS CALLER
AS
$$
    // SnowConvert Helpers Code section is omitted.

    let MESSAGETXT = `ERROR MESSAGE`;
    RAISERROR("E_INVALIDARG","16","1");
    RAISERROR("Diagram does not exist or you do not have permission.","16","1");
    RAISERROR(MESSAGETXT,"16","1");
$$;
Copy

BREAK/CONTINUE

Die Transformation „break/continue“ sorgt dafür, dass der Codefluss angehalten oder mit einem anderen Block fortgesetzt wird.

Zum Beispiel:

-- Additional Params: -t JavaScript
CREATE PROCEDURE ProcSample
AS
BEGIN
IF @@ROWCOUNT > 0
  Continue;
ELSE
  BREAK;
END
Copy

Wird umgewandelt in:

CREATE OR REPLACE PROCEDURE ProcSample ()
RETURNS STRING
LANGUAGE JAVASCRIPT
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
EXECUTE AS CALLER
AS
$$
  // SnowConvert Helpers Code section is omitted.

  if (ROW_COUNT > 0) {
    continue;
  } else {
    break;
  }
$$;
Copy

INSERT INTO EXEC

Der Code wurde geringfügig geändert, da die Anweisung INSERT INTO [Table] EXEC(...) in Snowflake nicht unterstützt wird. Dies ermöglicht es uns, die Verhaltensweise durch Hinzufügen einiger Codezeilen zu replizieren:

  • Die erste hinzugefügte Zeile ist ein Aufruf der Funktion insertIntoTemporaryTable, in die der aus dem Argument innerhalb von EXEC extrahierte Code eingefügt wird. Dadurch wird das Resultset in eine temporäre Tabelle eingefügt. Weitere Informationen zu dieser Funktion finden Sie im Abschnitt Insert Into EXEC-Hilfsfunktion.

  • Exec von Insert wird aus dem Code entfernt und eine Abfrage, die die Ergebnisse des EXEC aus der temporären Tabelle abruft.

     SELECT * FROM MYDB.PUBLIC.SnowConvertPivotTemporaryTable
    
Copy
  • Die letzte hinzugefügte Zeile ist eine DROP TABLE-Anweisung für die hinzugefügte temporäre Tabelle.

     DROP TABLE SnowConvertPivotTemporaryTable
    
Copy

Quellcode:

 INSERT INTO #Table1
EXEC ('SELECT
Table1.ID
FROM Population');

INSERT INTO #Table1
EXEC (@DBTables);
Copy

Übersetzter Code:

   insertIntoTemporaryTable(`SELECT Table1.ID FROM MYDB.PUBLIC.Population)
  EXEC(`INSERT INTO MYDB.PUBLIC.T_Table1 SELECT * FROM MYDB.PUBLIC.SnowConvertPivotTemporaryTable`);
  EXEC(`DROP TABLE SnowConvertPivotTemporaryTable`)
  
  insertIntoTemporaryTable(`${DBTABLES}`)
  EXEC(`INSERT INTO MYDB.PUBLIC.T_Table1 SELECT * FROM MYDB.PUBLIC.SnowConvertPivotTemporaryTable`);
  EXEC(`DROP TABLE SnowConvertPivotTemporaryTable`)
Copy

BEGIN TRANSACTION

BEGIN TRANSACTION wird in den Snowflake-Befehl BEGIN umgewandelt und in einen EXEC-Hilfsaufruf eingefügt.

Die Hilfsfunktion ist für die tatsächliche Ausführung der resultierenden BEGIN zuständig.

Beispiel:

 -- Input code
BEGIN TRAN @transaction_name;
Copy
 // Output code
EXEC(`BEGIN`, []);
Copy

COMMIT TRANSACTION

COMMIT TRANSACTION wird in den Snowflake-Befehl COMMIT umgewandelt und in einen EXEC-Hilfsaufruf eingefügt.

Die Hilfsfunktion ist für die tatsächliche Ausführung der resultierenden COMMIT zuständig.

Beispiel:

 -- Input code
COMMIT TRAN @transaction_name;
Copy
 // Output code
EXEC(`COMMIT`, []);
Copy

ROLLBACK TRANSACTION

ROLLBACK TRANSACTION wird in den Snowflake-Befehl ROLLBACK umgewandelt und in einen EXEC-Hilfsaufruf eingefügt.

Die Hilfsfunktion ist für die tatsächliche Ausführung der resultierenden ROLLBACK zuständig.

Beispiel:

 -- Input code
ROLLBACK TRAN @transaction_name;
Copy
 // Output code
EXEC(`ROLLBACK`, []);
Copy

WAITFOR DELAY

WAITFOR DELAY-Klausel wird in die Funktion SYSTEM$WAIT von Snowflake umgewandelt. Der Parameter _time_to\pass der Funktion DELAY wird in Sekunden umgewandelt, damit er als Parameter in der Funktion SYSTEM$WAIT verwendet werden kann.

Die anderen Varianten der WAITFOR-Klausel werden in Snowflake nicht unterstützt und sind daher mit der entsprechenden Meldung gekennzeichnet.

Beispiel:

 -- Input code
1) WAITFOR DELAY '02:00';
2) WAITFOR TIME '13:30';
3) WAITFOR (RECEIVE TOP (1)
   @dh = conversation_handle,
   @mt = message_type_name,
   @body = message_body
   FROM [eqe]), TIMEOUT 5000;
Copy
 // Output code
1) EXEC(`SYSTEM$WAIT(120)`,[]);
2) /*** SSC-EWI-0040 - THE STATEMENT IS NOT SUPPORTED IN SNOWFLAKE ***/
   /*WAITFOR TIME '13:30'*/
   ;
3) /*** SSC-EWI-0040 - THE STATEMENT IS NOT SUPPORTED IN SNOWFLAKE ***/
   /*WAITFOR (RECEIVE TOP (1)
      @dh = conversation_handle,
      @mt = message_type_name,
      @body = message_body
      FROM [eqe]), TIMEOUT 5000*/
   ;
Copy

3. Cursors

Da CURSORS in Snowflake nicht unterstützt wird, ordnet SnowConvert deren Funktionalität einer JavaScript-Hilfsfunktion zu, die die ursprüngliche Verhaltensweise auf der Zielplattform emuliert. Beispiel:

Eingabe:

 -- Additional Params: -t JavaScript
CREATE PROCEDURE [procCursorHelper] AS

DECLARE vendor_cursor CURSOR FOR   
    SELECT VendorID, Name  
    FROM Purchasing.Vendor  
    WHERE PreferredVendorStatus = 1  
    ORDER BY VendorID;
GO
Copy
Ausgabe:
CREATE OR REPLACE PROCEDURE procCursorHelper ()
RETURNS STRING
LANGUAGE JAVASCRIPT
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
EXECUTE AS CALLER
AS
$$
    // SnowConvert Helpers Code section is omitted.

    var VENDOR_CURSOR = new CURSOR(`SELECT
       VendorID,
       Name
    FROM
       Purchasing.Vendor
    WHERE
       PreferredVendorStatus = 1
    ORDER BY VendorID`,[],false);
$$;
Copy

DECLARE CURSOR

Im Moment wird „Declare Cursor“ nur kommentiert.

Quellcode

 DECLARE myCursor1 CURSOR FOR SELECT COL1 FROM TABLE1
Copy

Übersetzter Code

 let myCursor1 = new CURSOR(`SELECT COL1 FROM TABLE1`,() => []);
Copy

OPEN

Quellcode

 OPEN myCursor1
OPEN GLOBAL myCursor2
Copy

Übersetzter Code

 myCursor1.OPEN();
myCursor2.OPEN()
Copy

FETCH

Quellcode

 DECLARE @VALUE1 INT
FETCH NEXT FROM myCursor1 into @VALUE1
Copy

Übersetzter Code

 var VALUE1;
myCursor1.FETCH_NEXT();
VALUE1 = myCursor1.INTO();
Copy

CLOSE

Quellcode

 CLOSE myCursor1
CLOSE GLOBAL myCursor2
Copy

Übersetzter Code

 myCursor1.CLOSE()
myCursor2.CLOSE()
Copy

DEALLOCATE

Quellcode

 DEALLOCATE myCursor1
DEALLOCATE GLOBAL myCursor2
Copy

Übersetzter Code

 myCursor1.DEALLOCATE()
myCursor2.DEALLOCATE()
Copy

@@FETCH_STATUS

Quellcode

 @@FETCH_STATUS
Copy

Übersetzter Code

 myCursor1.FETCH_STATUS()
Copy

@@CURSOR_ROWS

Quellcode

 @@CURSOR_ROWS
Copy

Übersetzter Code

 myCursor1.FETCH_STATUS()
Copy

4. Expressions

Binäre Operationen

Quellcode

 SET @var1 = 1 + 1;
SET @var1 = 1 - 1;
SET @var1 = 1 / 1;
SET @var1 = 1 * 1;
SET @var1 = 1 OR 1;
SET @var1 = 1 AND 1;
Copy

Übersetzter Code

 VAR1 = 1 + 1;
VAR1 = 1 - 1;
VAR1 = 1 / 1;
VAR1 = 1 * 1;
VAR1 = 1 || 1;
VAR1 = 1 && 1;
Copy

Bedingungen

Quellcode

 @var1 > 0
@var1 = 0
@var1 < 0
@var1 <> 0
Copy

Übersetzter Code

 VAR1 > 0
VAR1 = 0
VAR1 < 0
VAR1 != 0
Copy
IN-Prädikat
NULL-Prädikat

Quellcode

 @var1 is null
@var2 is not null
Copy

Übersetzter Code

 VAR1 == null
VAR2 != null
Copy

5. Labels and Goto

Labels verhalten sich in JavaScript nicht so wie in SQL Server. Um die Verhaltensweise zu simulieren, werden sie in functions umgewandelt. Ihre Verwendung wird durch einen Aufruf der generierten Funktion ersetzt, die die gesamte Logik des Labels enthält. Beispiel:

Quellcode

 -- Additional Params: -t JavaScript
CREATE PROCEDURE [procWithLabels] 
AS
SUCCESS_EXIT:
	SET @ErrorStatus = 0
	RETURN @ErrorStatus

ERROR_EXIT:
	RETURN @ErrorStatus
Copy
Übersetzter Code
 CREATE OR REPLACE PROCEDURE procWithLabels ()
RETURNS STRING
LANGUAGE JAVASCRIPT
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
EXECUTE AS CALLER
AS
$$
	// SnowConvert Helpers Code section is omitted.

	SUCCESS_EXIT();
	ERROR_EXIT();
	function SUCCESS_EXIT() {
		ERRORSTATUS = 0;
		return ERRORSTATUS;
	}
	function ERROR_EXIT() {
		return ERRORSTATUS;
	}
$$;
Copy

Wie Sie im obigen Beispiel sehen, werden die Funktionsdeklarationen, die im Quellcode die Bezeichnungen waren, an das Ende des Codes gesetzt, um ihn übersichtlicher zu gestalten.

GOTO ist ein weiterer Befehl, der in JavaScript nicht existiert. Um die Verhaltensweise zu simulieren, werden die Verwendungen in Aufrufe der referenzierten Funktion (Label) umgewandelt, denen eine RETURN-Anweisung vorangestellt wird. Beispiel:

Quellcode
 -- Additional Params: -t JavaScript
CREATE PROCEDURE [procWithLabels] 
AS
DECLARE @ErrorStatus int = 0;
IF @ErrorStatus <> 0 GOTO ERROR_EXIT
	
SUCCESS_EXIT:
	SET @ErrorStatus = 0
	RETURN @ErrorStatus

ERROR_EXIT:
	RETURN @ErrorStatus
Copy
Übersetzter Code
CREATE OR REPLACE PROCEDURE procWithLabels ()
RETURNS STRING
LANGUAGE JAVASCRIPT
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
EXECUTE AS CALLER
AS
$$
	// SnowConvert Helpers Code section is omitted.

	let ERRORSTATUS = 0;
	if (ERRORSTATUS != 0) {
		return ERROR_EXIT();
	}
	SUCCESS_EXIT();
	ERROR_EXIT();
	function SUCCESS_EXIT() {
		ERRORSTATUS = 0;
		return ERRORSTATUS;
	}
	function ERROR_EXIT() {
		return ERRORSTATUS;
	}
$$;
Copy

Wie Sie im obigen Beispiel sehen, wird return dem Funktionsaufruf hinzugefügt, um den Codefluss zu stoppen, wie es SQL Server mit GOTO tut.

Bekannte Probleme

Es wurden keine Probleme gefunden.

Zugehörige EWIs

  1. [SSC-EWI-0040](../../general/technical-documentation/issues-and-troubleshooting/conversion-issues/generalEWI. md#ssc-ewi-0040): Anweisung wird nicht unterstützt.

  2. [SSC-EWI-0073](../../general/technical-documentation/issues-and-troubleshooting/conversion-issues/generalEWI. md#ssc-ewi-0073): Überprüfung der Funktionsäquivalenz ausstehend.

Tabellen

Applies to
  • [x] SQL Server

  • [x] Azure Synapse Analytics

Bemerkung

Einige Teile des Ausgabecodes wurden aus Gründen der Übersichtlichkeit weggelassen.

Grundlegende CREATE TABLE-Anweisung

Quelle

 CREATE TABLE [MYSCHEMA].[MYTABLE]
(
    [COL1] INT IDENTITY (1,1) NOT NULL,
    [COL2] INT,
    [COL2 COL3 COL4] VARCHAR,
    [COL VARCHAR_SPANISH] [VARCHAR](20) COLLATE Modern_Spanish_CI_AI DEFAULT 'HOLA',
    [COL VARCHAR_LATIN] [VARCHAR](20) COLLATE Latin1_General_CI_AI DEFAULT 'HELLO' 
);
Copy

Erwartet

 CREATE OR REPLACE SEQUENCE MYSCHEMA.MYTABLE_COL1
    START WITH 1
    INCREMENT BY 1
COMMENT = 'FOR TABLE-COLUMN MYSCHEMA.MYTABLE.COL1';

CREATE OR REPLACE TABLE MYSCHEMA.MYTABLE (
    COL1 INT DEFAULT MYSCHEMA.MYTABLE_COL1.NEXTVAL NOT NULL,
    COL2 INT,
    "COL2 COL3 COL4" VARCHAR,
    "COL VARCHAR_SPANISH" VARCHAR(20) COLLATE 'ES-CI-AI' /*** SSC-PRF-0002 - CASE INSENSITIVE COLUMNS CAN DECREASE THE PERFORMANCE OF QUERIES ***/ DEFAULT 'HOLA',
    "COL VARCHAR_LATIN" VARCHAR(20) COLLATE 'EN-CI-AI' /*** SSC-PRF-0002 - CASE INSENSITIVE COLUMNS CAN DECREASE THE PERFORMANCE OF QUERIES ***/ DEFAULT 'HELLO'
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
;
Copy

Temporäre Tabellen

Im Quellcode kann es einige Tabellennamen geben, die mit dem Zeichen # beginnen.

 CREATE TABLE #MyLocalTempTable (
        COL1 INT,
        COL2 INT
);
Copy

Wenn das der Fall ist, werden sie im Ausgabecode in temporäre Tabellen umgewandelt.

Schauen wir uns an, wie der Code von oben migriert werden würde.

 CREATE OR REPLACE TEMPORARY TABLE T_MyLocalTempTable (
        COL1 INT,
        COL2 INT
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"transact"}}'
;
Copy

Wie Sie sehen können, wurde TEMPORARY zur Definition der Tabelle hinzugefügt und das Zeichen # wurde durch T_ ersetzt.

Außerdem werden alle Verweise auf die Tabelle umgewandelt, damit sie dem neuen Namen der temporären Tabelle entsprechen.

NULL- und NOT NULL-Spaltenoption

NULL- und NOT NULL-Spaltenoptionen werden in Snowflake unterstützt.

Quelle

 CREATE TABLE [SCHEMA1].[TABLE1](
	[COL1] [varchar](20) NOT NULL
) ON [PRIMARY]
GO

CREATE TABLE [SCHEMA1].[TABLE2](
	[COL1] [varchar](20) NULL
) ON [PRIMARY]
GO
Copy

Erwartet

 CREATE OR REPLACE TABLE SCHEMA1.TABLE1 (
	COL1 VARCHAR(20) NOT NULL
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"transact"}}'
;

CREATE OR REPLACE TABLE SCHEMA1.TABLE2 (
	COL1 VARCHAR(20) NULL
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"transact"}}'
;
Copy

Identität-Spaltenoption

Für Identitätsspalten wird eine Sequenz erstellt und der Spalte zugewiesen.

Quelle

 CREATE TABLE acct3.UnidentifiedCash3 (
UnidentifiedCash_ID3 INT IDENTITY (666, 313) NOT NULL
);
Copy

Erwartet

 CREATE OR REPLACE SEQUENCE acct3.UnidentifiedCash3_UnidentifiedCash_ID3
START WITH 666
INCREMENT BY 313
COMMENT = 'FOR TABLE-COLUMN acct3.UnidentifiedCash3.UnidentifiedCash_ID3';

CREATE OR REPLACE TABLE acct3.UnidentifiedCash3 (
UnidentifiedCash_ID3 INT DEFAULT acct3.UnidentifiedCash3_UnidentifiedCash_ID3.NEXTVAL NOT NULL
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"transact"}}'
;
Copy

Standardspaltenoption

Standardausdruck wird in Snowflake unterstützt, in SQL Server kann er jedoch zusammen mit einem Namen für eine Einschränkung auftreten. Da dieser Teil in Snowflake nicht unterstützt wird, wird er entfernt und eine Warnung hinzugefügt.

Quelle

 CREATE TABLE [SCHEMA1].[TABLE1] (
    [COL1] VARCHAR (10) CONSTRAINT [constraintName] DEFAULT ('0') NOT NULL
);
Copy

Erwartet

 CREATE OR REPLACE TABLE SCHEMA1.TABLE1 (
    COL1 VARCHAR(10)
                     --** SSC-FDM-0012 - CONSTRAINT IN DEFAULT EXPRESSION IS NOT SUPPORTED IN SNOWFLAKE **
                     DEFAULT ('0') NOT NULL
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"transact"}}'
;
Copy

Spalteneinschränkung

Quelle

 CREATE TABLE [SalesLT].[Address](
	[AddressID] [int] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL,
	[AddressLine1] [nvarchar](60) NOT NULL,
	[AddressLine2] [nvarchar](60) NULL,
	[City] [nvarchar](30) NOT NULL,
	[StateProvince] [dbo].[Name] NOT NULL,
	[CountryRegion] [dbo].[Name] NOT NULL,
	[PostalCode] [nvarchar](15) NOT NULL,
	[rowguid] [uniqueidentifier] ROWGUIDCOL  NOT NULL,
	[ModifiedDate] [datetime] NOT NULL,
	CONSTRAINT [PK_Address_AddressID] PRIMARY KEY CLUSTERED 
	(
		[AddressID] ASC
	)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY],
	CONSTRAINT [AK_Address_rowguid] UNIQUE NONCLUSTERED 
	(
		[rowguid] ASC
	)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
Copy

Erwartet

 CREATE OR REPLACE SEQUENCE SalesLT.Address_AddressID
	START WITH 1
	INCREMENT BY 1
COMMENT = 'FOR TABLE-COLUMN SalesLT.Address.AddressID';

--** SSC-FDM-0007 - MISSING DEPENDENT OBJECT "[dbo].[Name]" **
CREATE OR REPLACE TABLE SalesLT.Address (
	AddressID INT DEFAULT SalesLT.Address_AddressID.NEXTVAL NOT NULL,
	AddressLine1 VARCHAR(60) NOT NULL,
	AddressLine2 VARCHAR(60) NULL,
	City VARCHAR(30) NOT NULL,
	StateProvince VARIANT /*** SSC-FDM-TS0015 - DATA TYPE DBO.NAME IS NOT SUPPORTED IN SNOWFLAKE ***/ NOT NULL,
	CountryRegion VARIANT /*** SSC-FDM-TS0015 - DATA TYPE DBO.NAME IS NOT SUPPORTED IN SNOWFLAKE ***/ NOT NULL,
	PostalCode VARCHAR(15) NOT NULL,
	rowguid VARCHAR
 	               !!!RESOLVE EWI!!! /*** SSC-EWI-0040 - THE STATEMENT IS NOT SUPPORTED IN SNOWFLAKE ***/!!!
 	               ROWGUIDCOL  NOT NULL,
	ModifiedDate TIMESTAMP_NTZ(3) NOT NULL,
	CONSTRAINT PK_Address_AddressID PRIMARY KEY (AddressID),
	CONSTRAINT AK_Address_rowguid UNIQUE (rowguid)
)
COMMENT = '{ "origin": "sf_sc", "name": "snowconvert", "version": {  "major": 0,  "minor": 0,  "patch": "0" }, "attributes": {  "component": "transact",  "convertedOn": "09/23/2024" }}'
;
Copy

Collate-Spaltenoption

Die Transformation für „Collate“ finden Sie unter folgendem Link.

collate.md

ENCRYPTED WITH-Spaltenoption

„Encrypted With“ wird in Snowflake nicht unterstützt, daher wird es entfernt und eine Warnung hinzugefügt.

Quelle

 CREATE TABLE [SCHEMA1].[TABLE1] (
    [COL1] NVARCHAR(60) ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = MyCEK, ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256')
);
Copy

Erwartet

 CREATE OR REPLACE TABLE SCHEMA1.TABLE1 (
    COL1 VARCHAR(60)
--                     --** SSC-FDM-TS0009 - ENCRYPTED WITH NOT SUPPORTED IN SNOWFLAKE **
--                     ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = MyCEK, ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256')
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"transact"}}'
;
Copy

NOT FOR REPLICATION

Die Option NOT FOR REPLICATION wird in Snowflake nicht unterstützt. Sie wird für die Identität verwendet, die auf eine SEQUENCE migriert wird.

Warnung

Beachten Sie, dass NOT FOR REPLICATION eine Anweisung ist, die in Snowflake nicht benötigt wird, da sie in ein Äquivalent übersetzt wird, also wird sie entfernt.

Quelle

 CREATE TABLE [TABLE1] (
    [COL1] INT IDENTITY (1, 1) NOT FOR REPLICATION NOT NULL
) ON [PRIMARY];
Copy

Ausgabe

 CREATE OR REPLACE SEQUENCE TABLE1_COL1
    START WITH 1
    INCREMENT BY 1
COMMENT = 'FOR TABLE-COLUMN TABLE1.COL1';

CREATE OR REPLACE TABLE TABLE1 (
    COL1 INT DEFAULT TABLE1_COL1.NEXTVAL NOT NULL
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"transact"}}'
;
Copy

On Primary

Die Option ON PRIMARY ist eine Anweisung, die in SQL Server verwendet wird, um festzulegen, in welcher Datei ein Objekt, z. B. eine Tabelle, erstellt werden soll. Zum Beispiel in einer primären oder sekundären Dateigruppe innerhalb der Datenbank. Snowflake bietet eine andere Logik und zeigt verschiedene Einschränkungen an. Bitte lesen Sie die folgende Snowflake-Dokumentation für weitere Informationen.

Quelle

 CREATE TABLE [TABLE1](
[COL1] [nvarchar](255) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL
 CONSTRAINT [pk_dimAddress_AddressId] PRIMARY KEY CLUSTERED ([COL1]) 
 WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
Copy
Ausgabe
 CREATE OR REPLACE TABLE TABLE1 (
 COL1 VARCHAR(255) COLLATE 'EN-CI-AS' /*** SSC-PRF-0002 - CASE INSENSITIVE COLUMNS CAN DECREASE THE PERFORMANCE OF QUERIES ***/ /*** SSC-FDM-TS0002 - COLLATION FOR VALUE CP1 NOT SUPPORTED ***/ NOT NULL
  CONSTRAINT pk_dimAddress_AddressId PRIMARY KEY (COL1)
 )
 COMMENT = '{ "origin": "sf_sc", "name": "snowconvert", "version": {  "major": 0,  "minor": 0,  "patch": "0" }, "attributes": {  "component": "transact",  "convertedOn": "09/23/2024" }}'
 ;
Copy

ASC/DESC-Spaltensortierung

Spaltensortierung wird in Snowflake nicht unterstützt, die Schlüsselwörter ASC oder DESC werden entfernt.

Quelle

 CREATE TABLE [TABLE1](
	[COL1] [int] NOT NULL,
 CONSTRAINT [constraint1] PRIMARY KEY CLUSTERED ([COL1] ASC)
) ON [PRIMARY]
Copy
Ausgabe
 CREATE OR REPLACE TABLE TABLE1 (
	COL1 INT NOT NULL,
	 CONSTRAINT constraint1 PRIMARY KEY (COL1)
	)
	COMMENT = '{ "origin": "sf_sc", "name": "snowconvert", "version": {  "major": 0,  "minor": 0,  "patch": "0" }, "attributes": {  "component": "transact",  "convertedOn": "09/23/2024" }}'
	;
Copy

Berechnete Spalten

Berechnete Spalten werden in Snowflake unterstützt, wir müssen nur den expliziten Datentyp hinzufügen, um die Tabelle zum Beispiel bereitstellen zu können.

Quelle

 CREATE TABLE [TABLE1](
	[COL2] [int] NOT NULL,
	[COL2] [int] NOT NULL,
	[COL1] AS (COL3 * COL2),
)
Copy
Ausgabe
 CREATE OR REPLACE TABLE TABLE1 (
	COL2 INT NOT NULL,
	COL2 INT NOT NULL,
	COL1 VARIANT AS (COL3 * COL2) /*** SSC-FDM-TS0014 - COMPUTED COLUMN WAS TRANSFORMED TO ITS SNOWFLAKE EQUIVALENT, FUNCTIONAL EQUIVALENCE VERIFICATION PENDING. ***/
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"transact"}}'
;
Copy

Wenn der berechnete Ausdruck nicht transformiert werden kann, wird eine Warnung hinzugefügt und stattdessen eine einfache Spaltendefinition mit dem Rückgabetyp des Ausdrucks verwendet, wie im folgenden Beispiel:

Quelle
 CREATE TABLE [TABLE1](
	[Col1] AS (CONVERT ([XML], ExpressionValue))
)
Copy

Der Ausdruck CONVERT ([NUMERIC], ExpressionValue) wird von SnowConvert noch nicht unterstützt. Nach der Überprüfung stellt SnowConvert fest, dass es sich um XML ist. Die Transformation lautet

 CREATE OR REPLACE TABLE TABLE1 (
	Col1 TEXT AS (CAST(ExpressionValue AS VARIANT !!!RESOLVE EWI!!! /*** SSC-EWI-0036 - XML DATA TYPE CONVERTED TO VARIANT ***/!!!)) /*** SSC-FDM-TS0014 - COMPUTED COLUMN WAS TRANSFORMED TO ITS SNOWFLAKE EQUIVALENT, FUNCTIONAL EQUIVALENCE VERIFICATION PENDING. ***/
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"transact"}}'
;
Copy

SnowConvert führt einen Prozess aus, um den ursprünglichen Ausdruckstyp in SQL Server zu ermitteln. Die Spalte wird jedoch den entsprechenden Zieltyp haben. Im vorherigen Beispiel war der Spaltentyp in SQLServer XML, aber der Zieltyp in Snowflake für die Speicherung einer XML ist TEXT. Weitere Informationen über die Zuordnung von Datentypen finden Sie in den Abschnitten über Datentypen.

MASKED WITH-Spaltenoption

In SQL Server wird die Datenmaskierung verwendet, um sensible Informationen vor nicht privilegierten Benutzern zu schützen. Lesen Sie die Dokumentation SQL SERVER für weitere Informationen. In Snowflake gibt es eine dynamische Datenmaskierungsfunktion, die jedoch nur für die Enterprise Edition verfügbar ist. Bitte lesen Sie die folgende Snowflake Dokumentation.

Eingabe

 CREATE TABLE TABLE1
(
	[COL1] [nvarchar](50) MASKED WITH (FUNCTION = 'default()') NULL
);
Copy
Ausgabe
 CREATE OR REPLACE TABLE TABLE1
(
	COL1 VARCHAR(50)
 	                !!!RESOLVE EWI!!! /*** SSC-EWI-TS0017 - COLUMN MASKING NOT SUPPORTED IN CREATE TABLE ***/!!!
 MASKED WITH (FUNCTION = 'default()') NULL
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"transact"}}'
;
Copy

ROWGUIDCOL-Spaltenoption

ROWGUIDCOL ist in Snowflake nicht mehr anwendbar. Er wird in SQL Server verwendet für UNIQUEIDENTIFIER -Typen, die derzeit nach VARCHAR übersetzt werden. Beispiel:

Eingabe

 CREATE TABLE TABLEROWID (
    [ROWGUID] UNIQUEIDENTIFIER ROWGUIDCOL NOT NULL
) ON [PRIMARY];
Copy
Ausgabe
 CREATE OR REPLACE TABLE TABLEROWID (
    ROWGUID VARCHAR
                    !!!RESOLVE EWI!!! /*** SSC-EWI-0040 - THE STATEMENT IS NOT SUPPORTED IN SNOWFLAKE ***/!!!
                    ROWGUIDCOL NOT NULL
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"transact"}}'
;
Copy

GENERATED ALWAYS AS ROW START/END-Spaltenoption

ROW START/END wird in Snowflake nicht unterstützt. Ein Fehler wird hinzugefügt, wenn SnowConvert versucht, diese Art von Spaltenoption zu transformieren.

Eingabe

 CREATE TABLE TABLEROWID (
    [COL1] DATETIME GENERATED ALWAYS AS ROW START NOT NULL
) ON [PRIMARY];
Copy
Ausgabe
 CREATE OR REPLACE TABLE TABLEROWID (
    COL1 TIMESTAMP_NTZ(3) GENERATED ALWAYS AS ROW START !!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'GeneratedClause' NODE ***/!!! NOT NULL
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"transact"}}'
;
Copy

Bekannte Probleme

Es wurden keine Probleme gefunden.

Zugehörige EWIs

  1. [SSC-EWI-0036](../../general/technical-documentation/issues-and-troubleshooting/conversion-issues/generalEWI. md#ssc-ewi-0036): Datentyp in einen anderen Datentyp konvertiert.

  2. [SSC-EWI-0040](../../general/technical-documentation/issues-and-troubleshooting/conversion-issues/generalEWI. md#ssc-ewi-0040): Anweisung wird nicht unterstützt.

  3. [SSC-EWI-0073](../../general/technical-documentation/issues-and-troubleshooting/conversion-issues/generalEWI. md#ssc-ewi-0073): Überprüfung der Funktionsäquivalenz ausstehend.

  4. [SSC-EWI-TS0017](../../general/technical-documentation/issues-and-troubleshooting/conversion-issues/sqlServerEWI. md#ssc-ewi-ts0017): Maskierung wird nicht unterstützt.

  5. [SSC-FDM-0012](../../general/technical-documentation/issues-and-troubleshooting/functional-difference/generalFDM. md#ssc-fdm-0012): Einschränkung im Standardausdruck wird nicht unterstützt.

  6. [SSC-FDM-TS0002](../../general/technical-documentation/issues-and-troubleshooting/functional-difference/sqlServerFDM. md#ssc-fdm-ts0002): Diese Meldung wird angezeigt, wenn eine COLLATE-Klausel vorhanden ist, die in Snowflake nicht unterstützt wird.

  7. [SSC-FDM-TS0009](../../general/technical-documentation/issues-and-troubleshooting/functional-difference/sqlServerFDM. md#ssc-fdm-ts0009): Encrypted With in Snowflake nicht unterstützt.

  8. [SSC-FDM-TS0014](../../general/technical-documentation/issues-and-troubleshooting/functional-difference/sqlServerFDM. md#ssc-fdm-ts0014): Berechnete Spalte transformiert.

  9. [SSC-FDM-TS0015](../../general/technical-documentation/issues-and-troubleshooting/functional-difference/sqlServerFDM. md#ssc-fdm-ts0015): Datentyp wird in Snowflake nicht unterstützt.

  10. [SSC-PRF-0002](../../general/technical-documentation/issues-and-troubleshooting/performance-review/README. md#ssc-prf-0002): Spalten, bei denen die Groß-/Kleinschreibung nicht beachtet wird, können die Leistung von Abfragen verringern.

Ansichten

Applies to
  • [x] SQL Server

  • [x] Azure Synapse Analytics

Bemerkung

Einige Teile des Ausgabecodes wurden aus Gründen der Übersichtlichkeit weggelassen.

In diesem Abschnitt werden wir die Transformation für „Create View“ überprüfen.

Beispielhafte Quellcode-Muster

SIMPLE CREATE VIEW

Das folgende Beispiel zeigt eine Transformation für eine einfache CREATE VIEW-Anweisung.

 CREATE VIEW VIEWNAME
AS
SELECT AValue from ATable;
Copy

Erwartet

 CREATE OR REPLACE VIEW VIEWNAME
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
AS
SELECT
AValue
from
ATable;
Copy

CREATE OR ALTER VIEW

Die in SqlServer verwendete Definition CREATE OR ALTER wird in Snowflake in CREATE OR REPLACE umgewandelt.

 CREATE OR ALTER VIEW VIEWNAME
AS
SELECT AValue from ATable;
Copy
 CREATE OR REPLACE VIEW VIEWNAME
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
AS
SELECT
AValue
from
ATable;
Copy

CREATE VIEW WITH

In dieser Art von Ansicht können nach dem Namen der Ansicht die folgenden Klauseln stehen

  • WITH ENCRYPTION

  • WITH SCHEMABINDING

  • WITH VIEW_METADATA

Warnung

Beachten Sie, dass die oben genannten Klauseln aus der Übersetzung entfernt wurden, da sie in der Snowflake-Syntax nicht relevant sind.

 CREATE OR ALTER VIEW VIEWNAME
WITH ENCRYPTION  
AS
SELECT AValue from ATable;
Copy
 CREATE OR REPLACE VIEW VIEWNAME
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
AS
SELECT
AValue
from
ATable;
Copy

CREATE VIEW AS SELECT WITH CHECK OPTION

Bei dieser Art von Ansicht kommt die Klausel WITH CHECK OPTION nach dem Ende der SELECT-Anweisung, die in „Create View“ verwendet wird.

Warnung

Beachten Sie, dass WITH CHECK OPTIONaus der Übersetzung entfernt wurde, da es in der Snowflake-Syntax nicht relevant ist.

 CREATE OR ALTER VIEW VIEWNAME
AS
SELECT AValue from ATable
WITH CHECK OPTION;
Copy

Erwartet

 CREATE OR REPLACE VIEW VIEWNAME
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
AS
SELECT
AValue
from
ATable;
Copy

CREATE VIEW AS COMMON TABLE EXPRESSION

Zum Abrufen der Daten müssen allgemeine Tabellenausdrücke verwendet werden:

 CREATE VIEW EMPLOYEEIDVIEW
AS
WITH CTE AS ( SELECT NationalIDNumber from [HumanResources].[Employee] 
UNION ALL 
SELECT BusinessEntityID FROM [HumanResources].[EmployeeDepartmentHistory] )
SELECT * FROM MyCTE;
Copy
 CREATE OR REPLACE VIEW EMPLOYEEIDVIEW
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
AS
--** SSC-PRF-TS0001 - PERFORMANCE WARNING - RECURSION FOR CTE NOT CHECKED. MIGHT REQUIRE RECURSIVE KEYWORD **
WITH CTE AS ( SELECT
NationalIDNumber
from
HumanResources.Employee
UNION ALL
SELECT
BusinessEntityID
FROM
HumanResources.EmployeeDepartmentHistory
)
SELECT
*
FROM
MyCTE;
Copy
UNSUPPORTED SCENARIOS

Übliche Tabellenausdrücke mit Update-, Insert- oder DELETE-Anweisungen werden auskommentiert, da sie in Snowflake und SQLServer nicht unterstützt werden.

Wenn der Ansicht eine ungültige CTE hinzugefügt wird, wird diese vollständig auskommentiert.

 --!!!RESOLVE EWI!!! /*** SSC-EWI-0021 - COMMON TABLE EXPRESSION IN VIEW NOT SUPPORTED ***/!!!
--CREATE OR REPLACE VIEW PUBLIC.EmployeeInsertVew
--AS
--WITH MyCTE AS ( SELECT
--NationalIDNumber
--from
--HumanResources.Employee
--UNION ALL
--SELECT
--BusinessEntityID
--FROM
--HumanResources.EmployeeDepartmentHistory
--)
--INSERT INTO PUBLIC.Dummy
Copy

FINAL SAMPLE

Schauen wir uns ein letztes Beispiel an, fassen wir alle Fälle zusammen, die wir bisher gesehen haben, und sehen wir, wie die Transformation aussehen würde

 CREATE OR ALTER VIEW VIEWNAME
WITH ENCRYPTION  
AS  
Select AValue from ATable
WITH CHECK OPTION;  
Copy

Erwartet

 CREATE OR REPLACE VIEW VIEWNAME
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
AS
Select
AValue
from
ATable;
Copy

Wie Sie sehen können, haben wir OR ALTER durch OR REPLACE ersetzt und die Klausel WITH ENCRYPTION, die nach dem Namen der Ansicht kommt, sowie die Klausel WITH CHECK OPTION, die nach Select kommt, entfernt.

Zugehörige EWIs

  1. [SSC-PRF-TS0001](../../general/technical-documentation/issues-and-troubleshooting/performance-review/README. md#ssc-prf-ts0001): Leistungswarnung – Rekursion für CTE nicht überprüft. Könnte ein rekursives Schlüsselwort erfordern.

Azure Synapse Analytics

Applies to
  • [x] Azure Synapse Analytics

Beschreibung

Dieser Abschnitt enthält die Übersetzung der Syntax für Azure Synapse Analytics Tables.

Bemerkung

Prüfen Sie für die meisten Muster die Übersetzungsspezifikation für allgemeine Tabellen, da sie fast die gleiche Syntax und Verhaltensweise aufweisen.

Create Table

CREATE TABLE { database_name.schema_name.table_name | schema_name.table_name | table_name }
    ( 
      { column_name &#x3C;data_type>  [ &#x3C;column_options> ] } [ ,...n ]
    )  
    [ WITH ( &#x3C;table_option> [ ,...n ] ) ]  
[;]
Copy

Create Table als

 CREATE TABLE { database_name.schema_name.table_name | schema_name.table_name | table_name }
    [ ( column_name [ ,...n ] ) ]  
    WITH ( 
      <distribution_option> -- required
      [ , <table_option> [ ,...n ] ]    
    )  
    AS <select_statement>  
    OPTION <query_hint> 
[;]  
Copy

Beispielhafte Quellcode-Muster

WITH Tabellenoptionen

Azure Synapse Analytics bietet eine zusätzliche Syntax für die Definition von Tabellenoptionen.

 <table_option> ::=
    {
       CLUSTERED COLUMNSTORE INDEX -- default for Azure Synapse Analytics 
      | CLUSTERED COLUMNSTORE INDEX ORDER (column [,...n])  
      | HEAP --default for Parallel Data Warehouse
      | CLUSTERED INDEX ( { index_column_name [ ASC | DESC ] } [ ,...n ] ) -- default is ASC
    }  
    {
        DISTRIBUTION = HASH ( distribution_column_name )
      | DISTRIBUTION = HASH ( [distribution_column_name [, ...n]] ) 
      | DISTRIBUTION = ROUND_ROBIN -- default for Azure Synapse Analytics
      | DISTRIBUTION = REPLICATE -- default for Parallel Data Warehouse
    }
    | PARTITION ( partition_column_name RANGE [ LEFT | RIGHT ] -- default is LEFT  
        FOR VALUES ( [ boundary_value [,...n] ] ) )
Copy

Snowflake sorgt automatisch für die Optimierung von Tabellen durch Mechanismen wie die Mikropartitionierung. Aus diesem Grund gibt es in Snowflake keine entsprechende Syntax für einige dieser Tabellenoptionen. Daher ist es nicht notwendig, einige der Tabellenoptionen von Transact zu definieren.

Tabellenoptionen, die ausgelassen werden sollen:

  • CLUSTERED COLUMNSTORE INDEX (ohne Spalte)

  • HEAP

  • DISTRIBUTION

  • PARTITION

CLUSTERED [ COLUMNSTORE ] INDEX mit Spalten, wird in Snowflake in CLUSTER BY umgewandelt. Eine Leistungsüberprüfung PRF wird hinzugefügt, da es ratsam ist, zu prüfen, ob die Definition eines CLUSTER KEY notwendig ist.

Transact
 CREATE TABLE my_table (
    enterprise_cif INT,
    name NVARCHAR(100),
    address NVARCHAR(255),
    created_at DATETIME
) 
WITH (
    DISTRIBUTION = HASH(enterprise_cif),
    CLUSTERED INDEX (enterprise_cif)
);
Copy
Snowflake
 CREATE OR REPLACE TABLE my_table (
  enterprise_cif INT,
  name VARCHAR(100),
  address VARCHAR(255),
  created_at TIMESTAMP_NTZ(3)
)
--** SSC-PRF-0007 - PERFORMANCE REVIEW - CLUSTER BY **
CLUSTER BY (enterprise_cif)
COMMENT = '{ "origin": "sf_sc", "name": "snowconvert", "version": {  "major": 0,  "minor": 0,  "patch": "0" }, "attributes": {  "component": "transact",  "convertedOn": "10/09/2024" }}'
;
Copy

Bekannte Probleme

Es wurden keine Probleme gefunden.

Zugehörige EWIs

  1. [SSC-PRF-0007](../../general/technical-documentation/issues-and-troubleshooting/performance-review-messages/README. md#ssc-prf-0007): PERFORMANCE REVIEW - CLUSTER BY.

TEXTIMAGE_ON

Applies to
  • [x] SQL Server

Bemerkung

Nicht relevante Anweisung.

Warnung

Beachten Sie, dass diese Anweisung aus der Migration entfernt wurde, da sie eine nicht relevante Syntax darstellt. Das bedeutet, dass sie in Snowflake nicht erforderlich ist.

Beschreibung

TEXTIMAGE_ON [PRIMARY] ist eine Möglichkeit in Transact, die großen Informationsgruppen innerhalb einer Tabelle zu handhaben. In Snowflake ist es nicht erforderlich, diese Art von Merkmalen zu definieren, da Snowflake große Datendateien oder Informationen in einer anderen Anordnung verarbeitet.

Beispielhafte Quellcode-Muster

Beachten Sie, dass in diesem Beispiel TEXTIMAGE_ON [PRIMARY] wegen der unnötigen Syntax entfernt wurde.

 CREATE TABLE [dbo].[TEST_Person](
	[date_updated] [datetime] NULL
 ) TEXTIMAGE_ON [PRIMARY]
Copy
 CREATE OR REPLACE TABLE dbo.TEST_Person (
	date_updated TIMESTAMP_NTZ(3) NULL
 )
 COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
 ;
Copy

Bekannte Probleme

Es wurden keine Probleme gefunden.

Zugehörige EWIs

Keine zugehörigen EWIs.

FUNCTION

Applies to
  • [x] SQL Server

  • [x] Azure Synapse Analytics

Beschreibung

SQL Server unterstützt nur zwei Arten von benutzerdefinierten Funktionen:

Anhand dieser UDFs-Typen ist es möglich, sie nach der inneren Logik in einfach und komplex, zu unterteilen.

Einfache Simple UDFs gleichen die SQL Server-Syntax mit der Snowflake-Syntax ab. Dieser Typ fügt keine Logik hinzu und geht direkt zum Ergebnis. Diese entsprechen in der Regel Snowflakes SQL UDFs. \ \ Komplexe UDFs verwenden bestimmten Anweisungen (INSERT, DELETE, UPDATE, SET, DECLARE, usw.) oder Control-of-Flow-Blöcken (IF…ELSE, WHILE, usw.) in großem Umfang und stellen in der Regel eine Nichtübereinstimmung oder einen Verstoß gegen die Definition von SQL UDFs in Snowflake dar.

Einschränkungen

Transact UDFs haben einige Beschränkungen, die in anderen Datenbank-Engines (wie Oracle und Teradata) nicht vorhanden sind. Diese Beschränkungen helfen bei der Übersetzung, indem sie das Ausmaß der Fehler eingrenzen. Das bedeutet, dass es bestimmte Szenarien gibt, die wir vermeiden sollten.

Hier sind einige der Beschränkungen, die SQL Server für UDFs hat

  • UDFs können nicht verwendet werden, um Aktionen durchzuführen, die den Zustand der Datenbank verändern

  • Benutzerdefinierte Funktionen können keine OUTPUT INTO-Klausel enthalten, die eine Tabelle als Ziel hat

  • Benutzerdefinierte Funktionen können nicht mehrere Resultsets zurückgeben. Verwenden Sie eine gespeicherte Prozedur, wenn Sie mehrere Resultsets zurückgeben müssen.

Die vollständige Liste finden Sie unter diesem Link Benutzerdefinierte Funktionen erstellen (Datenbank-Engine)

scalar.md

inline-table-valued.md

INLINE TABLE-VALUED

Applies to
  • [x] SQL Server

  • [x] Azure Synapse Analytics

Beschreibung

Bemerkung

Einige Teile des Ausgabecodes wurden aus Gründen der Übersichtlichkeit weggelassen.

Inline-Funktionen mit Tabellenwerten sind Tabellenausdrücke, die Parameter akzeptieren, eine SELECT-Anweisung ausführen und ein TABLE zurückgeben können (SQL Server-Referenz: Erstellen einer Inline-Funktion mit Tabellenwerten).

Transact-Syntax

 -- Transact-SQL Inline Table-Valued Function Syntax
CREATE [ OR ALTER ] FUNCTION [ schema_name. ] function_name
( [ { @parameter_name [ AS ] [ type_schema_name. ] parameter_data_type
    [ = default ] [ READONLY ] }
    [ ,...n ]
  ]
)
RETURNS TABLE
    [ WITH <function_option> [ ,...n ] ]
    [ AS ]
    RETURN [ ( ] select_stmt [ ) ]
[ ; ]
Copy

Snowflake SQL-Syntax

 CREATE OR REPLACE FUNCTION <name> ( [ <arguments> ] )
  RETURNS TABLE ( <output_col_name> <output_col_type> [, <output_col_name> <output_col_type> ... ] )
  AS '<sql_expression>'sql
Copy

Beispielhafte Quellcode-Muster

Der folgende Abschnitt beschreibt alle möglichen Quelltextmuster, die in dieser Art von CREATE FUNCTION-Syntax vorkommen können.

Für Inline-Funktionen mit Tabellenwerten kann es nur eine Anweisung pro Body geben, die wie folgt aussehen kann:

  • SELECT-Anweisung

  • Allgemeiner TabellenausdruckWITH

Werte direkt aus einer Tabelle auswählen und zurückgeben

Dies ist das einfachste Szenario, bei dem Sie einen einfachen Select aus einer Tabelle durchführen und die Werte zurückgeben

Transact-SQL
 CREATE FUNCTION GetDepartmentInfo()
RETURNS TABLE
AS
RETURN
(
  SELECT DepartmentID, Name, GroupName
  FROM HumanResources.Department
);

GO

SELECT * from GetDepartmentInfo()
Copy
DepartmentID|Name                      |GroupName                           |
------------+--------------------------+------------------------------------+
           1|Engineering               |Research and Development            |
           2|Tool Design               |Research and Development            |
           3|Sales                     |Sales and Marketing                 |
           4|Marketing                 |Sales and Marketing                 |
           5|Purchasing                |Inventory Management                |
           6|Research and Development  |Research and Development            |
           7|Production                |Manufacturing                       |
           8|Production Control        |Manufacturing                       |
           9|Human Resources           |Executive General and Administration|
          10|Finance                   |Executive General and Administration|
          11|Information Services      |Executive General and Administration|
          12|Document Control          |Quality Assurance                   |
          13|Quality Assurance         |Quality Assurance                   |
          14|Facilities and Maintenance|Executive General and Administration|
          15|Shipping and Receiving    |Inventory Management                |
          16|Executive                 |Executive General and Administration|

Copy
Snowflake SQL
 CREATE OR REPLACE FUNCTION GetDepartmentInfo ()
RETURNS TABLE(
  DepartmentID STRING /*** SSC-FDM-TS0012 - INFORMATION FOR THE COLUMN DepartmentID WAS NOT FOUND. STRING DATATYPE USED TO MATCH CAST AS STRING OPERATION ***/,
  Name STRING /*** SSC-FDM-TS0012 - INFORMATION FOR THE COLUMN Name WAS NOT FOUND. STRING DATATYPE USED TO MATCH CAST AS STRING OPERATION ***/,
  GroupName STRING /*** SSC-FDM-TS0012 - INFORMATION FOR THE COLUMN GroupName WAS NOT FOUND. STRING DATATYPE USED TO MATCH CAST AS STRING OPERATION ***/
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
AS
$$
    SELECT
    CAST(DepartmentID AS STRING),
    CAST(Name AS STRING),
    CAST(GroupName AS STRING)
    FROM
    HumanResources.Department
$$;

SELECT
    *
from
    TABLE(GetDepartmentInfo());
Copy
DepartmentID|Name                      |GroupName                           |
------------+--------------------------+------------------------------------+
           1|Engineering               |Research and Development            |
           2|Tool Design               |Research and Development            |
           3|Sales                     |Sales and Marketing                 |
           4|Marketing                 |Sales and Marketing                 |
           5|Purchasing                |Inventory Management                |
           6|Research and Development  |Research and Development            |
           7|Production                |Manufacturing                       |
           8|Production Control        |Manufacturing                       |
           9|Human Resources           |Executive General and Administration|
          10|Finance                   |Executive General and Administration|
          11|Information Services      |Executive General and Administration|
          12|Document Control          |Quality Assurance                   |
          13|Quality Assurance         |Quality Assurance                   |
          14|Facilities and Maintenance|Executive General and Administration|
          15|Shipping and Receiving    |Inventory Management                |
          16|Executive                 |Executive General and Administration|

Copy

Wählen Sie Werte aus mehreren Tabellen aus und geben Sie sie zurück, indem Sie Spalten umbenennen und eingebaute Funktionen verwenden

Dies ist ein Beispiel für eine Abfrage mit integrierten Funktionen in einer SELECT-Anweisung, die Daten aus verschiedenen Tabellen abruft, Spalten umbenennt und eine Tabelle zurückgibt.

Transact-SQL
 CREATE FUNCTION GetPersonBasicInfo()
RETURNS TABLE
AS 
RETURN
(	
 SELECT TOP (20)
      P.PersonType,
      P.FirstName,
      E.JobTitle,
	  E.Gender,
      YEAR(E.HireDate) as HIREYEAR
  FROM 
      Person.Person P
  INNER JOIN 
      HumanResources.Employee E
  ON
      P.BusinessEntityID = E.BusinessEntityID 
);

GO

SELECT * FROM GetPersonBasicInfo();
Copy
PersonType|FirstName|JobTitle                         |Gender|HIREYEAR|
----------+---------+---------------------------------+------+--------+
EM        |Ken      |Chief Executive Officer          |M     |    2009|
EM        |Terri    |Vice President of Engineering    |F     |    2008|
EM        |Roberto  |Engineering Manager              |M     |    2007|
EM        |Rob      |Senior Tool Designer             |M     |    2007|
EM        |Gail     |Design Engineer                  |F     |    2008|
EM        |Jossef   |Design Engineer                  |M     |    2008|
EM        |Dylan    |Research and Development Manager |M     |    2009|
EM        |Diane    |Research and Development Engineer|F     |    2008|
EM        |Gigi     |Research and Development Engineer|F     |    2009|
EM        |Michael  |Research and Development Manager |M     |    2009|
EM        |Ovidiu   |Senior Tool Designer             |M     |    2010|
EM        |Thierry  |Tool Designer                    |M     |    2007|
EM        |Janice   |Tool Designer                    |F     |    2010|
EM        |Michael  |Senior Design Engineer           |M     |    2010|
EM        |Sharon   |Design Engineer                  |F     |    2011|
EM        |David    |Marketing Manager                |M     |    2007|
EM        |Kevin    |Marketing Assistant              |M     |    2007|
EM        |John     |Marketing Specialist             |M     |    2011|
EM        |Mary     |Marketing Assistant              |F     |    2011|
EM        |Wanida   |Marketing Assistant              |F     |    2011|    

Copy
Snowflake SQL
 CREATE OR REPLACE FUNCTION GetPersonBasicInfo ()
RETURNS TABLE(
	PersonType STRING /*** SSC-FDM-TS0012 - INFORMATION FOR THE COLUMN PersonType WAS NOT FOUND. STRING DATATYPE USED TO MATCH CAST AS STRING OPERATION ***/,
	FirstName STRING /*** SSC-FDM-TS0012 - INFORMATION FOR THE COLUMN FirstName WAS NOT FOUND. STRING DATATYPE USED TO MATCH CAST AS STRING OPERATION ***/,
	JobTitle STRING /*** SSC-FDM-TS0012 - INFORMATION FOR THE COLUMN JobTitle WAS NOT FOUND. STRING DATATYPE USED TO MATCH CAST AS STRING OPERATION ***/,
	Gender STRING /*** SSC-FDM-TS0012 - INFORMATION FOR THE COLUMN Gender WAS NOT FOUND. STRING DATATYPE USED TO MATCH CAST AS STRING OPERATION ***/,
	HIREYEAR INTEGER
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
AS
$$
	 SELECT
	 TOP 20
		CAST(P.PersonType AS STRING),
		CAST(P.FirstName AS STRING),
		CAST(E.JobTitle AS STRING),
		CAST(E.Gender AS STRING),
		YEAR(E.HireDate :: TIMESTAMP) as HIREYEAR
	  FROM
		Person.Person P
	  INNER JOIN
			HumanResources.Employee E
	  ON P.BusinessEntityID = E.BusinessEntityID
$$;

SELECT
	 *
FROM
	 TABLE(GetPersonBasicInfo());
Copy
PersonType|FirstName|JobTitle                         |Gender|HIREYEAR|
----------+---------+---------------------------------+------+--------+
EM        |Ken      |Chief Executive Officer          |M     |    2009|
EM        |Terri    |Vice President of Engineering    |F     |    2008|
EM        |Roberto  |Engineering Manager              |M     |    2007|
EM        |Rob      |Senior Tool Designer             |M     |    2007|
EM        |Gail     |Design Engineer                  |F     |    2008|
EM        |Jossef   |Design Engineer                  |M     |    2008|
EM        |Dylan    |Research and Development Manager |M     |    2009|
EM        |Diane    |Research and Development Engineer|F     |    2008|
EM        |Gigi     |Research and Development Engineer|F     |    2009|
EM        |Michael  |Research and Development Manager |M     |    2009|
EM        |Ovidiu   |Senior Tool Designer             |M     |    2010|
EM        |Thierry  |Tool Designer                    |M     |    2007|
EM        |Janice   |Tool Designer                    |F     |    2010|
EM        |Michael  |Senior Design Engineer           |M     |    2010|
EM        |Sharon   |Design Engineer                  |F     |    2011|
EM        |David    |Marketing Manager                |M     |    2007|
EM        |Kevin    |Marketing Assistant              |M     |    2007|
EM        |John     |Marketing Specialist             |M     |    2011|
EM        |Mary     |Marketing Assistant              |F     |    2011|
EM        |Wanida   |Marketing Assistant              |F     |    2011|

Copy

Spalten mit der WITH-Anweisung auswählen

Der Body einer Inline-Funktion mit Tabellenwerten kann auch mit einer WITH -Anweisung angegeben werden, wie unten gezeigt.

Transact-SQL
 CREATE FUNCTION GetMaritalStatusByGender
(
	@P_Gender nchar(1)
)

RETURNS TABLE 
AS
RETURN
(
  WITH CTE AS 
	(
	 SELECT BusinessEntityID, MaritalStatus, Gender 
	 FROM HumanResources.Employee 
	 where Gender = @P_Gender
	)	
  SELECT 
	MaritalStatus, Gender, CONCAT(P.FirstName,' ', P.LastName) as Name
  FROM 
	CTE INNER JOIN Person.Person P
  ON
	CTE.BusinessEntityID = P.BusinessEntityID
);

GO

select * from GetMaritalStatusByGender('F');
Copy
MaritalStatus|Gender|Name                   |
-------------+------+-----------------------+
S            |F     |Terri Duffy            |
M            |F     |Gail Erickson          |
S            |F     |Diane Margheim         |
M            |F     |Gigi Matthew           |
M            |F     |Janice Galvin          |
M            |F     |Sharon Salavaria       |
S            |F     |Mary Dempsey           |
M            |F     |Wanida Benshoof        |
M            |F     |Mary Gibson            |
M            |F     |Jill Williams          |
S            |F     |Jo Brown               |
M            |F     |Britta Simon           |
M            |F     |Margie Shoop           |
M            |F     |Rebecca Laszlo         |
M            |F     |Suchitra Mohan         |
M            |F     |Kim Abercrombie        |
S            |F     |JoLynn Dobney          |
M            |F     |Nancy Anderson         |
M            |F     |Ruth Ellerbrock        |
M            |F     |Doris Hartwig          |
M            |F     |Diane Glimp            |
M            |F     |Bonnie Kearney         |
M            |F     |Denise Smith           |
S            |F     |Diane Tibbott          |
M            |F     |Carole Poland          |
M            |F     |Carol Philips          |
M            |F     |Merav Netz             |
S            |F     |Betsy Stadick          |
S            |F     |Danielle Tiedt         |
S            |F     |Kimberly Zimmerman     |
M            |F     |Elizabeth Keyser       |
M            |F     |Mary Baker             |
M            |F     |Alice Ciccu            |
M            |F     |Linda Moschell         |
S            |F     |Angela Barbariol       |
S            |F     |Kitti Lertpiriyasuwat  |
S            |F     |Susan Eaton            |
S            |F     |Kim Ralls              |
M            |F     |Nicole Holliday        |
S            |F     |Anibal Sousa           |
M            |F     |Samantha Smith         |
S            |F     |Olinda Turner          |
S            |F     |Cynthia Randall        |
M            |F     |Sandra Reátegui Alayo  |
S            |F     |Linda Randall          |
S            |F     |Shelley Dyck           |
S            |F     |Laura Steele           |
S            |F     |Susan Metters          |
S            |F     |Katie McAskill-White   |
M            |F     |Barbara Decker         |
M            |F     |Yvonne McKay           |
S            |F     |Janeth Esteves         |
M            |F     |Brenda Diaz            |
M            |F     |Lorraine Nay           |
M            |F     |Paula Nartker          |
S            |F     |Lori Kane              |
M            |F     |Kathie Flood           |
S            |F     |Belinda Newman         |
M            |F     |Karen Berge            |
M            |F     |Lori Penor             |
M            |F     |Jo Berry               |
M            |F     |Laura Norman           |
M            |F     |Paula Barreto de Mattos|
M            |F     |Mindy Martin           |
M            |F     |Deborah Poe            |
S            |F     |Candy Spoon            |
M            |F     |Barbara Moreland       |
M            |F     |Janet Sheperdigian     |
S            |F     |Wendy Kahn             |
S            |F     |Sheela Word            |
M            |F     |Linda Meisner          |
S            |F     |Erin Hagens            |
M            |F     |Annette Hill           |
S            |F     |Jean Trenary           |
S            |F     |Stephanie Conroy       |
S            |F     |Karen Berg             |
M            |F     |Janaina Bueno          |
M            |F     |Linda Mitchell         |
S            |F     |Jillian Carson         |
S            |F     |Pamela Ansman-Wolfe    |
S            |F     |Lynn Tsoflias          |
M            |F     |Amy Alberts            |
S            |F     |Rachel Valdez          |
M            |F     |Jae Pak                |

Copy
Snowflake SQL
 CREATE OR REPLACE FUNCTION GetMaritalStatusByGender
(P_GENDER STRING
)
RETURNS TABLE(
	MaritalStatus STRING /*** SSC-FDM-TS0012 - INFORMATION FOR THE COLUMN MaritalStatus WAS NOT FOUND. STRING DATATYPE USED TO MATCH CAST AS STRING OPERATION ***/,
	Gender STRING /*** SSC-FDM-TS0012 - INFORMATION FOR THE COLUMN Gender WAS NOT FOUND. STRING DATATYPE USED TO MATCH CAST AS STRING OPERATION ***/,
	Name VARCHAR
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
AS
$$
	--** SSC-PRF-TS0001 - PERFORMANCE WARNING - RECURSION FOR CTE NOT CHECKED. MIGHT REQUIRE RECURSIVE KEYWORD **
  WITH CTE AS
	(
	 SELECT
	 	BusinessEntityID,
	 	MaritalStatus,
	 	Gender
	 FROM
	 	HumanResources.Employee
	 where
	 	Gender = :P_GENDER
	)
  SELECT
	 CAST(MaritalStatus AS STRING),
	 CAST(Gender AS STRING),
	 CONCAT(P.FirstName,' ', P.LastName) as Name
  FROM
	 CTE
	 INNER JOIN
	 	Person.Person P
  ON CTE.BusinessEntityID = P.BusinessEntityID
$$;

select
  *
from GetMaritalStatusByGender('F') !!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'TableValuedFunctionCall' NODE ***/!!!;
Copy
MaritalStatus|Gender|Name                   |
-------------+------+-----------------------+
S            |F     |Terri Duffy            |
M            |F     |Gail Erickson          |
S            |F     |Diane Margheim         |
M            |F     |Gigi Matthew           |
M            |F     |Janice Galvin          |
M            |F     |Sharon Salavaria       |
S            |F     |Mary Dempsey           |
M            |F     |Wanida Benshoof        |
M            |F     |Mary Gibson            |
M            |F     |Jill Williams          |
S            |F     |Jo Brown               |
M            |F     |Britta Simon           |
M            |F     |Margie Shoop           |
M            |F     |Rebecca Laszlo         |
M            |F     |Suchitra Mohan         |
M            |F     |Kim Abercrombie        |
S            |F     |JoLynn Dobney          |
M            |F     |Nancy Anderson         |
M            |F     |Ruth Ellerbrock        |
M            |F     |Doris Hartwig          |
M            |F     |Diane Glimp            |
M            |F     |Bonnie Kearney         |
M            |F     |Denise Smith           |
S            |F     |Diane Tibbott          |
M            |F     |Carole Poland          |
M            |F     |Carol Philips          |
M            |F     |Merav Netz             |
S            |F     |Betsy Stadick          |
S            |F     |Danielle Tiedt         |
S            |F     |Kimberly Zimmerman     |
M            |F     |Elizabeth Keyser       |
M            |F     |Mary Baker             |
M            |F     |Alice Ciccu            |
M            |F     |Linda Moschell         |
S            |F     |Angela Barbariol       |
S            |F     |Kitti Lertpiriyasuwat  |
S            |F     |Susan Eaton            |
S            |F     |Kim Ralls              |
M            |F     |Nicole Holliday        |
S            |F     |Anibal Sousa           |
M            |F     |Samantha Smith         |
S            |F     |Olinda Turner          |
S            |F     |Cynthia Randall        |
M            |F     |Sandra Reátegui Alayo  |
S            |F     |Linda Randall          |
S            |F     |Shelley Dyck           |
S            |F     |Laura Steele           |
S            |F     |Susan Metters          |
S            |F     |Katie McAskill-White   |
M            |F     |Barbara Decker         |
M            |F     |Yvonne McKay           |
S            |F     |Janeth Esteves         |
M            |F     |Brenda Diaz            |
M            |F     |Lorraine Nay           |
M            |F     |Paula Nartker          |
S            |F     |Lori Kane              |
M            |F     |Kathie Flood           |
S            |F     |Belinda Newman         |
M            |F     |Karen Berge            |
M            |F     |Lori Penor             |
M            |F     |Jo Berry               |
M            |F     |Laura Norman           |
M            |F     |Paula Barreto de Mattos|
M            |F     |Mindy Martin           |
M            |F     |Deborah Poe            |
S            |F     |Candy Spoon            |
M            |F     |Barbara Moreland       |
M            |F     |Janet Sheperdigian     |
S            |F     |Wendy Kahn             |
S            |F     |Sheela Word            |
M            |F     |Linda Meisner          |
S            |F     |Erin Hagens            |
M            |F     |Annette Hill           |
S            |F     |Jean Trenary           |
S            |F     |Stephanie Conroy       |
S            |F     |Karen Berg             |
M            |F     |Janaina Bueno          |
M            |F     |Linda Mitchell         |
S            |F     |Jillian Carson         |
S            |F     |Pamela Ansman-Wolfe    |
S            |F     |Lynn Tsoflias          |
M            |F     |Amy Alberts            |
S            |F     |Rachel Valdez          |
M            |F     |Jae Pak                |

Copy

Bekannte Probleme

Es wurden keine Probleme gefunden

Zugehörige EWIs

  1. [SSC-FDM-TS0012](../../general/technical-documentation/issues-and-troubleshooting/functional-difference/sqlServerFDM. md#ssc-fdm-ts0012): Es wurden keine Informationen für den Ausdruck gefunden. CAST zu STRING verwendet

  2. [SSC-PRF-TS0001](../../general/technical-documentation/issues-and-troubleshooting/performance-review/README. md#ssc-prf-ts0001): Leistungswarnung – Rekursion für CTE nicht überprüft. Könnte ein rekursives Schlüsselwort erfordern.

  3. [SSC-EWI-0073](../../general/technical-documentation/issues-and-troubleshooting/conversion-issues/generalEWI. md#ssc-ewi-0073): Überprüfung der Funktionsäquivalenz ausstehend

MULTI-STATEMENT TABLE-VALUED

Applies to
  • [x] SQL Server

  • [x] Azure Synapse Analytics

Bemerkung

Einige Teile des Ausgabecodes wurden aus Gründen der Übersichtlichkeit weggelassen.

Bemerkung

Alle Codebeispiele auf dieser Seite sind noch nicht in SnowConvert implementiert. Sie sind als Referenz dafür zu verstehen, wie die einzelnen Szenarien in Snowflake umgesetzt werden sollten. Einige Teile des Ausgabecodes wurden aus Gründen der Übersichtlichkeit weggelassen.

Beschreibung

Eine Tabellenwertfunktion mit mehreren Anweisungen ähnelt einer Tabellenwertfunktion mit einerINLINE-Anweisung (INLINE TABLE-VALUED. Eine Tabellenwertfunktion mit mehreren Anweisungen (Multi-Statement Table-Valued Function, MSTVF) kann jedoch mehr als eine Anweisung in ihrem Funktions-Body haben. Die Tabellenspalten sind im Rückgabetyp angegeben und sie hat einen BEGIN/END-Block (SQL Server-Referenz: Erstellen einer Tabellenwertfunktion mit mehreren Anweisungen

Transact-SQL-Syntax

 CREATE [ OR ALTER ] FUNCTION [ schema_name. ] function_name
( [ { @parameter_name [ AS ] [ type_schema_name. ] parameter_data_type
    [ = default ] [READONLY] }
    [ ,...n ]
  ]
)
RETURNS @return_variable TABLE <table_type_definition>
    [ WITH <function_option> [ ,...n ] ]
    [ AS ]
    BEGIN
        function_body
        RETURN
    END
[ ; ]
Copy

Snowflake SQL

 CREATE OR REPLACE FUNCTION <name> ( [ <arguments> ] )
  RETURNS TABLE ( <output_col_name> <output_col_type> [, <output_col_name> <output_col_type> ... ] )
  AS '<sql_expression>'
Copy

Beispielhafte Quellcode-Muster

Der folgende Abschnitt beschreibt alle möglichen Quelltextmuster, die in dieser Art von CREATE FUNCTION-Syntax vorkommen können.

Der Funktions-Body einer Tabellenwertfunktion mit mehreren Anweisungen muss eine SELECT-Anweisung sein. Aus diesem Grund müssen die anderen Anweisungen separat aufgerufen werden.

Werte in eine Tabelle einfügen

Fügt eine oder mehrere Zeilen in die Tabelle ein und gibt die Tabelle mit den neuen Werten zurück

Transact-SQL
 CREATE OR ALTER FUNCTION calc_behavioral_segment()
RETURNS @behavioral_segments TABLE (behavioral_segment VARCHAR(50))
AS
BEGIN
	DECLARE @col varchar(15)
	SET @col = 'Unknown'
	INSERT INTO @behavioral_segments 
	SELECT @col
	
	RETURN 
END

SELECT * FROM calc_behavioral_segment();
Copy
BEHAVIORAL_SEGMENT|
------------------+
           Unknown|

Copy
Snowflake SQL
 !!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'TABLE VALUED FUNCTIONS' NODE ***/!!!
CREATE OR ALTER FUNCTION calc_behavioral_segment ()
RETURNS BEHAVIORAL_SEGMENTS TABLE (
	behavioral_segment VARCHAR(50))
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"transact"}}'
AS
BEGIN
	DECLARE @col varchar(15)
	SET @col = 'Unknown'
	INSERT INTO @behavioral_segments
	SELECT @col

	RETURN
END

SELECT * FROM calc_behavioral_segment();;
Copy
BEHAVIORAL_SEGMENT|
------------------+
           Unknown|

Copy

Wert entsprechend der IF/ELSE-Anweisung einfügen

Fügt entsprechend der Bedingung eine Zeile in die Tabelle ein und gibt die Tabelle mit dem neuen Wert zurück

Transact-SQL
 CREATE OR ALTER FUNCTION odd_or_even_number(@number INT)
RETURNS @numbers TABLE (number_type VARCHAR(15))
AS
BEGIN 
	IF ((@number % 2) = 0)
	BEGIN
		INSERT @numbers SELECT 'Even'
	END
		  
	ELSE
	BEGIN
		INSERT @numbers SELECT 'Odd'
	END

	RETURN
END

SELECT * FROM odd_or_even_number(9);
Copy
       NUMBER_TYPE|
------------------+
               Odd|

Copy
Snowflake SQL
 !!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'TABLE VALUED FUNCTIONS' NODE ***/!!!
CREATE OR ALTER FUNCTION odd_or_even_number (NUMBER INT)
RETURNS NUMBERS TABLE (
	number_type VARCHAR(15))
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"transact"}}'
AS
BEGIN
	IF ((@number % 2) = 0)
	BEGIN
		INSERT @numbers SELECT 'Even'
	END

	ELSE
	BEGIN
		INSERT @numbers SELECT 'Odd'
	END

	RETURN
END

SELECT * FROM odd_or_even_number(9);;
Copy
       NUMBER_TYPE|
------------------+
               Odd|

Copy

Fügt mehrere gemäß der IF/ELSE-Anweisung ein

Das folgende Beispiel fügt mehr als einen Wert in die Tabelle ein und mehr als eine Variable wird entsprechend der Bedingung geändert. Gibt die Tabelle mit den neuen Werten zurück

Transact-SQL
 CREATE OR ALTER FUNCTION new_employee_hired(@id VARCHAR (50), @position VARCHAR(50), @experience VARCHAR(15))
RETURNS @new_employee TABLE (id_employee VARCHAR (50), working_from_home BIT, team VARCHAR(15), computer VARCHAR(15)) 
AS
BEGIN 
	DECLARE @wfh BIT
	DECLARE @team VARCHAR(15)
	DECLARE @computer VARCHAR(15)

	IF @position = 'DEVELOPER'
	BEGIN
		SET @team = 'TEAM_1'
		SET @computer = 'LAPTOP'		
	END

	IF @position = 'IT'
	BEGIN		
		SET @team = 'TEAM_2'
		SET @computer = 'DESKTOP'
	END

	IF @experience = 'JUNIOR'
	BEGIN
		SET @wfh = '0'			
	END
	IF @experience = 'SENIOR'
	BEGIN
		SET @wfh = '1'						
	END

	INSERT INTO @new_employee VALUES (@id, @wfh, @team, @computer)
	RETURN
END

SELECT * FROM new_employee_hired('123456789', 'DEVELOPER', 'SENIOR');
Copy
   ID_EMPLOYEE|  WORKING_FROM_HOME|     TEAM|   COMPUTER|
--------------+-------------------|---------|-----------|
     123456789|                  1|   TEAM_1|     LAPTOP|

Copy
Snowflake
 !!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'TABLE VALUED FUNCTIONS' NODE ***/!!!
CREATE OR ALTER FUNCTION new_employee_hired (ID STRING, POSITION STRING, EXPERIENCE STRING)
RETURNS NEW_EMPLOYEE TABLE (
	id_employee VARCHAR(50),
	working_from_home BOOLEAN,
	team VARCHAR(15),
	computer VARCHAR(15))
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"transact"}}'
AS
BEGIN
	DECLARE @wfh BIT
	DECLARE @team VARCHAR(15)
	DECLARE @computer VARCHAR(15)

	IF @position = 'DEVELOPER'
	BEGIN
		SET @team = 'TEAM_1'
		SET @computer = 'LAPTOP'
	END

	IF @position = 'IT'
	BEGIN
		SET @team = 'TEAM_2'
		SET @computer = 'DESKTOP'
	END

	IF @experience = 'JUNIOR'
	BEGIN
		SET @wfh = '0'
	END
	IF @experience = 'SENIOR'
	BEGIN
		SET @wfh = '1'
	END

	INSERT INTO @new_employee VALUES (@id, @wfh, @team, @computer)
	RETURN
END

SELECT * FROM new_employee_hired('123456789', 'DEVELOPER', 'SENIOR');;
Copy
   ID_EMPLOYEE|  WORKING_FROM_HOME|     TEAM|   COMPUTER|
--------------+-------------------|---------|-----------|
     123456789|                  1|   TEAM_1|     LAPTOP|

Copy

Warnung

Falls es verschachtelte IF-Anweisungen gibt und mehr als eine Variable in den Anweisungen geändert wird, ist es notwendig, eine gespeicherte Prozedur zu verwenden.

Zuvor eingefügte Werte aktualisieren

Aktualisiert die Spaltenwerte der Tabelle im Funktions-Body und gibt ihn mit den neuen Werten zurück.

Transact-SQL
 CREATE OR ALTER FUNCTION get_employees_history()
RETURNS @employee_history TABLE (
	department_name NVARCHAR(50),
	first_name NVARCHAR(50),
	last_name NVARCHAR(50), 
	start_date DATE,
	end_date DATE,
	job_title NVARCHAR(50), 
	months_working INT
)
BEGIN
	INSERT INTO @employee_history
	SELECT D.name AS department_name, P.first_name, P.last_name, EH.start_date, EH.end_date, E.job_title, 0 FROM Department D
	LEFT OUTER JOIN employee_department_history EH
		ON D.department_ID = EH.department_ID
	INNER JOIN  Employee E
		ON E.business_entity_ID = EH.business_entity_ID
	INNER JOIN Person P
		ON P.business_entity_ID = E.business_entity_ID 
		

	UPDATE @employee_history
	SET 
		months_working = 
		CASE WHEN end_date IS NULL THEN DATEDIFF(MONTH, start_date, GETDATE())
		ELSE DATEDIFF(MONTH, start_date, end_date)
	END
	RETURN;
END;

SELECT TOP(10) * FROM get_employees_history();
Copy
                      DEPARTMENT_NAME|         FIRST_NAME|          LAST_NAME|      START_DATE|         END_DATE|                           JOB_TITLE|        MONTHS_WORKING|
-------------------------------------+ ------------------+-------------------+----------------+-----------------+------------------------------------+----------------------+
                                Sales|               Syed|              Abbas|      2013-03-14| 	    NULL|               Pacific Sales Manager|                   106|
                           Production|                Kim|        Abercrombie|      2010-01-16|             NULL|        Production Technician - WC60|                   144|
                    Quality Assurance|              Hazem|           Abolrous|      2009-02-28|             NULL|           Quality Assurance Manager|                   155|
               Shipping and Receiving|              Pilar|           Ackerman|      2009-01-02|             NULL|   Shipping and Receiving Supervisor|                   156|
                           Production|                Jay|              Adams|      2009-03-05|             NULL|        Production Technician - WC60|                   154|
                 Information Services|           François|           Ajenstat|      2009-01-17|             NULL|              Database Administrator|                   156|
                                Sales|                Amy|            Alberts|      2012-04-16|             NULL|              European Sales Manager|                   117|
                           Production|               Greg|           Alderson|      2008-12-02|             NULL|        Production Technician - WC45|                   157|
                    Quality Assurance|               Sean|          Alexander|      2008-12-28|             NULL|        Quality Assurance Technician|                   157|
           Facilities and Maintenance|               Gary|             Altman|      2009-12-02|             NULL|                  Facilities Manager|                   145|


Copy
Snowflake SQL
 !!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'TABLE VALUED FUNCTIONS' NODE ***/!!!
CREATE OR ALTER FUNCTION get_employees_history ()
RETURNS EMPLOYEE_HISTORY TABLE (
	department_name VARCHAR(50),
	first_name VARCHAR(50),
	last_name VARCHAR(50),
	start_date DATE,
	end_date DATE,
	job_title VARCHAR(50),
	months_working INT
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"transact"}}'
BEGIN
	INSERT INTO @employee_history
	SELECT D.name AS department_name, P.first_name, P.last_name, EH.start_date, EH.end_date, E.job_title, 0 FROM Department D
	LEFT OUTER JOIN employee_department_history EH
		ON D.department_ID = EH.department_ID
	INNER JOIN  Employee E
		ON E.business_entity_ID = EH.business_entity_ID
	INNER JOIN Person P
		ON P.business_entity_ID = E.business_entity_ID


	UPDATE @employee_history
	SET
		months_working =
		CASE WHEN end_date IS NULL THEN DATEDIFF(MONTH, start_date, GETDATE())
		ELSE DATEDIFF(MONTH, start_date, end_date)
	END
	RETURN;
END;

SELECT TOP(10) * FROM get_employees_history();;
Copy
                      DEPARTMENT_NAME|         FIRST_NAME|          LAST_NAME|      START_DATE|         END_DATE|                           JOB_TITLE|        MONTHS_WORKING|
-------------------------------------+ ------------------+-------------------+----------------+-----------------+------------------------------------+----------------------+
                                Sales|               Syed|              Abbas|      2013-03-14| 	    NULL|               Pacific Sales Manager|                   106|
                           Production|                Kim|        Abercrombie|      2010-01-16|             NULL|        Production Technician - WC60|                   144|
                    Quality Assurance|              Hazem|           Abolrous|      2009-02-28|             NULL|           Quality Assurance Manager|                   155|
               Shipping and Receiving|              Pilar|           Ackerman|      2009-01-02|             NULL|   Shipping and Receiving Supervisor|                   156|
                           Production|                Jay|              Adams|      2009-03-05|             NULL|        Production Technician - WC60|                   154|
                 Information Services|           François|           Ajenstat|      2009-01-17|             NULL|              Database Administrator|                   156|
                                Sales|                Amy|            Alberts|      2012-04-16|             NULL|              European Sales Manager|                   117|
                           Production|               Greg|           Alderson|      2008-12-02|             NULL|        Production Technician - WC45|                   157|
                    Quality Assurance|               Sean|          Alexander|      2008-12-28|             NULL|        Quality Assurance Technician|                   157|
           Facilities and Maintenance|               Gary|             Altman|      2009-12-02|             NULL|                  Facilities Manager|                   145|


Copy

Mehrere RETURN-Klauseln

Im folgenden Beispiel gibt es mehr als eine Klausel, da es je nach Situation nicht notwendig ist, die gesamte Funktion auszuführen.

Transact-SQL
CREATE OR ALTER FUNCTION create_new_team(@team_name VARCHAR(50))
RETURNS @new_team TABLE (type VARCHAR(50), name VARCHAR(50))
AS
BEGIN 
	DECLARE @employees INT
	SET @employees = (SELECT count(*) FROM employee)
	DECLARE @type VARCHAR(15)
	SET @type = 'small_team'
	IF (@employees &#x3C; 8)
	BEGIN
		INSERT @new_team VALUES (@type, @team_name) 
		RETURN
	END
	
	SET @type = 'big_team'
	INSERT @new_team VALUES (@type, @team_name) 

	RETURN
END

SELECT * FROM create_new_team('Team1');             
Copy
          TYPE|           NAME|
--------------+ --------------+
    SMALL_TEAM|          TEAM1|
 

Copy
Snowflake SQL
 !!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'TABLE VALUED FUNCTIONS' NODE ***/!!!
CREATE OR ALTER FUNCTION create_new_team (TEAM_NAME STRING)
RETURNS NEW_TEAM TABLE (
	type VARCHAR(50),
	name VARCHAR(50))
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"transact"}}'
AS
BEGIN
	DECLARE @employees INT
	SET @employees = (SELECT count(*) FROM employee)
	DECLARE @type VARCHAR(15)
	SET @type = 'small_team'
	IF (@employees < 8)
	BEGIN
		INSERT @new_team VALUES (@type, @team_name)
		RETURN
	END

	SET @type = 'big_team'
	INSERT @new_team VALUES (@type, @team_name)

	RETURN
END

SELECT * FROM create_new_team('Team1');;
Copy
          TYPE|           NAME|
--------------+ --------------+
    SMALL_TEAM|          TEAM1|

Copy

Warnung

Diese Transformation wird angewendet, wenn nur ein Wert eingefügt werden soll. Bei mehr als einem Wert müssen Sie eine gespeicherte Prozedur verwenden.

Komplexe Fälle

Das Beispiel ist ein komplexer Fall, der verschachtelte if-Anweisungen verwendet und einen Wert abhängig von der Bedingung „true“ einfügt.

Transact-SQL
 CREATE OR ALTER FUNCTION vacation_status(@id VARCHAR (50))
RETURNS @status TABLE (vacation_status VARCHAR(30))
AS
BEGIN 
	DECLARE @hire_date DATETIME
	SET @hire_date = (SELECT @hire_date FROM employee WHERE employeeId = @id)
	DECLARE @vacation_hours INT
	SET @vacation_hours = (SELECT count(vacation_hours) FROM employee WHERE employeeId = @id)
	DECLARE @time_working INT
	SET @time_working = (SELECT DATEDIFF(MONTH, @hire_date,GETDATE()))

	IF (@vacation_hours > 0)
	BEGIN
		IF (@time_working > 3)
		BEGIN
			IF (@vacation_hours < 120)
			BEGIN
				INSERT INTO @status VALUES ('Ok')
			END

			IF (@vacation_hours = 120)
			BEGIN
				INSERT INTO @status values ('In the limit')
			END

			IF (@vacation_hours > 120)
			BEGIN
				INSERT INTO @status VALUES ('With excess')
			END
		END
		ELSE
		BEGIN
			INSERT INTO @status values ('Hired recently')
		END
	END
	ELSE
	BEGIN
		INSERT INTO @status values ('No hours')
	END
	RETURN
END

SELECT * FROM vacation_status('adventure-worksken0')
Copy
  VACATION_STATUS|
-----------------+
               OK|

Copy
Snowflake SQL
 !!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'TABLE VALUED FUNCTIONS' NODE ***/!!!
CREATE OR ALTER FUNCTION vacation_status (ID STRING)
RETURNS STATUS TABLE (
	vacation_status VARCHAR(30))
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"transact"}}'
AS
BEGIN
	DECLARE @hire_date DATETIME
	SET @hire_date = (SELECT @hire_date FROM employee WHERE employeeId = @id)
	DECLARE @vacation_hours INT
	SET @vacation_hours = (SELECT count(vacation_hours) FROM employee WHERE employeeId = @id)
	DECLARE @time_working INT
	SET @time_working = (SELECT DATEDIFF(MONTH, @hire_date,GETDATE()))

	IF (@vacation_hours > 0)
	BEGIN
		IF (@time_working > 3)
		BEGIN
			IF (@vacation_hours < 120)
			BEGIN
				INSERT INTO @status VALUES ('Ok')
			END

			IF (@vacation_hours = 120)
			BEGIN
				INSERT INTO @status values ('In the limit')
			END

			IF (@vacation_hours > 120)
			BEGIN
				INSERT INTO @status VALUES ('With excess')
			END
		END
		ELSE
		BEGIN
			INSERT INTO @status values ('Hired recently')
		END
	END
	ELSE
	BEGIN
		INSERT INTO @status values ('No hours')
	END
	RETURN
END

SELECT * FROM vacation_status('adventure-worksken0');
Copy
  VACATION_STATUS|
-----------------+
               OK|

Copy

Bekannte Probleme

WHILE-Anweisungen in Verbindung mit Abfragen

Das Problem bei diesem Beispiel ist, dass es keine Möglichkeit gibt, die WHILE-Anweisung innerhalb der WITH-Klausel des Haupt-Select in eine CTE umzuwandeln. Dadurch sind wir gezwungen, diese Anweisung in eine gespeicherte Prozedur umzuwandeln, um die gleiche Logik zu erhalten.

Transact-SQL
--Additional Params: -t JavaScript
CREATE OR ALTER FUNCTION get_group_name
(@department_id INT)
RETURNS @group_names TABLE (group_name VARCHAR(15))
AS
BEGIN
DECLARE @name VARCHAR(30) = 'Another Department'  
WHILE @name = 'Another Department'   
BEGIN    
	IF (@department_id &#x3C; 3)
	BEGIN
		SET @name = 'engineering'
	END
	  
	IF @department_id = 3
	BEGIN
		SET @name = 'Tool Design'
	END
	
	SELECT @department_id = @department_id / 3
END
INSERT @group_names SELECT @name
RETURN
END

SELECT * FROM get_group_name(9);
Copy
        GROUP_NAME|
------------------+
       Tool Design|

Copy
Snowflake SQL
 !!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'TABLE VALUED FUNCTIONS' NODE ***/!!!
CREATE OR ALTER FUNCTION get_group_name
(DEPARTMENT_ID INT)
RETURNS @group_names TABLE (
	group_name VARCHAR(15))
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"transact"}}'
AS
BEGIN
DECLARE @name VARCHAR(30) = 'Another Department'
WHILE @name = 'Another Department'
BEGIN
	IF (@department_id < 3)
	BEGIN
		SET @name = 'engineering'
	END

	IF @department_id = 3
	BEGIN
		SET @name = 'Tool Design'
	END

	SELECT @department_id = @department_id / 3
END
INSERT @group_names SELECT @name
RETURN
END

SELECT * FROM get_group_name(9);;
Copy
        GROUP_NAME|
------------------+
       Tool Design|

Copy

Cursor deklarieren

Benutzerdefinierte Funktionen können DECLARE, OPEN, FETCH, CLOSE oder DEALLOCATE für einen CURSOR nicht verwenden. Verwenden Sie eine gespeicherte Prozedur, um mit Cursors zu arbeiten.

Transact-SQL
 --Additional Params: -t JavaScript

CREATE OR ALTER FUNCTION amount_new_specimens(@id int)
RETURNS @new_specimens TABLE (amount int)
AS
BEGIN
	DECLARE @first_specimen VARCHAR(30) ;
	set @first_specimen = (select name_specimen from specimen where specimen_id = @id);
	DECLARE @second_specimen VARCHAR(30);

	DECLARE @specimens TABLE (name_specimen VARCHAR(30))

	DECLARE Cursor1 CURSOR 
	FOR SELECT name_specimen 
	FROM specimen 

	OPEN cursor1
	FETCH NEXT FROM cursor1
	INTO @second_specimen;
	
	WHILE @@FETCH_STATUS = 0 
	BEGIN
		IF @first_specimen <> @second_specimen
		BEGIN
			INSERT INTO @specimens values (CONCAT_WS('-', @first_specimen, @second_specimen))
		END
		FETCH NEXT FROM cursor1
		INTO @second_specimen;
	END

	CLOSE cursor1;
	DEALLOCATE cursor1;

	INSERT INTO @new_specimens SELECT COUNT(*) FROM @specimens
	RETURN 
END

SELECT * FROM amount_new_specimens(1);
Copy
            AMOUNT|
------------------+
                 3|

Copy
Snowflake SQL
 --Additional Params: -t JavaScript
!!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'TABLE VALUED FUNCTIONS' NODE ***/!!!

CREATE OR ALTER FUNCTION amount_new_specimens (ID INT)
RETURNS @new_specimens TABLE (
	amount INT
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"transact"}}'
AS
BEGIN
	DECLARE @first_specimen VARCHAR(30) ;
	set @first_specimen = (select name_specimen from specimen where specimen_id = @id);
	DECLARE @second_specimen VARCHAR(30);

	DECLARE @specimens TABLE (name_specimen VARCHAR(30))

	DECLARE Cursor1 CURSOR
	FOR SELECT name_specimen
	FROM specimen

	OPEN cursor1
	FETCH NEXT FROM cursor1
	INTO @second_specimen;

	WHILE @@FETCH_STATUS = 0
	BEGIN
		IF @first_specimen <> @second_specimen
		BEGIN
			INSERT INTO @specimens values (CONCAT_WS('-', @first_specimen, @second_specimen))
		END
		FETCH NEXT FROM cursor1
		INTO @second_specimen;
	END

	CLOSE cursor1;
	DEALLOCATE cursor1;

	INSERT INTO @new_specimens SELECT COUNT(*) FROM @specimens
	RETURN
END

SELECT * FROM amount_new_specimens(1);;
Copy
            AMOUNT|
------------------+
                 3|

Copy

Verschiedene Anweisungen werden in allgemeinen Tabellenausdrücken nicht unterstützt

Die Klauseln UPDATE, INSERT, DELETE, ALTER oder DROP werden im Body von allgemeinen Tabellenausdrücken nicht unterstützt, auch nicht nach ihrer Deklaration mit einem Delimitator. Aus diesem Grund kann die Funktion so geändert werden, dass sie als gespeicherte Prozedur funktioniert.

Transact-SQL
 --Additional Params: -t JavaScript

CREATE OR ALTER PROCEDURE product_history 
AS
BEGIN
	DECLARE @product_history TABLE (
		product_name NVARCHAR(50),
		rating INT
	)
	INSERT INTO @product_history
	SELECT P.Name AS product_name, AVG(ALL R.rating) FROM Production.product P
	INNER JOIN  Production.product_review R
		ON R.product_ID = P.product_ID
	GROUP BY P.Name;

	DELETE FROM @product_history
	WHERE rating < 2;

	SELECT * FROM @product_history; 

END
GO;

EXEC product_history
Copy
                      PRODUCT_NAME|            Rating|
----------------------------------+------------------|
                 HL Mountain Pedal|                 3|
            Mountain Bike Socks, M|                 5|
             Road-550-W Yellow, 40|                 5|

Copy
Snowflake SQL
 CREATE OR REPLACE PROCEDURE product_history ()
RETURNS STRING
LANGUAGE JAVASCRIPT
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
EXECUTE AS CALLER
AS
$$
	// REGION SnowConvert Helpers Code
	var _RS, ROW_COUNT, _ROWS, MESSAGE_TEXT, SQLCODE = 0, SQLSTATE = '00000', OBJECT_SCHEMA_NAME  = 'UNKNOWN', ERROR_HANDLERS, NUM_ROWS_AFFECTED, PROC_NAME = arguments.callee.name, DOLLAR_DOLLAR = '$' + '$';
	function* sqlsplit(sql) {
		var part = '';
		var ismark = () => sql[i] == '$' && sql[i + 1] == '$';
		for(var i = 0;i < sql.length;i++) {
			if (sql[i] == ';') {
				yield part + sql[i];
				part = '';
			} else if (ismark()) {
				part += sql[i++] + sql[i++];
				while ( i < sql.length && !ismark() ) {
					part += sql[i++];
				}
				part += sql[i] + sql[i++];
			} else part += sql[i];
		}
		if (part.trim().length) yield part;
	};
	var formatDate = (arg) => (new Date(arg - (arg.getTimezoneOffset() * 60000))).toISOString().slice(0,-1);
	var fixBind = function (arg) {
		arg = arg == undefined ? null : arg instanceof Date ? formatDate(arg) : arg;
		return arg;
	};
	var EXEC = (stmt,binds = [],severity = "16",noCatch = false) => {
		binds = binds ? binds.map(fixBind) : binds;
		for(var stmt of sqlsplit(stmt)) {
			try {
				_RS = snowflake.createStatement({
						sqlText : stmt,
						binds : binds
					});
				_ROWS = _RS.execute();
				ROW_COUNT = _RS.getRowCount();
				NUM_ROWS_AFFECTED = _RS.getNumRowsAffected();
				return {
					THEN : (action) => !SQLCODE && action(fetch(_ROWS))
				};
			} catch(error) {
				let rStack = new RegExp('At .*, line (\\d+) position (\\d+)');
				let stackLine = error.stackTraceTxt.match(rStack) || [0,-1];
				MESSAGE_TEXT = error.message.toString();
				SQLCODE = error.code.toString();
				SQLSTATE = error.state.toString();
				snowflake.execute({
					sqlText : `SELECT UPDATE_ERROR_VARS_UDF(?,?,?,?,?,?)`,
					binds : [stackLine[1],SQLCODE,SQLSTATE,MESSAGE_TEXT,PROC_NAME,severity]
				});
				throw error;
			}
		}
	};
	// END REGION

	EXEC(`CREATE OR REPLACE TEMPORARY TABLE T_product_history (
   product_name VARCHAR(50),
   rating INT
	)`);
	EXEC(`	INSERT INTO T_product_history
	SELECT
	   P.Name AS product_name,
	   AVG(ALL R.rating) FROM
	   Production.product P
	   INNER JOIN
	      Production.product_review R
	      ON R.product_ID = P.product_ID
	GROUP BY
	   P.Name`);
	EXEC(`DELETE FROM
   T_product_history
   WHERE
   rating < 2`);
	EXEC(`
	SELECT
	   *
	FROM
	   T_product_history`);
$$;

!!!RESOLVE EWI!!! /*** SSC-EWI-0040 - THE STATEMENT IS NOT SUPPORTED IN SNOWFLAKE ***/!!!
;

CALL product_history();
Copy
                      PRODUCT_NAME|            Rating|
----------------------------------+------------------|
                 HL Mountain Pedal|                 3|
            Mountain Bike Socks, M|                 5|
             Road-550-W Yellow, 40|                 5|

Copy

Zugehörige EWIs

  1. [SSC-EWI-0040](../../general/technical-documentation/issues-and-troubleshooting/conversion-issues/generalEWI. md#ssc-ewi-0040): Anweisung wird nicht unterstützt.

  2. [SSC-EWI-0073](../../general/technical-documentation/issues-and-troubleshooting/conversion-issues/generalEWI. md#ssc-ewi-0073): Überprüfung der Funktionsäquivalenz ausstehend

SCALAR

Applies to
  • [x] SQL Server

  • [x] Azure Synapse Analytics

Beschreibung

Bemerkung

Einige Teile des Ausgabecodes wurden aus Gründen der Übersichtlichkeit weggelassen.

Eine skalare benutzerdefinierte Funktion ist eine Transact-SQL oder Common Language Runtime (CLR)-Routine, die Parameter akzeptiert, eine Aktion durchführt, z. B. eine komplexe Berechnung, und das Ergebnis dieser Aktion als skalaren Wert zurückgibt. (SQL Server-Referenz: Unterabschnitt CREATE FUNCTION).

Bemerkung

Diese Funktionen werden in der Regel innerhalb der Anweisung SELECToder bei der Einrichtung einer einzelnen Variablen (höchstwahrscheinlich innerhalb einer gespeicherten Prozedur) verwendet.

Transact-SQL-Syntax

 -- Transact-SQL Scalar Function Syntax
CREATE [ OR ALTER ] FUNCTION [ schema_name. ] function_name
( [ { @parameter_name [ AS ][ type_schema_name. ] parameter_data_type
 [ = default ] [ READONLY ] }
    [ ,...n ]
  ]
)
RETURNS return_data_type
    [ WITH <function_option> [ ,...n ] ]
    [ AS ]
    BEGIN
        function_body
        RETURN scalar_expression
    END
[ ; ]
Copy

Snowflake-Syntax

Snowflake erlaubt 3 verschiedene Sprachen in den benutzerdefinierten Funktionen:

  • SQL

  • JavaScript

  • Java

Vorerst wird SnowConvert nur SQL und JavaScript als Zielsprachen unterstützen.

Bemerkung

Benutzerdefinierte SQL-Funktionen unterstützen nur eine Abfrage als Body. Sie können aus der Datenbank lesen, aber nicht schreiben oder verändern. (Referenz zu skalaren SQL UDFs).

 CREATE [ OR REPLACE ] [ SECURE ] FUNCTION <name> ( [ <arg_name> <arg_data_type> ] [ , ... ] )
  RETURNS { <result_data_type> | TABLE ( <col_name> <col_data_type> [ , ... ] ) }
  [ [ NOT ] NULL ]
  [ { CALLED ON NULL INPUT | { RETURNS NULL ON NULL INPUT | STRICT } } ]
  [ VOLATILE | IMMUTABLE ]
  [ COMMENT = '<string_literal>' ]
  AS '<function_definition>'
Copy

Bemerkung

Benutzerdefinierte JavaScript-Funktionen erlauben mehrere Anweisungen in ihren Bodys, können aber keine Abfragen an die Datenbank durchführen. (Referenz zu skalaren JavaScript UDFs)

 CREATE [ OR REPLACE ] [ SECURE ] FUNCTION <name> ( [ <arg_name> <arg_data_type> ] [ , ... ] )
  RETURNS { <result_data_type> | TABLE ( <col_name> <col_data_type> [ , ... ] ) }
  [ [ NOT ] NULL ]
  LANGUAGE JAVASCRIPT
  [ { CALLED ON NULL INPUT | { RETURNS NULL ON NULL INPUT | STRICT } } ]
  [ VOLATILE | IMMUTABLE ]
  [ COMMENT = '<string_literal>' ]
  AS '<function_definition>'
Copy

Beispielhafte Quellcode-Muster

SET- und DECLARE-Anweisungen

Die häufigsten Anweisungen in Funktions-Bodys sind die Anweisungen DECLARE und SET. Bei DECLARE-Anweisungen ohne Standardwert wird die Transformation ignoriert. SET-Anweisungen und DECLARE-Anweisungen mit einem Standardwert werden in COMMON TABLE EXPRESSION umgewandelt. Jeder gemeinsame Tabellenausdruck enthält eine Spalte, die den Wert der lokalen Variablen darstellt.

Transact-SQL
 CREATE OR ALTER FUNCTION PURCHASING.GetVendorName()
RETURNS NVARCHAR(50) AS
BEGIN
	DECLARE @result NVARCHAR(50)
	DECLARE @BUSINESSENTITYID INT
	
	SET @BUSINESSENTITYID = 1492
	
	SELECT @result = Name FROM PURCHASING.VENDOR WHERE BUSINESSENTITYID = @BUSINESSENTITYID
	
	RETURN @result
END

GO

SELECT PURCHASING.GetVendorName() as vendor_name;
Copy
vendor_name            | 
-----------------------+ 
Australia Bike Retailer|

Copy
Snowflake
 CREATE OR REPLACE FUNCTION PURCHASING.GetVendorName ()
RETURNS VARCHAR(50)
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"transact"}}'
AS
$$
	WITH CTE1 AS
	(
		SELECT
			1492 AS BUSINESSENTITYID
	),
	CTE2 AS
	(
		SELECT
			Name AS RESULT
		FROM
			PURCHASING.VENDOR
		WHERE
			BUSINESSENTITYID = (
				SELECT
					BUSINESSENTITYID
				FROM
					CTE1
			)
	)
	SELECT
		RESULT
	FROM
		CTE2
$$;

SELECT
	PURCHASING.GetVendorName() as vendor_name;
Copy
VENDOR_NAME            |
-----------------------+
Australia Bike Retailer|

Copy

Transformation von IF/ELSE-Anweisung

IF/ELSE-Anweisungen können auf unterschiedliche Weise gehandhabt werden. Sie können entweder in Javascript oder in SQL transformiert werden, indem die CASE EXPRESSION innerhalb der SELECT-Anweisung die Bedingungen innerhalb der Abfragen zulässt. Während die Transformation in Javascript ziemlich einfach ist, ist die CASE-Anweisung auf den ersten Blick vielleicht nicht so offensichtlich.

Transact-SQL
 CREATE OR ALTER FUNCTION PURCHASING.HasActiveFlag(@BusinessEntityID int)
RETURNS VARCHAR(10) AS
BEGIN
	DECLARE @result VARCHAR(10)
	DECLARE @ActiveFlag BIT
	
	SELECT @ActiveFlag = ActiveFlag from PURCHASING.VENDOR v where v.BUSINESSENTITYID = @BusinessEntityID
	
	IF @ActiveFlag = 1
		SET @result = 'YES'
	ELSE IF @ActiveFlag = 0 
		SET @result = 'NO'
	
	RETURN @result
END

GO

SELECT PURCHASING.HasActiveFlag(1516) as has_active_flag;
Copy
has_active_flag|
---------------+
NO             |

Copy
Snowflake
 CREATE OR REPLACE FUNCTION PURCHASING.HasActiveFlag (P_BUSINESSENTITYID INT)
RETURNS VARCHAR(10)
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"transact"}}'
AS
$$
	WITH CTE1 AS
	(

		SELECT
			ActiveFlag AS ACTIVEFLAG
		from
			PURCHASING.VENDOR v
		where
			v.BUSINESSENTITYID = P_BUSINESSENTITYID
	),
	CTE2 AS
	(
		SELECT
			CASE
				WHEN (
					SELECT
						ACTIVEFLAG
					FROM
						CTE1
				) = 1
					THEN 'YES'
				WHEN (
					SELECT
						ACTIVEFLAG
					FROM
						CTE1
				) = 0
					THEN 'NO'
			END AS RESULT
	)
	SELECT
		RESULT
	FROM
		CTE2
$$;

SELECT
	PURCHASING.HasActiveFlag(1516) as has_active_flag;
Copy
HAS_ACTIVE_FLAG|
---------------+
NO             |

Copy

NESTED-Anweisungen

Bei NESTED-Anweisungen wird die strukturierte Programmierung in eine einzige Abfrage umgewandelt. Die Anweisungen in der Ablaufsteuerung werden in Tabellenstrukturen verschachtelt, um die Ausführungsreihenfolge beizubehalten.

Bemerkung

CASE EXPRESSIONS kann nur einen Wert pro Anweisung zurückgeben

Beispiel

Bemerkung

Der folgende Code ist in beiden Programmierparadigmen funktional gleichwertig.

 DECLARE @VendorId AS int;
DECLARE @AccountNumber AS VARCHAR(50);
SELECT @VendorId = poh.VendorID 
    FROM Purchasing.PurchaseOrderHeader poh
    WHERE PurchaseOrderID = 1
SELECT @AccountNumber = v.AccountNumber
    FROM Purchasing.Vendor v
    WHERE v.BusinessEntityID = @VendorId
Copy
 SELECT V.AccountNumber AccountNumber
FROM (SELECT poh.VendorID VendorId 
         FROM Purchasing.PurchaseOrderHeader poh
         WHERE PurchaseOrderID = 1
) T1, Purchasing.Vendor v
WHERE v.BusinessEntityID = T1.VendorId
Copy
AccountNumber|
-------------+
LITWARE0001  |

Copy

Bedingte Variablen durch SELECTs

Die Definition und Zuweisung von Variablen innerhalb von bedingten Anweisungen ist tendenziell etwas problematisch, da Verweise auf die Variable weiter unten im Code wissen müssten, wo die Variable zuletzt geändert wurde. Und nicht nur das: Wenn der Verweis innerhalb einer anderen bedingten Anweisung steht, müsste es eine Art Umleitung geben, die auf die vorherige bekannte Zuweisung an die Variable verweist.

Dies alles wird durch Verschachtelungen und komplexe Abfragen, die im Eingabecode zu finden sind, noch verschlimmert.

Im folgenden Szenario kann die erste IF-Anweisung ohne Probleme umgewandelt werden, da der Inhalt einfach genug ist. Die zweite und dritte IF-Anweisung sind auskommentiert, weil sie derzeit nicht unterstützt werden, da es andere Anweisungen als Variablenzuweisungen durch SELECT gibt.

SQL Server
 CREATE or ALTER FUNCTION PURCHASING.SELECTINUDF (
    @param1 varchar(12)
)
RETURNS int
AS
BEGIN
    declare @var1 int;
    declare @var2 int;
    declare @var3 int;

    IF @param1 = 'first'
    BEGIN
        select @var1 = col1 + 10 from table1 WHERE id = 0;
        select @var2 = col1 + 20 from table1 WHERE id = 0;
        select @var3 = col1 + 30 from table1 WHERE id = 0;
    END

    IF @param1 = 'second'
    BEGIN
        declare @var4 int = 10;
        select @var1 = col1 + 40 from table1 WHERE id = 0;
        select @var2 = col1 + 40 from table1 WHERE id = 0;
    END

    IF @param1 = 'third'
    BEGIN
        select col1 from table1 where id = 0;
        select @var1 = col1 + 50 from table1 WHERE id = 0;
        select @var2 = col1 + 50 from table1 WHERE id = 0;
    END

    RETURN @var1
END

SELECT PURCHASING.SELECTINUDF('first') as result; -- Assuming table1.col1 is 0 when ID = 0
Copy
RESULT|
------+
    10|

Copy
Snowflake
 CREATE OR REPLACE FUNCTION PURCHASING.SELECTINUDF (PARAM1 STRING)
RETURNS INT
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"transact"}}'
AS
$$
    WITH CTE1 AS
    (
        SELECT
            CASE
                WHEN PARAM1 = 'first'
                    THEN (SELECT
                        col1 + 10 AS VAR1 from
                        table1
                        WHERE
                        id = 0)
            END AS VAR1,
            CASE
                WHEN PARAM1 = 'first'
                        THEN (SELECT
                        col1 + 20 AS VAR2 from
                        table1
                        WHERE
                        id = 0)
            END AS VAR2,
            CASE
                WHEN PARAM1 = 'first'
                        THEN (SELECT
                        col1 + 30 AS VAR3 from
                        table1
                        WHERE
                        id = 0)
            END AS VAR3
    ),
    !!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'IF STATEMENT' NODE ***/!!!
    CTE2 AS
    (
        /*    IF @param1 = 'second'
            BEGIN
                declare @var4 int = 10;
                select @var1 = col1 + 40 from table1 WHERE id = 0;
                select @var2 = col1 + 40 from table1 WHERE id = 0;
            END*/
        SELECT
            null
    ),
    !!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'IF STATEMENT' NODE ***/!!!
    CTE3 AS
    (
        /*    IF @param1 = 'third'
            BEGIN
                select col1 from table1 where id = 0;
                select @var1 = col1 + 50 from table1 WHERE id = 0;
                select @var2 = col1 + 50 from table1 WHERE id = 0;
            END*/
        SELECT
            null
    ),
    CTE4 AS
    (

        SELECT
            PURCHASING.SELECTINUDF('first') as result
    )
    SELECT
        VAR1
    FROM
        CTE4
$$ -- Assuming table1.col1 is 0 when ID = 0
;
Copy
RESULT|
------+
    10|

Copy

Eine Variable zuweisen und zurückgeben

In diesem einfachen Muster gibt es eine Variablendeklaration, dann wird diese Variable mit einer SELECT-Anweisung gesetzt und schließlich zurückgegeben. Diese wird in einen allgemeinen Tabellenausdruck umgewandelt, um die ursprüngliche Verhaltensweise beizubehalten.

SQL Server
 CREATE OR ALTER FUNCTION Purchasing.GetTotalFreight()
RETURNS MONEY AS
BEGIN
	DECLARE @Result MONEY
	SELECT @Result = ISNULL(SUM(t.Freight), 0) from Purchasing.PurchaseOrderHeader t
	return @Result
END

GO

select Purchasing.GetTotalFreight() as Result;
Copy
Result      |
------------+
1583978.2263|

Copy
Snowflake
 CREATE OR REPLACE FUNCTION Purchasing.GetTotalFreight ()
RETURNS NUMBER(38, 4)
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"transact"}}'
AS
$$
	WITH CTE1 AS
	(
		SELECT
			NVL(SUM(t.Freight), 0) AS RESULT from
			Purchasing.PurchaseOrderHeader t
	)
	SELECT
		RESULT
	FROM
		CTE1
$$;

select
	Purchasing.GetTotalFreight() as Result;
Copy
RESULT      |
------------+
1583978.2263|

Copy

Aufrufe mehrerer Funktionen

Für dieses spezielle Muster gibt es keine offensichtlichen Abfragen, aber es gibt mehrere Aufrufe mehrerer Funktionen, die mit derselben Variable arbeiten und sie am Ende zurückgeben. Da Snowflake nur Abfragen innerhalb seiner Funktionen unterstützt, besteht die Lösung für diesen Block darin, ihn zu einem Select hinzuzufügen und die Aufrufe darin zu verschachteln, wobei sicherzustellen ist, dass der Rückgabewert mit dem der Quelle übereinstimmt.

SQL Server
 CREATE OR ALTER FUNCTION PURCHASING.Foo
(
	@PARAM1	INT
)
RETURNS varchar(25)
AS
BEGIN
	DECLARE @filter INT = @PARAM1
	DECLARE @NAME VARCHAR(25) = (SELECT Name from Purchasing.Vendor v where BusinessEntityID = @filter) 
	SET @NAME = REPLACE(@NAME, 'Australia', 'USA')
	SET @NAME = REPLACE(@NAME, 'Bike', 'Car')
	RETURN @NAME
END

GO

SELECT PURCHASING.Foo(1492) AS Name;
Copy
Name            |
----------------+
USA Car Retailer|

Copy
Snowflake
 CREATE OR REPLACE FUNCTION PURCHASING.Foo (PARAM1 INT)
RETURNS VARCHAR(25)
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"transact"}}'
AS
$$
	WITH CTE1 AS
	(
		SELECT
			PARAM1 AS FILTER
	),
	CTE2 AS
	(
		SELECT
			(SELECT
					Name
				from
					Purchasing.Vendor v
				where
					BusinessEntityID = (
						SELECT
							FILTER
						FROM
							CTE1
					)
			) AS NAME
	),
	CTE3 AS
	(
		SELECT
			REPLACE((
				SELECT
					NAME
				FROM
					CTE3
			), 'Australia', 'USA') AS NAME
	),
	CTE4 AS
	(
		SELECT
			REPLACE((
				SELECT
					NAME
				FROM
					CTE4
			), 'Bike', 'Car') AS NAME
	)
	SELECT
		NAME
	FROM
		CTE4
$$;

SELECT
	PURCHASING.Foo(1492) AS Name;
Copy
NAME            |
----------------+
USA Car Retailer|

Copy

Eine Variable basierend auf mehreren IF Bedingungen erhöhen und ihren Wert zurückgeben

Bei diesem Muster wird eine Variable durch mehrere IF-Bedingungen verändert (in diesem Fall erhöht). Zu Beginn wird ein Satz von Variablen initialisiert und verwendet, um zu bestimmen, ob die Ergebnisvariable erhöht werden soll oder nicht. Schließlich wird die Ergebnisvariable zurückgegeben.

SQL Server
 CREATE OR ALTER FUNCTION PURCHASING.FOO() 
RETURNS MONEY
AS
BEGIN
	declare @firstValue MONEY
	declare @secondValue MONEY
	declare @Result MONEY
	select  @Result = 0
	select 	@firstValue = SubTotal from Purchasing.PurchaseOrderHeader where PurchaseOrderID = 1
	select 	@secondValue = SubTotal from Purchasing.PurchaseOrderHeader where PurchaseOrderID = 2
	if @firstValue is not null
		select @Result = @Result + @firstValue
	if @secondValue is not null
		select @Result = @Result + @secondValue
	return @Result 
END

GO

SELECT PURCHASING.Foo() AS Result;
Copy
Result  |
--------+
473.1415|

Copy
Snowflake
CREATE OR REPLACE FUNCTION PURCHASING.FOO ()
RETURNS NUMBER(38, 4)
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"transact"}}'
AS
$$
	WITH CTE1 AS
	(
		select
			0 AS RESULT
	),
	CTE2 AS
	(
		select
			SubTotal AS FIRSTVALUE
		from
			Purchasing.PurchaseOrderHeader
		where
			PurchaseOrderID = 1
	),
	CTE3 AS
	(
		select
			SubTotal AS SECONDVALUE
		from
			Purchasing.PurchaseOrderHeader
		where
			PurchaseOrderID = 2
	),
	CTE4 AS
	(
		SELECT
			CASE
				WHEN (
					SELECT
						FIRSTVALUE
					FROM
						CTE2
				) is not null
					THEN (
					select
						(
							SELECT
								RESULT
							FROM
								CTE1
						) + (
							SELECT
								FIRSTVALUE
							FROM
								CTE2
						) AS RESULT)
			END AS RESULT
	),
	CTE5 AS
	(
		SELECT
			CASE
				WHEN (
					SELECT
						SECONDVALUE
					FROM
						CTE3
				) is not null
					THEN (
					select
						(
							SELECT
								RESULT
							FROM
								CTE1
						) + (
							SELECT
								SECONDVALUE
							FROM
								CTE3
						) AS RESULT)
				ELSE (SELECT
					RESULT
				FROM
					CTE4)
			END AS RESULT
	)
	SELECT
		RESULT
	FROM
		CTE5
$$;

SELECT
	PURCHASING.Foo() AS Result;
Copy
RESULT  |
--------+
473.1415|

Copy

Zwei oder mehrere RETURN-Anweisungen

Bei diesem Muster wird der IF-Block, der die RETURN-Klausel enthält, die den Codefluss unterbricht, am Ende des Bodys hinzugefügt, wie die letzte auszuführende Anweisung in einem CASE-Ausdruck.

Grundlegender Fall

In diesem speziellen Szenario gibt es keine Logik zwischen der bedingten RETURN-Anweisung und der abschließenden RETURN-Anweisung, so dass der gesamte Text-Bodys einem einzigen CASE EXPRESSION zugeordnet wird.

SQL Server
 CREATE OR ALTER FUNCTION [PURCHASING].[FOO] ()
RETURNS INT
AS
BEGIN
	IF exists (SELECT PreferredVendorStatus FROM Purchasing.Vendor v )
		RETURN 1

	RETURN 0
END

GO

SELECT PURCHASING.FOO() as result;
Copy
result|
------+
     1|

Copy
Snowflake
 CREATE OR REPLACE FUNCTION PURCHASING.FOO ()
RETURNS INT
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"transact"}}'
AS
$$
	SELECT
		CASE
			WHEN exists (SELECT
					PreferredVendorStatus
				FROM
					Purchasing.Vendor v
			)
				THEN 1
			ELSE 0
		END
$$;

SELECT
	PURCHASING.FOO() as result;
Copy
RESULT|
------+
     1|

Copy

Allgemeine Tabellenausdrücke

Die allgemeinen Tabellenausdrücke werden wie im ursprünglichen Code beibehalten und mit den generierten Ausdrücken verkettet. SnowConvert ist in der Lage, zunächst alle ursprünglichen COMMON TABLE EXPRESSION-Namen zu identifizieren, um die Erzeugung doppelter Namen zu vermeiden.

SQL Server
 CREATE OR ALTER FUNCTION [PURCHASING].[FOO] 
(
	@status INT
) 
Returns INT
As
Begin 
	Declare @result as int = 0

	;WITH ctetable(RevisionNumber) as 
	(
		SELECT RevisionNumber
		FROM Purchasing.PurchaseOrderHeader poh
		where poh.Status = @status
	),
	finalCte As
	(
		SELECT RevisionNumber FROM ctetable	
	)
	
	Select @result = count(RevisionNumber) from finalCte	
	return @result;
End

GO

SELECT PURCHASING.FOO(4) as result;
Copy
result|
------+
  3689|

Copy
Snowflake
 CREATE OR REPLACE FUNCTION PURCHASING.FOO (STATUS INT)
Returns INT
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"transact"}}'
AS
$$
	WITH CTE1 AS
	(
		SELECT
			0 AS RESULT
	),
	ctetable (
		RevisionNumber
	) as
		(
			SELECT
			RevisionNumber
			FROM
			Purchasing.PurchaseOrderHeader poh
			where
			poh.Status = STATUS
		),
		finalCte As
		(
			SELECT
			RevisionNumber
		FROM
			ctetable
		),
		CTE2 AS
		(
		Select
			COUNT(RevisionNumber) AS RESULT from
			finalCte
		)
		SELECT
		RESULT
		FROM
		CTE2
$$;

SELECT
		PURCHASING.FOO(4) as result;
Copy
RESULT|
------+
  3689|

Copy

In JavaScript UDFs umwandeln

Wenn es mehrere Anweisungen gibt und die Funktion in keiner Weise auf die Datenbank zugreift, kann sie unter Beibehaltung der Funktionsäquivalenz in eine JavaScript-Funktion umgewandelt werden

SQL Server
 CREATE OR ALTER FUNCTION PURCHASING.GetFiscalYear 
(
	@DATE AS DATETIME
)
RETURNS INT
AS
BEGIN
	DECLARE @FiscalYear AS INT
	DECLARE @CurMonth AS INT
	SET @CurMonth = DATEPART(M,@DATE)
	SET @FiscalYear = DATEPART(YYYY, @DATE)
	IF (@CurMonth >= 7)
	BEGIN
		SET @FiscalYear = @FiscalYear + 1 
	END
	RETURN @FiscalYear
END

GO

SELECT PURCHASING.GetFiscalYear('2020-10-10') as DATE;
Copy
 CREATE OR ALTER FUNCTION PURCHASING.[getCleanChargeCode]
(
	@ChargeCode varchar(50)
)
returns varchar(50) as
begin
	declare @CleanChargeCode varchar(50),@Len int,@Pos int=2
	set @Pos=LEN(@ChargeCode)-1
	while @Pos > 1
	begin
		set @CleanChargeCode=RIGHT(@ChargeCode,@Pos)
		if TRY_CAST(@CleanChargeCode as bigint) is not null
			return @CleanChargeCode
		set @Pos=@Pos-1
	end
	set @Pos=LEN(@ChargeCode)-1
	while @Pos > 1
	begin
		set @CleanChargeCode=LEFT(@ChargeCode,@Pos)
		if TRY_CAST(@CleanChargeCode as bigint) is not null
			return @CleanChargeCode
		set @Pos=@Pos-1
	end
	return null
end

GO

SELECT PURCHASING.[getCleanChargeCode]('16test') AS CleanChargeCode;
Copy
DATE|
----+
2021|

Copy
CleanChargeCode|
---------------+
16             |

Copy
Snowflake
 --** SSC-FDM-0029 - USER DEFINED FUNCTION WAS TRANSFORMED TO SNOWFLAKE PROCEDURE **
CREATE OR REPLACE PROCEDURE PURCHASING.GetFiscalYear (DATE TIMESTAMP_NTZ(3))
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"transact"}}'
EXECUTE AS CALLER
AS
$$
	DECLARE
		FISCALYEAR INT;
		CURMONTH INT;
	BEGIN
		 
		 
		CURMONTH := DATE_PART(month, :DATE :: TIMESTAMP);
		FISCALYEAR := DATE_PART(year, :DATE :: TIMESTAMP);
		IF ((:CURMONTH >= 7)) THEN
			BEGIN
				FISCALYEAR := :FISCALYEAR + 1;
			END;
		END IF;
		RETURN :FISCALYEAR;
	END;
$$;


SELECT
	!!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'GetFiscalYear' NODE ***/!!!
	PURCHASING.GetFiscalYear('2020-10-10') as DATE;
Copy
 --** SSC-FDM-0029 - USER DEFINED FUNCTION WAS TRANSFORMED TO SNOWFLAKE PROCEDURE **
CREATE OR REPLACE PROCEDURE PURCHASING.getCleanChargeCode (CHARGECODE STRING)
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"transact"}}'
EXECUTE AS CALLER
AS
$$
	DECLARE
		CLEANCHARGECODE VARCHAR(50);
		LEN INT;
		POS INT := 2;
	BEGIN
		 
		POS := LEN(:CHARGECODE)-1;
		WHILE (:POS > 1) LOOP
			CLEANCHARGECODE := RIGHT(:CHARGECODE, :POS);
			IF (TRY_CAST(:CLEANCHARGECODE as BIGINT) is not null) THEN
				RETURN :CLEANCHARGECODE;
			END IF;
			POS := :POS -1;
		END LOOP;
		POS := LEN(:CHARGECODE)-1;
		WHILE (:POS > 1) LOOP
			CLEANCHARGECODE := LEFT(:CHARGECODE, :POS);
			IF (TRY_CAST(:CLEANCHARGECODE as BIGINT) is not null) THEN
				RETURN :CLEANCHARGECODE;
			END IF;
			POS := :POS -1;
		END LOOP;
		RETURN null;
	END;
$$;

SELECT
	PURCHASING.getCleanChargeCode('16test') !!!RESOLVE EWI!!! /*** SSC-EWI-0067 - UDF WAS TRANSFORMED TO SNOWFLAKE PROCEDURE, CALLING PROCEDURES INSIDE QUERIES IS NOT SUPPORTED ***/!!! AS CleanChargeCode;
Copy
DATE  |
------+
2021.0|

Copy
CLEANCHARGECODE|
---------------+
16             |

Copy

Bekannte Probleme

Warnung

Benutzerdefinierte Funktionen können nicht verwendet werden, um Aktionen durchzuführen, die den Zustand der Datenbank verändern

Warnung

Benutzerdefinierte Funktionen können keine OUTPUT INTO- Klausel enthalten, die eine Tabelle als Ziel hat

Warnung

Benutzerdefinierte Funktionen können DECLARE, OPEN, FETCH, CLOSE oder DEALLOCATE für einen CURSOR nicht verwenden. Verwenden Sie eine gespeicherte Prozedur, wenn Sie Cursors verwenden müssen.

Warnung

Benutzerdefinierte Funktionen können keine CONTROL-OF-FLOW-Anweisungen wie WHILE ausführen, wenn es mindestens einen Aufruf an die Datenbank gibt

Warnung

Benutzerdefinierte Funktionen mit Referenzen auf andere benutzerdefinierte Funktionen, die in gespeicherte Prozeduren umgewandelt wurden, werden ebenfalls in Prozeduren umgewandelt.

Warnung

Benutzerdefinierte Funktionen, die @@ROWCOUNT verwenden, werden in SQL nicht unterstützt und sollten in gespeicherte Prozeduren umgewandelt werden, um die Funktionsäquivalenz zu wahren.

Warnung

Benutzerdefinierte Funktionen mit SELECT Anweisungen, die sich selbst eine Variable zuweisen, werden in Snowflake nicht unterstützt. Siehe auch SELECT @local_variable

Für alle nicht unterstützten Fälle prüfen Sie bitte die entsprechenden EWIs und die unten stehenden Muster, um Empfehlungen und mögliche Umgehungslösungen zu erhalten.

Andere Bedingungen als IF/ELSE-Anweisungen neben Abfragen

Das nächste Szenario beinhaltet die Verwendung der „WHILE-Anweisung“ zusammen mit anderen Abfragen. Das Problem bei diesem Beispiel ist, dass es keine Möglichkeit gibt, die WHILE-Anweisung innerhalb der WITH-Klausel des Haupt-Select in eine CTE umzuwandeln. Dadurch sind wir gezwungen, diese Anweisung in eine JavaScript-Prozedur umzuwandeln, um die gleiche Logik zu erhalten.

SQL Server
 CREATE OR ALTER FUNCTION PURCHASING.FOO()
RETURNS INT
AS
BEGIN
    DECLARE @i int = 0, @p int;
    Select @p = COUNT(*) FROM PURCHASING.VENDOR
    
    WHILE (@p < 1000)
    BEGIN
        SET @i = @i + 1
        SET @p = @p + @i
    END
        
    IF (@i = 6)
        RETURN 1
    
    RETURN @p
END

GO

SELECT PURCHASING.FOO() as result;
Copy
result|
------+
  1007|

Copy

Snowflake

 --** SSC-FDM-0029 - USER DEFINED FUNCTION WAS TRANSFORMED TO SNOWFLAKE PROCEDURE **
CREATE OR REPLACE PROCEDURE PURCHASING.FOO ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"transact"}}'
EXECUTE AS CALLER
AS
$$
    DECLARE
        I INT := 0;
        P INT;
    BEGIN
         
        Select
            COUNT(*)
        INTO
            :P
 FROM
            PURCHASING.VENDOR;
        WHILE (:P < 1000) LOOP
            I := :I + 1;
            P := :P + :I;
        END LOOP;
        IF ((:I = 6)) THEN
            RETURN 1;
        END IF;
        RETURN :P;
    END;
$$;

SELECT
    PURCHASING.FOO() !!!RESOLVE EWI!!! /*** SSC-EWI-0067 - UDF WAS TRANSFORMED TO SNOWFLAKE PROCEDURE, CALLING PROCEDURES INSIDE QUERIES IS NOT SUPPORTED ***/!!! as result;
Copy
FOO |
----+
1007|

Copy

Zuweisung einer Variablen unter Verwendung ihres eigenen Werts bei der Iteration durch einen Rowset

Im folgenden Beispiel wird die Variable @names verwendet, um mehrere Werte aus einer Spalte zu einer einzigen Zeichenfolge zu verketten. Die Variable wird wie gezeigt bei jeder Iteration aktualisiert, was von SnowFlake UDFs nicht unterstützt wird. Für dieses Szenario sollte die Funktion in eine Prozedur umgewandelt werden.

SQL Server

 CREATE OR ALTER FUNCTION PURCHASING.FOO()
RETURNS VARCHAR(8000)
AS
BEGIN
    DECLARE @names varchar(8000)
    SET @names = ''
    SELECT @names = ISNULL(@names + ' ', '') + Name from Purchasing.Vendor v 
    return @names              
END

GO

select PURCHASING.FOO() as names;
Copy
names                                                                                                                                                                                                                                                          |
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 Australia Bike Retailer Allenson Cycles Advanced Bicycles Trikes, Inc. Morgan Bike Accessories Cycling Master Chicago Rent-All Greenwood Athletic Company Compete Enterprises, Inc International Light Speed Training Systems Gardner Touring Cycles Internati|

Copy

Snowflake-Abfrage

 --** SSC-FDM-0029 - USER DEFINED FUNCTION WAS TRANSFORMED TO SNOWFLAKE PROCEDURE **
CREATE OR REPLACE PROCEDURE PURCHASING.FOO ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"transact"}}'
EXECUTE AS CALLER
AS
$$
    DECLARE
        NAMES VARCHAR(8000);
    BEGIN
         
        NAMES := '';
        SELECT
            NVL(:NAMES || ' ', 0) + Name
        INTO
            :NAMES
        from
            Purchasing.Vendor v;
        RETURN :NAMES;
    END;
$$;

select
    PURCHASING.FOO() !!!RESOLVE EWI!!! /*** SSC-EWI-0067 - UDF WAS TRANSFORMED TO SNOWFLAKE PROCEDURE, CALLING PROCEDURES INSIDE QUERIES IS NOT SUPPORTED ***/!!! as names;
Copy

Warnung

Beachten Sie bei den oben beschriebenen Szenarien die folgenden Beschränkungen:

  1. Alle Aufrufe von benutzerdefinierten Funktionen in DML-Abfragen wie SELECT, INSERT, DELETE, UPDATE oder MERGE werden fehlschlagen, da Aufrufe von gespeicherten Prozeduren in diesen Abfragen nicht erlaubt sind.

  2. Aufrufen von benutzerdefinierten Funktionen innerhalb von Prozeduren sollte das Schlüsselwort CALL vorangestellt werden.

  3. Benutzerdefinierte Funktionen, die in COMPUTED COLUMNS verwendet werden, schlagen bei der Ausführung fehl.

Zugehörige EWIs

  1. [SSC-EWI-0067](../../general/technical-documentation/issues-and-troubleshooting/conversion-issues/generalEWI. md#ssc-ewi-0067): UDF wurde in eine Snowflake-Prozedur umgewandelt, der Aufruf von Prozeduren innerhalb einer Abfrage wird nicht unterstützt.

  2. [SSC-EWI-0073](../../general/technical-documentation/issues-and-troubleshooting/conversion-issues/generalEWI. md#ssc-ewi-0073): Überprüfung der Funktionsäquivalenz ausstehend.

  3. [SSC-FDM-0029](../../general/technical-documentation/issues-and-troubleshooting/functional-difference/generalFDM. md#ssc-fdm-0029): Eine benutzerdefinierte Funktion wurde in eine Snowflake-Prozedur umgewandelt.