Pass column name as a parameter - sql

I need to pass a column name from front end to back end in my code. i'm using c# with oracle and when i pass the column name as a parameter, it gives an error and it's because the column name is used as a string in here and i need to know how to fix this. here is my code,
PROCEDURE PR_GETCLIENTCONTRACTDATA(INSTRFIELD IN VARCHAR2,INSTRCONTRACTNO IN VARCHAR2,CUR_OUTPUT OUT T_CURSOR)--ADDED BY DIDULA 25/10/2017
IS
BEGIN
OPEN CUR_OUTPUT FOR
SELECT c.con_no,
DECODE (a.clm_cori,
'1', a.clm_cltitle || ' ' || a.clm_initialsfull || ' '
|| a.clm_name,
a.clm_name
) cliname,
a.clm_code,
( a.clm_permaddline1
|| '|'
|| a.clm_permaddline2
|| '|'
|| COALESCE (a.clm_permaddline3, a.clm_permaddline4)
|| '|'
|| NULLIF ((a.clm_permaddline4),
COALESCE (a.clm_permaddline3, a.clm_permaddline4)
)
) address
FROM leaseinfo.tblcontracts c, corpinfo.tblclientmain a
WHERE a.clm_code = c.con_clmcode
AND INSTRFIELD = INSTRCONTRACTNO; ***here INSTRFIELD is the column name
that i need to pass***
END PR_GETCLIENTCONTRACTDATA;

Whitelist the column names:
PROCEDURE PR_GETCLIENTCONTRACTDATA(
INSTRFIELD IN VARCHAR2,
INSTRCONTRACTNO IN VARCHAR2,
CUR_OUTPUT OUT T_CURSOR
)
IS
BEGIN
OPEN CUR_OUTPUT FOR
SELECT -- your select clauses
FROM leaseinfo.tblcontracts c,
INNER JOIN corpinfo.tblclientmain a -- ANSI join syntax
ON a.clm_code = c.con_clmcode
WHERE CASE INSTRFIELD
WHEN 'COLUMNA' THEN ColumnA
WHEN 'COLUMNB' THEN ColumnB
WHEN 'COLUMNC' THEN ColumnC
END = INSTRCONTRACTNO;
END PR_GETCLIENTCONTRACTDATA;
/

When you use OPEN cur FOR ... you can pass a string, i.e.
PROCEDURE PR_GETCLIENTCONTRACTDATA(INSTRFIELD IN VARCHAR2,INSTRCONTRACTNO IN VARCHAR2,CUR_OUTPUT OUT T_CURSOR)
IS
BEGIN
OPEN CUR_OUTPUT FOR
'SELECT c.con_no,
DECODE (a.clm_cori,
''1'', a.clm_cltitle || '' '' || a.clm_initialsfull || '' ''
|| a.clm_name,
a.clm_name
) cliname,
a.clm_code,
( a.clm_permaddline1
|| ''|''
|| a.clm_permaddline2
|| ''|''
|| COALESCE (a.clm_permaddline3, a.clm_permaddline4)
|| ''|''
|| NULLIF ((a.clm_permaddline4),
COALESCE (a.clm_permaddline3, a.clm_permaddline4)
)
) address
FROM leaseinfo.tblcontracts c
JOIN corpinfo.tblclientmain a ON a.clm_code = c.con_clmcode
WHERE '||DBMS_ASSERT.SIMPLE_SQL_NAME(INSTRFIELD)||' = :INSTRCONTRACTNO)'
USING INSTRCONTRACTNO;
END PR_GETCLIENTCONTRACTDATA;

Related

How can i turn this pl/sql into a procedure

