SQL Server 2008 - Implementing DECODE - sql

First, I know there are plenty of posts etc relating to the use of CASE in place of DECODE, but they don't appear to fit with my concern.
I am trying to convert an Oracle PL/SQL procedure to SQL Server. The procedure builds a SQL statement dynamically, and uses the DECODE function to create a x-tab. The procedure is as so:
PROCEDURE GET_XFORM_DATALOGS (
fLOTCODE IN VARCHAR2,
THEDATA OUT SYS_REFCURSOR) IS
-- VARIABLE DECLARATIONS
TYPE loc_array_type IS TABLE OF VARCHAR2(40); -- array type
loc_array loc_array_type; -- array for test names
prod VARCHAR2(20); -- product ID
step VARCHAR2(20); -- step ID
sql_str VARCHAR2(32000); -- SQL statement
-- EXECUTABLE CODE
BEGIN -- executable part starts here
-- get the test names for the given lot code
SELECT
PT_TESTNAME BULK COLLECT INTO loc_array
FROM
(
SELECT DISTINCT
TESTPARMS.PT_TESTNAME,
TESTPARMS.PT_TESTNUM
FROM
"PRETEST".PRETEST_LOT#PRS_DBLINK LOT,
"PRETEST".PRETEST_MEASURE#PRS_DBLINK MEASURE,
"PRETEST".PRETEST_TEST_PARMS#PRS_DBLINK TESTPARMS
WHERE
LOT.PT_LOTSQ = MEASURE.PT_LOTSQ AND
MEASURE.PT_LOTSQ = TESTPARMS.PT_LOTSQ AND
MEASURE.PT_TESTNUM = TESTPARMS.PT_TESTNUM AND
LOT.PT_LOTID = fLOTCODE
ORDER BY
PT_TESTNUM
);
-- build the SQL string
sql_str := '';
sql_str := sql_str || 'SELECT ';
sql_str := sql_str || ' PRETEST_LOT.PT_LOTID, ';
sql_str := sql_str || ' PRETEST_LOT.PT_LOCTYPE, ' ;
sql_str := sql_str || ' PRETEST_LOT.PT_TESTDATE, ';
sql_str := sql_str || ' PRETEST_MEASURE.PT_WAFERID, ';
sql_str := sql_str || ' PRETEST_MEASURE.PT_XCOORD, ';
sql_str := sql_str || ' PRETEST_MEASURE.PT_YCOORD, ';
-- add the decodes for column headings
FOR i IN loc_array.first..loc_array.last LOOP
sql_str := sql_str || 'max ( decode ( PRETEST_TEST_PARMS.PT_TESTNAME, '''
|| loc_array(i) || ''', PRETEST_MEASURE.PT_MEAS_VALUE, null ) ) '
|| loc_array(i);
IF (i < loc_array.last) THEN
sql_str := sql_str || ', ';
END IF;
END LOOP;
-- build the remainder of the SQL
sql_str := sql_str || ' FROM ';
sql_str := sql_str || ' "PRETEST".PRETEST_LOT#PRS_DBLINK PRETEST_LOT, ';
sql_str := sql_str || ' "PRETEST".PRETEST_MEASURE#PRS_DBLINK PRETEST_MEASURE, ';
sql_str := sql_str || ' "PRETEST".PRETEST_TEST_PARMS#PRS_DBLINK PRETEST_TEST_PARMS ';
sql_str := sql_str || ' WHERE ';
sql_str := sql_str || ' PRETEST_LOT.PT_LOTSQ = PRETEST_MEASURE.PT_LOTSQ AND ';
sql_str := sql_str || ' PRETEST_MEASURE.PT_LOTSQ = PRETEST_TEST_PARMS.PT_LOTSQ AND ';
sql_str := sql_str || ' PRETEST_MEASURE.PT_TESTNUM = PRETEST_TEST_PARMS.PT_TESTNUM AND ';
sql_str := sql_str || ' (PRETEST_LOT.PT_LOTID = :fFLOTCODE) ';
sql_str := sql_str || ' GROUP BY ';
sql_str := sql_str || ' PRETEST_LOT.PT_LOTID, ';
sql_str := sql_str || ' PRETEST_LOT.PT_LOCTYPE, ';
sql_str := sql_str || ' PRETEST_LOT.PT_TESTDATE, ';
sql_str := sql_str || ' PRETEST_MEASURE.PT_WAFERID, ';
sql_str := sql_str || ' PRETEST_MEASURE.PT_XCOORD, ';
sql_str := sql_str || ' PRETEST_MEASURE.PT_YCOORD ';
sql_str := sql_str || ' ORDER BY ';
sql_str := sql_str || ' PRETEST_LOT.PT_TESTDATE ';
-- run the query
OPEN THEDATA FOR sql_str USING fLOTCODE;
END GET_XFORM_DATALOGS;
The question I have is, is this going to be possible to implement in SQL Server? I can't seem to work out how to use CASE WHEN THEN etc to create column headings based on the dynamic data.
Sorry if what I've asked is unclear. Thanks for any help you can offer.
BBz

Well the Oracle equivalent using CASE would be:
sql_str := sql_str || 'max ( CASE WHEN PRETEST_TEST_PARMS.PT_TESTNAME = '''
|| loc_array(i) || ''' THEN PRETEST_MEASURE.PT_MEAS_VALUE END ) '
|| loc_array(i);
So try converting that to SQL Server instead.

Related

Print a json structure from a dynamic query

I want to create function that return a CLOB with a json content.
But first i want to print the result (see query code) to see how it looks like.
The result must be a json, that will contain the information for 1 record just, this record select query, must be created dynamically.
So I try the next query, to resolve this problem. but i get an error.
Query
declare
v_stmt VARCHAR2(1000);
l_sep varchar2(1) := chr(10);
l_tab varchar2(1) := chr(9);
up_column VARCHAR2(50);
low_column VARCHAR2(50);
cur_asc SYS_REFCURSOR;
Vcdogcur SYS_REFCURSOR;
id_ccd number;
first boolean := true;
begin
id_ccd := 174;
v_stmt := 'select ';
open cur_asc for
SELECT column_name as up_column
,lower(column_name) as low_column
FROM USER_TAB_COLUMNS
WHERE table_name = upper('my_table');
loop
FETCH cur_asc
INTO up_column, low_column;
EXIT WHEN cur_asc%NOTFOUND;
if not first then
v_stmt := v_stmt || ',';
end if;
first := false;
v_stmt := v_stmt || l_sep || l_tab ||up_column || ' as ' || low_column;
END LOOP;
--v_stmt := v_stmt || l_sep || 'from my_table' || l_sep ||'where id = ' || id_ccd || ';';
v_stmt := v_stmt || l_sep || 'from my_table' || l_sep ||'where id = ' || id_ccd;
DBMS_OUTPUT.PUT_LINE('salida: ' || v_stmt);
CLOSE cur_asc;
--v_stmt := v_stmt || l_sep || 'from my_table' || l_sep ||'where id = ' || id_ccd;
--DBMS_OUTPUT.PUT_LINE('salida: ' || v_stmt);
open Vcdogcur for v_stmt;
APEX_JSON.initialize_clob_output;
APEX_JSON.open_object;
APEX_JSON.write('my_table', Vcdogcur);
APEX_JSON.close_object;
DBMS_OUTPUT.put_line(APEX_JSON.get_clob_output);
CLOSE Vcdogcur;
end;
/
DBMS output
salida: select
CREATED as created,
CREATED_BY as created_by,
UPDATED as updated,
UPDATED_BY as updated_by,
ID as id,
TEXT as text,
PART as part,
CODE as code,
DATE as date,
PERCENTAGE as percentage
from my_table
where id = 174
{
"my_table":[
{
"CREATED":"2020-06-04T08:10:09.000000000Z"
,"CREATED_BY":"APEX_APP"
,"UPDATED":"2020-06-04T10:10:09.295632000Z"
,"UPDATED_BY":"APEX_APP"
,"ID":174
,"TEXT":"ALL"
,"PART":2770
,"CODE":2212
,"DATE":"2017-01-01T00:00:00.000000000Z"
,"PERCENTAGE":-4.98
}
]
}
Error
Informe de error -
ORA-01001: cursor no válido
ORA-06512: en línea 44
01001. 00000 - "invalid cursor"
*Cause:
*Action:
Can somebody help me to resolve this?
Best Regards

error when executing a varchar2 in a procedure

I have a varchar2 with an INSERT and I want to execute it in a procedure I try to do it with an execute but this happens:
EXECUTE IMMEDIATE sql_str;
Error:
ERROR at line 1:
ORA-00911: invalid character
ORA-06512: at "SYS.INSERT_MOVIMIENTOS", line 47
ORA-06512: at line 1
Varchar2 carries an insert that is this and works if I paste it but when executing it in the procedure something of the procedure fails.
INSERT INTO MOVIMIENTOS (COD_BANCO, COD_SUCUR, NUM_CTA, FECHA_MOV, TIPO_MOV, IMPORTE) VALUES (2000, 2000, 0, '11/11/08', 'I', 500);
My procedure
CREATE OR REPLACE PROCEDURE INSERT_MOVIMIENTOS (
INSERTMOV_COD_BANCO IN NUMBER,
INSERTMOV_COD_SUCUR IN NUMBER,
INSERTMOV_NUM_CTA IN NUMBER,
INSERTMOV_FECHA_MOV IN DATE,
INSERTMOV_TIPO_MOV IN CHAR,
INSERTMOV_IMPORTE IN NUMBER
)
IS
sql_str VARCHAR2(500) := 'INSERT INTO MOVIMIENTOS (';
movimiento movimientos_typ;
BEGIN
movimiento := movimientos_typ(
INSERTMOV_COD_BANCO,
INSERTMOV_COD_SUCUR,
INSERTMOV_NUM_CTA,
INSERTMOV_FECHA_MOV,
INSERTMOV_TIPO_MOV,
INSERTMOV_IMPORTE
);
IF movimiento.getCOD_BANCO() != 0 THEN
sql_str := sql_str || 'COD_BANCO, COD_SUCUR, NUM_CTA, FECHA_MOV, TIPO_MOV, IMPORTE) VALUES (' ||
movimiento.getCOD_BANCO() || ', ' ||
movimiento.getCOD_SUCUR() || ', ' ||
movimiento.getNUM_CTA() || ', ''' ||
movimiento.getFECHA_MOV() || ''', ''' ||
movimiento.getTIPO_MOV() || ''', ' ||
movimiento.getIMPORTE() || ');';
ELSE
sql_str := sql_str || 'COD_SUCUR, NUM_CTA, FECHA_MOV, TIPO_MOV, IMPORTE) VALUES (' ||
movimiento.getCOD_SUCUR() || ', ' ||
movimiento.getNUM_CTA() || ', ''' ||
movimiento.getFECHA_MOV() || ''', ''' ||
movimiento.getTIPO_MOV() || ''', ' ||
movimiento.getIMPORTE() || ');';
END IF;
DBMS_OUTPUT.PUT_LINE('////////////////////////////////////////');
DBMS_OUTPUT.PUT_LINE('CONSULTA: ' || sql_str);
DBMS_OUTPUT.PUT_LINE('////////////////////////////////////////');
DBMS_OUTPUT.PUT_LINE('DATOS INTRODUCIDOS: ');
movimiento.display;
DBMS_OUTPUT.PUT_LINE('////////////////////////////////////////');
EXECUTE IMMEDIATE sql_str;
DBMS_OUTPUT.PUT_LINE('FUNCION REALIZADA CON EXITO');
END;
/
Donot end with the semicolon ; in your query string.
movimiento.getIMPORTE() || ')';
The error is just because of it.
by the way, you should be using bind variables. Dynamically constructing the values this way is vulnerable to SQL Injection.

debug oracle procedure

I have a oracle stored procedure, inputs is
p_processId = 5660
p_featureClassName ='future_parcels'
p_DrawnGeometry = MDSYS.SDO_GEOMETRY(2003, 2400000, null,
MDSYS.SDO_ELEM_INFO_ARRAY(1, 1003, 1, 27, 2003, 1),
MDSYS.SDO_ORDINATE_ARRAY(8439212.4589933194220066070556640625,
4540074.1191380098462104797363281250, 8439201.7998965308070182800292968750, 4540058.374383729882538318634033203125, 8439315.814959609881043434143066406250, 4540058.374466760084033012390136718750, 8439319.9868115298449993133544921875, 4540067.6362674199044704437255859375, 8439323.231370599940419197082519531250, 4540081.528450479730963706970214843750, 8439328.328618479892611503601074218750, 4540097.737373660318553447723388671875, 8439330.6458750404417514801025390625, 4540129.691041340120136737823486328125, 8439332.959363190457224845886230468750, 4540149.486472180113196372985839843750, 8439227.984901839867234230041503906250, 4540148.055711519904434680938720703125, 8439225.43722324073314666748046875, 4540138.489620880223810672760009765625, 8439223.1199580393731594085693359375, 4540118.576599569991230964660644531250, 8439220.802692830562591552734375, 4540098.663578259758651256561279296875, 8439212.4589933194220066070556640625, 4540074.1191380098462104797363281250, 8439252.6796298995614051818847656250, 4540086.660427900031208992004394531250, 8439243.2996299006044864654541015625, 4540125.440427900291979312896728515625, 8439299.99962989985942840576171875, 4540138.040427899919450283050537109375, 8439310.49962989985942840576171875, 4540098.280427900142967700958251953125, 8439252.6796298995614051818847656250, 4540086.660427900031208992004394531250))
Procedure:
CREATE OR REPLACE
PROCEDURE get_DrawnGeometries (
p_processId IN INTEGER
, p_featureClassName IN VARCHAR2
, p_DrawnGeometry IN SDO_GEOMETRY
, p_prm_val OUT VARCHAR2
)
IS
PRAGMA AUTONOMOUS_TRANSACTION;
CURSOR featClassAttributes_cur (featureClassName IN VARCHAR2) IS
SELECT
gac.id
, lower(gac.column_name) AS column_name
, gac.view_u_pk
, gac.data_type
, gas.naziv
, gat.table_name
FROM geo_atrib_columns gac
JOIN geo_atrib_tables gat ON gat.table_name = gac.table_name
JOIN geo_app_slojevi gas ON gas.naziv = gat.layer_name
WHERE gas.naziv = featureClassName
AND gat.aktivan = 1
AND gac.aktivan = 1
AND gac.view_iu_write = 1
ORDER BY gac.view_order;
vc_sql CLOB;
vc_sql2 CLOB;
vc_sql3 CLOB;
v_columns VARCHAR2(1000);
v_tableName VARCHAR2(1000);
v_whereClause VARCHAR2(1000);
v_whereClause2 VARCHAR2(1000);
v_g_col_name VARCHAR2(30);
v_tolerance VARCHAR2(20);
v_separator VARCHAR2(16) := ' || ''' || glob_var.v_strSeparator || ''' || ';
p_id INTEGER;
v_mssg VARCHAR2(500) := NULL;
BEGIN
vc_sql := 'SELECT #columns# FROM #table_name# WHERE #where_clause#';
vc_sql2 := 'SELECT #columns# FROM #table_name# WHERE #where_clause2#';
vc_sql3 := vc_sql;
FOR rt_att IN featClassAttributes_cur(p_featureClassName) LOOP
IF rt_att.data_type = 'N' THEN
v_columns := v_columns || v_separator || ' nvl(gt_util.num2CharPointSep(' || rt_att.column_name|| '), ''NULL'')';
ELSE
v_columns := v_columns || v_separator || ' nvl(to_char(' || rt_att.column_name|| '), ''NULL'')';
END IF;
IF v_tableName IS NULL THEN
v_tableName := rt_att.table_name;
END IF;
--dbms_output.put_line(v_tableName);
END LOOP;
v_columns := ltrim(v_columns, v_separator);
v_g_col_name := gt_util.get_layer_g_col(v_tableName);
v_tolerance := gt_util.num2CharPointSep(gt_util.get_layer_tollerance(v_tableName, v_g_col_name));
--v_whereClause := 'ins_id = {0} AND SDO_GEOM.RELATE(:geom, ''EQUAL+INSIDE+CONTAINS+COVEREDBY+COVERS+OVERLAPBDYINTERSECT'', ' || v_g_col_name || ', ' || v_tolerance || ') = ''EQUAL+INSIDE+CONTAINS+COVEREDBY+COVERS+OVERLAPBDYINTERSECT''';
v_whereClause := 'ins_id = {0} AND SDO_GEOM.RELATE(:geom, ''EQUAL'', ' || v_g_col_name || ', ' || v_tolerance || ') = ''EQUAL''';
v_whereClause2 := 'ins_id = {0} AND gt_util.geom_is_equal(:geom, ' || v_g_col_name || ', ' || v_tolerance || ') = ''TRUE''';
v_whereClause := replace(v_whereClause, '{0}', to_char(p_processId));
v_whereClause2 := replace(v_whereClause2, '{0}', to_char(p_processId));
vc_sql := replace(vc_sql, '#columns#', v_columns);
vc_sql := replace(vc_sql, '#table_name#', v_tableName);
vc_sql := replace(vc_sql, '#where_clause#', v_whereClause);
vc_sql2 := replace(vc_sql2, '#columns#', v_columns);
vc_sql2 := replace(vc_sql2, '#table_name#', v_tableName);
vc_sql2 := replace(vc_sql2, '#where_clause2#', v_whereClause2);
dbms_output.put_line(vc_sql);
dbms_output.put_line(vc_sql2);
BEGIN
EXECUTE IMMEDIATE vc_sql INTO p_prm_val USING p_DrawnGeometry;
EXCEPTION WHEN NO_DATA_FOUND THEN
EXECUTE IMMEDIATE vc_sql2 INTO p_prm_val USING p_DrawnGeometry;
WHEN TOO_MANY_ROWS THEN
vc_sql3 := replace(vc_sql3, '#columns#', 'id');
vc_sql3 := replace(vc_sql3, '#table_name#', v_tableName);
vc_sql3 := replace(vc_sql3, '#where_clause#', v_whereClause);
vc_sql3 := 'SELECT * FROM (' || vc_sql3 || ' ORDER BY id DESC) WHERE ROWNUM = 1';
EXECUTE IMMEDIATE vc_sql3 INTO p_id USING p_DrawnGeometry;
EXECUTE IMMEDIATE 'DELETE FROM ' || v_tableName || ' WHERE id = ' || p_id;
COMMIT;
v_mssg := 'Identical geometry already exists. Drawn geometry is deleted. If you want to delete new geometry please delete the old one first';
RAISE error_util.ep_UsrExc;
--dbms_output.put_line(vc_sql2);
END;
EXCEPTION WHEN error_util.ep_UsrExc THEN
ERROR_UTIL.log_and_raise(SQLCODE, SQLERRM, v_mssg, DBMS_UTILITY.FORMAT_ERROR_BACKTRACE);
RAISE;
END get_DrawnGeometries;
how I can check result and debug it output ?
when I can call it returned errors
Procedure execution failed ORA-06550: line 1, column 233: PLS-00382:
expression is of wrong type ORA-06550: line 1, column 213: PL/SQL:
Statement ignored
In PL/SQL Developer you can right click on procedure name, click test and start debbuging