I had to write this query for an assignement. So we have a database and we are pulling information from it, this is going to work with some back end c# eventually. Is there anything i can do , knowing im going to reuse this, in order to make it better and more adaptable when the day comes when i have to connect it all.
set serveroutput on
DECLARE
LV_DATE HVK_RESERVATION.RESERVATION_START_DATE%TYPE;
LV_SERV VARCHAR(100);
CURSOR LCUR_RES IS
SELECT *
FROM HVK_RESERVATION R
INNER JOIN HVK_PET_RESERVATION PR
ON R.RESERVATION_NUMBER = PR.RES_RESERVATION_NUMBER
INNER JOIN HVK_PET P
ON P.PET_NUMBER = PR.PET_PET_NUMBER
INNER JOIN HVK_OWNER OW
ON OW.OWNER_NUMBER = P.OWN_OWNER_NUMBER
WHERE R.RESERVATION_START_DATE < LV_DATE
AND R.RESERVATION_END_DATE > LV_DATE;
CURSOR LCUR_SERVICE(PET_RES_NUM NUMBER) IS
SELECT *
FROM HVK_SERVICE S
INNER JOIN HVK_PET_RESERVATION_SERVICE PRS
ON PRS.SERV_SERVICE_NUMBER = S.SERVICE_NUMBER
AND PRS.PR_PET_RES_NUMBER = PET_RES_NUM;
BEGIN
LV_DATE := TO_DATE('&logdate', 'yy-mm-dd');
DBMS_OUTPUT.PUT_LINE('Kennel log for ' || '' || LV_DATE);
DBMS_OUTPUT.PUT_LINE('-------------------------------');
FOR I IN LCUR_RES LOOP
DBMS_OUTPUT.PUT_LINE('Run:' || '' || I.RUN_RUN_NUMBER || ' ' ||
'Pet: ' || '' || I.PET_NAME || ' ' ||
I.OWNER_LAST_NAME || ' Pet Reservation: ' || '' ||
I.PET_RES_NUMBER);
DBMS_OUTPUT.PUT_LINE('Reservation start/end ' || ' ' ||
I.RESERVATION_START_DATE || ' ' ||
I.RESERVATION_END_DATE);
DBMS_OUTPUT.PUT('Services : ');
FOR X IN LCUR_SERVICE(I.PET_RES_NUMBER) LOOP
DBMS_OUTPUT.PUT(X.SERVICE_DESCRIPTION || ' ');
END LOOP;
DBMS_OUTPUT.PUT_LINE('');
FOR LREC_LOG IN (SELECT *
FROM HVK_KENNEL_LOG KL
WHERE KL.PR_PET_RES_NUMBER = I.PET_RES_NUMBER
) LOOP
DBMS_OUTPUT.PUT_LINE('Notes: ' || '' ||
LREC_LOG.KENNEL_LOG_SEQUENCE_NUMBER || ' ' ||
'Log Note: ' || '' || LREC_LOG.KENNEL_LOG_NOTES);
END LOOP;
DBMS_OUTPUT.PUT_LINE(' ');
END LOOP;
END;
It it supposed to output the run number , reservation number , pet name , and any relate notes.
you can replace DECLARE with CREATE OR REPLACE PROCEDURE my_proc(in_logdate in date) IS.
in that case my_proc will be the name of your procedure.
you should also use a parameter instead of &logdate
so e.g. parameter name in_logdate of type date
...
LV_DATE := in_logdate;
...

Execute immediate UPDATE Statement

I try to make an update table CHECK_COMPRESSER into PROCEDURE and I use EXECUTE IMMEDIATE :
EXECUTE immediate 'update CHECK_COMPRESSER
set NEW_SIZE_MB = '||''''||TABLE_P_ENTRY.NEW_SIZE_MB || '''' ||
' WHERE EXEC_ID = ' || '''' || EXEC_ID || '''' || ' AND TABLE = ' || '''' || TABLE_P_ENTRY.SEGMENT_NAME || '''' || ' AND PARTITION = ' || '''' || TABLE_P_ENTRY.PARTITION_NAME || '''';
dbms_output.put_line shows:
update CHECK_COMPRESSER set NEW_SIZE_MB = '182' WHERE EXEC_ID = '43' AND TABLE = 'MA_CONTACT_COMPRESS' AND PARTITION = 'P_OLD'
but there is an error:
ORA-00936: missing expression ORA-06512: at "SASDBA.COMPRESS_TABLE",
line 50
so, how should I edit this code?
TABLE is a keyword. It can be used as identifier only if quoted: "TABLE".
P.S. PARTITION is the same.

Sanitize user input with the USING keyword in PL/pgSQL

This is how I create my search_term:
IF char_length(search_term) > 0 THEN
order_by := 'ts_rank_cd(textsearchable_index_col, to_tsquery(''' || search_term || ':*''))+GREATEST(0,(-1*EXTRACT(epoch FROM age(last_edited)/86400))+60)/60 DESC';
search_term := 'to_tsquery(''' || search_term || ':*'') ## textsearchable_index_col';
ELSE
search_term := 'true';
END IF;
I am having some trouble with a PLPGSQL function:
RETURN QUERY EXECUTE '
SELECT
*
FROM
articles
WHERE
$1 AND
' || publication_date_query || ' AND
primary_category LIKE ''' || category_filter || ''' AND
' || tags_query || ' AND
' || districts_query || ' AND
' || capability_query || ' AND
' || push_notification_query || ' AND
' || distance_query || ' AND
' || revision_by || ' AND
' || publication_priority_query || ' AND
' || status_query || ' AND
is_template = ' || only_templates || ' AND
status <> ''DELETED''
ORDER BY ' || order_by || ' LIMIT 500'
USING search_term;
END; $$;
returns ERROR:
argument of AND must be type boolean, not type text at character 64
As opposed to:
RETURN QUERY EXECUTE '
SELECT
*
FROM
articles
WHERE
' || search_term || ' AND
' || publication_date_query || ' AND
primary_category LIKE ''' || category_filter || ''' AND
' || tags_query || ' AND
' || districts_query || ' AND
' || capability_query || ' AND
' || push_notification_query || ' AND
' || distance_query || ' AND
' || revision_by || ' AND
' || publication_priority_query || ' AND
' || status_query || ' AND
is_template = ' || only_templates || ' AND
status <> ''DELETED''
ORDER BY ' || order_by || ' LIMIT 500';
END; $$;
... which works. Am I missing something?
My goal is to sanitize my user input.
If some of your input parameters can be NULL or empty and should be ignored in this case, you best build your whole statement dynamically depending on user input - and omit respective WHERE / ORDER BY clauses completely.
The key is to handle NULL and empty string correctly, safely (and elegantly) in the process. For starters, search_term <> '' is a smarter test than char_length(search_term) > 0. See:
Best way to check for "empty or null value"
And you need a firm understanding of PL/pgSQL, or you may be in over your head. Example code for your case:
CREATE OR REPLACE FUNCTION my_func(
_search_term text = NULL -- default value NULL to allow short call
, _publication_date_query date = NULL
-- , more parameters
)
RETURNS SETOF articles AS
$func$
DECLARE
sql text;
sql_order text; -- defaults to NULL
BEGIN
sql := concat_ws(' AND '
,'SELECT * FROM articles WHERE status <> ''DELETED''' -- first WHERE clause is immutable
, CASE WHEN _search_term <> '' THEN '$1 ## textsearchable_index_col' END -- ELSE NULL is implicit
, CASE WHEN _publication_date_query <> '' THEN 'publication_date > $2' END -- or similar ...
-- , more more parameters
);
IF search_term <> '' THEN -- note use of $1!
sql_order := 'ORDER BY ts_rank_cd(textsearchable_index_col, $1) + GREATEST(0,(-1*EXTRACT(epoch FROM age(last_edited)/86400))+60)/60 DESC';
END IF;
RETURN QUERY EXECUTE concat_ws(' ', sql, sql_order, 'LIMIT 500')
USING to_tsquery(_search_term || ':*') -- $1 -- prepare ts_query once here!
, _publication_date_query -- $2 -- order of params must match!
-- , more parameters
;
END
$func$ LANGUAGE plpgsql;
I added default values for function parameters, so you can omit params that don't apply in the call. Like:
SELECT * FROM my_func(_publication_date_query => '2016-01-01');
More:
Functions with variable number of input parameters
The forgotten assignment operator "=" and the commonplace ":="
Note the strategic use of concat_ws(). See:
How to concatenate columns in a Postgres SELECT?
Here is a related answer with lots of explanation:
Test for null in function with varying parameters

Select statement inside Concatenate (Oracle)