PLSQL : Dynamic table record holder

If I want to fetch records from a table (table name is dynamic from input), how to define the record holder or how to fetch the data from this defined table? p_table_name%rowtype will not complie because p_table_name is a parameter, not a table name.
PROCEDURE do_scan(p_table_name IN VARCHAR2
,p_min_num IN NUMBER
,p_time_range IN NUMBER
,p_problem_desc OUT
,p_result_code OUT)
IS
TYPE ObjCurTyp IS REF CURSOR;
v_obj_cursor ObjCurTyp;
v_obj_record ???????(p_table_name%rowtype)
BEGIN
v_stmt_str := 'Select * from :t where date_started > TRUNC(SYSDATE-3)';
OPEN v_obj_cursor FOR v_stmt_str USING p_table_name;
LOOP
FETCH v_obj_cursor INTO v_obj_record;
EXIT WHEN v_obj_cursor %NOTFOUND;
END LOOP;
END do_scan;
You can put that code as a dynamic PL/SQL block within an EXECUTE IMMEDIATE statement.
PROCEDURE do_scan
(
p_table_name IN VARCHAR2
p_min_num IN NUMBER
p_time_range IN NUMBER
p_problem_desc OUT
p_result_code OUT
)
IS
BEGIN
EXECUTE IMMEDIATE
'DECLARE ' ||
' TYPE ObjCurTyp IS REF CURSOR; ' ||
' v_obj_cursor ObjCurTyp; ' ||
' v_obj_record ' || p_table_name || '%rowtype; '||
'BEGIN ' ||
' v_stmt_str := ''Select * from :t where ' ||
' date_started > TRUNC(SYSDATE-3)''; ' ||
' OPEN v_obj_cursor ' ||
' FOR v_stmt_str USING ' ||
p_table_name || '; ' ||
' LOOP ' ||
' FETCH v_obj_cursor INTO v_obj_record; ' ||
' EXIT WHEN v_obj_cursor %NOTFOUND; ' ||
' END LOOP; ' ||
'END;';
END do_scan;
Regards,
Dariyoosh