I have complex Select statement in Oracle, with Case When conditions and they select all Concatenate values.
So something similar to this:
END
END
FROM something
...
What I need is to put Other value from other table instead of My Value in concatenate.
So Instead of (My Value) I would have:
(Select textValue from textView A where A.textID = '395')
If I run this statement alone, it will take out one exact value I want. However if I put it instead of (My Value) into concatenate it gives me error: ora-00936 missing expression
(Yes '395' is string in that other table)
Any Ideas please?
You can use inline views inside the case clause in Oracle. Isn't that what you are trying to do? "Missing expression" error is probably a missing bracket or some similar code error.
select case object_type
when 'TABLE' then
'select * from ' || object_name
when 'SYNONYM' then
'describe ' || object_name
when 'PACKAGE' then
(select to_char (count (*))
from user_source s
where s.type = o.object_type and s.name = o.object_name)
else
(select object_type from dual)
end
as objects
from user_objects o
Or simply create a function that returns that does this for you and call it.
create function gettextval (p_textid in varchar2)
return varchar2 is
l_returnval varchar2 (32767);
begin
select text_val
into l_returnval
from v_texts s
where s.text_id = p_textid;
return l_returnval;
exception
when no_data_found then
return p_textid;
end;
In this example I make it return the input string of nothing is found.
Then you can reference the function in your previous select.
' || gettextval('395') || '
can you post you query with the "select text" bit inside?
When use case->when i do like that:
SELECT
CASE A.LIST_TYPE_CD
WHEN '1' THEN '<A HREF="censured?thresholdId=censured' || GET_SITE_SUFFIX() || chr(38) || 'task=runSQL' || chr(38) || 'parseParams=true' || chr(38) || 'list_id=' || A.LIST_ID || chr(38) || 'list_name=' || A.LIST_NAME ||
'">' || (Select textValue from textView A where A.textID = '395') || '</A>'
WHEN '3' THEN '<A HREF=censured' || GET_SITE_SUFFIX() || chr(38) || 'task=runSQL' || chr(38) || 'parseParams=true' || chr(38) || 'list_id=' || A.LIST_ID ||
'">' || (Select textValue from textView B where B.textID = '395') || '</A>'
END
FROM something A

Oracle SQL - Alternative for dynamic query

I have a procedure (see below) which is using dynamic query. I wanted to rewrite this procedure with out using dynamic query. How do I write the conditions below?
PROCEDURE DemoProcedure(p_firstname IN VARCHAR2,
p_lastname IN VARCHAR2,
p_phone IN VARCHAR2
o_Cursor OUT t_Cursor) IS
SQLString VARCHAR2(4000);
BEGIN
SQLString :=
'SELECT * FROM
SCHEMA.TABLENAME_a A
INNER JOIN SCHEMA.TABLENAME_b B
ON A.ID = B.ID
WHERE
A.TYPE = 1 ';
IF p_firstname IS NOT NULL THEN
SQLString := SQLString || ' and UPPER(A.FIRST_NAME) like UPPER( ''' || p_firstname || ''')';
END IF;
IF p_lastname IS NOT NULL THEN
SQLString := SQLString || ' and UPPER(A.LAST_NAME) like UPPER( ''' || p_lastname || ''')';
END IF;
IF p_phone IS NOT NULL THEN
SQLString := SQLString || ' and UPPER(A.PHONE) = ''' ||
p_phone || '''';
END IF;
SQLString := SQLString || ' order by a.id ';
OPEN o_Cursor FOR SQLString;
END DemoProcedure;
It looks like you just want
OPEN o_cursor
FOR SELECT ...
WHERE A.TYPE = 1
AND (p_firstname IS NULL or upper(a.first_name) = upper(p_firstname))
AND (p_lastname IS NULL or upper(a.last_name) = upper(p_lastname))
AND (p_phone IS NULL or upper(a.phone) = p_phone)
ORDER BY a.id
I'm not sure why you'd want to bother upper-casing a phone number-- do you have character data in a phone number?
Different way writing the same SQL as #JustinCave suggested -
OPEN o_cursor
FOR SELECT ...
WHERE A.TYPE = 1
AND upper(a.first_name) = nvl(upper(p_firstname), upper(a.first_name))
AND upper(a.last_name) = nvl(upper(p_lastname),upper(a.last_name))
AND upper(a.phone) = nvl(p_phone,upper(a.phone))
ORDER BY a.id