PL/SQL missing right parenthesis

Hey folks im getting a sql error all the way at the bottom
right before the execute statement at the end of the code block:
stmt := v_first_sql || stmt || v_order_by_sql || v_last_sql;
any ideas of what Im doing wrong?
thanks
FUNCTION search_data
(
p_start_ind IN NUMBER,
p_end_ind IN NUMBER,
p_cols_sort_by IN char_tab,
p_sort_orders IN char_tab,
p_sor_number IN VARCHAR2,
p_tcn IN VARCHAR2,
p_sock IN NUMBER,
p_work_id IN NUMBER,
p_sap in NUMBER
)
RETURN bean_list
IS
stmt VARCHAR2(4000);
result bean_list;
v_jp_ids VARCHAR2(50);
v_first_sql VARCHAR2(512);
v_row_count NUMBER;
BEGIN
v_row_count := p_end_index - p_start_index + 1;
v_first_sql := 'BEGIN ';
v_first_sql := v_first_sql || ' SELECT item_search( id, mwslin,sor_code, fyear, wyear,';
v_first_sql := v_first_sql || ' sock, tcn, non, nomen,sap';
v_first_sql := v_first_sql || ' row_count )';
v_first_sql := v_first_sql || ' BULK COLLECT INTO :bind_var1';
v_first_sql := v_first_sql || ' FROM';
v_first_sql := v_first_sql || ' (';
v_first_sql := v_first_sql || ' SELECT /*+ FIRST_ROWS(' || TO_CHAR(v_row_count) || ') */ ';
v_first_sql := v_first_sql || ' ROWNUM rnum, a.*';
v_first_sql := v_first_sql || ' FROM';
v_first_sql := v_first_sql || ' (';
v_first_sql := v_first_sql || ' SELECT ob.*, COUNT(*) OVER () AS row_count';
v_first_sql := v_first_sql || ' FROM';
v_first_sql := v_first_sql || ' (';
v_order_by_sql := ' ) ob ' || temp_pkg.get_number_by( p_columns_sort_by, p_sort_orders );
v_last_sql := ' ) a';
v_last_sql := v_last_sql || ' WHERE rownum <= ' || TO_CHAR(p_end_index);
v_last_sql := v_last_sql || ' )';
v_last_sql := v_last_sql || ' WHERE rnum >= ' || TO_CHAR(p_start_index);
v_last_sql := v_last_sql || ' ORDER BY rnum;';
v_last_sql := v_last_sql || ' END;';
stmt := v_first_sql || stmt
EXECUTE IMMEDIATE stmt USING OUT result;
RETURN result;
END search_data;
The parentheses in YOUR code appear to be balanced, so clearly the problem is in the text introduced by
temp_pkg.get_order_by( p_columns_sort_by, p_sort_orders )
This function must be returning unbalanced parens.
By the way, unless you've gone to great lengths to sanitize the input, this is a SQL injection attack waiting to happen.