Я должен перевести код C# в хранимую процедуру в Oracle.
Я написал хранимую процедуру с случаем, когда не возвращаются нужные данные. Где я не прав?
Проблема заключается в управлении IF входных параметров.
Оракул:
CREATE OR REPLACE PROCEDURE SP_S_RICCFEMESSE
(
NUMEROCV IN VARCHAR2,
PROFILO IN NUMBER,
SALAES IN NUMBER,
DATAINIZIO IN VARCHAR2,
DATAFINE IN VARCHAR2,
ric_carteemesse OUT SYS_REFCURSOR
)
AS
BEGIN
OPEN ric_carteemesse FOR
SELECT DISTINCT A.*
,DESCARDPRFCFR AS TIPO_CARTA
,TO_CHAR(DATNAS,'DD/MM/YYYY') AS DATA_DI_NASCITA
,TO_CHAR(A.DATIVOPSA,'DD/MM/YYYY HH24:MI:SS') AS DATA_EMISSIONE
,TO_CHAR(DATINIVALRTA,'DD/MM/YYYY') AS INIZIO_VALIDITA_CARTA
,TO_CHAR(DATFINIVALRTA,'DD/MM/YYYY') AS FINE_VALIDITA_CARTA
,C.S_DENOMINAZIONE AS SALA_ES
,CASE
WHEN NVL(SCDUP,0) = '0'
THEN 'NO'
WHEN SCDUP > 0
THEN 'SI'
END AS DUPLICATO
FROM
DEMIRTAFRC A
INNER JOIN SMART_CARD B
ON A.CODSRE = B.COD_SM
LEFT JOIN RIVENDITA C
ON B.S_POSTAZIONE_UM = TO_CHAR(C.COD_RIVENDITA)
INNER JOIN DANACARDPRFCFR D ON A.CODPRF= D.CARDPRFCFR
WHERE
(B.D_ELETTRIFICAZIONE BETWEEN TO_DATE(DATAINIZIO,'DD/MM/YYYY') AND TO_DATE(DATAFINE,'DD/MM/YYYY')
AND A.MDLCSG = 'CBM' AND CODSRE IS NOT NULL)
AND NUMEROCV = (CASE WHEN NUMEROCV <> ''
THEN A.CODRTA
ELSE null
END)
AND PROFILO = (CASE WHEN PROFILO <> 0
THEN B.COD_REQUISITI
ELSE null
END)
AND SALAES = (CASE WHEN SALAES <> 999
THEN B.S_POSTAZIONE_UM
ELSE null
END)
ORDER BY A.DATETR DESC;
END SP_S_RICCFEMESSE;
Это код С# для замены:
if (_NumCV.ToString().Trim() != "")
_cmd.CommandText += " AND A.CODRTA = '" + _NumCV + "' ";
if (_Profilo != 0)
_cmd.CommandText += " AND B.COD_REQUISITI = " + _Profilo;
if (_SalaES != 999)
_cmd.CommandText += " AND B.S_POSTAZIONE_UM = '" + _SalaES + "' ";
У вас есть нулевое значение в столбцах PROFILO, SALES, NUMERO CV. Если да, то вы должны установить nvl в этих столбцах, где часть.
Поскольку вы С# говорите, что у вас может быть нуль, попробуйте это:
CREATE OR REPLACE PROCEDURE SP_S_RICCFEMESSE
(
NUMEROCV IN VARCHAR2,
PROFILO IN NUMBER,
SALAES IN NUMBER,
DATAINIZIO IN VARCHAR2,
DATAFINE IN VARCHAR2,
ric_carteemesse OUT SYS_REFCURSOR
)
AS
BEGIN
OPEN ric_carteemesse FOR
SELECT DISTINCT A.*
,DESCARDPRFCFR AS TIPO_CARTA
,TO_CHAR(DATNAS,'DD/MM/YYYY') AS DATA_DI_NASCITA
,TO_CHAR(A.DATIVOPSA,'DD/MM/YYYY HH24:MI:SS') AS DATA_EMISSIONE
,TO_CHAR(DATINIVALRTA,'DD/MM/YYYY') AS INIZIO_VALIDITA_CARTA
,TO_CHAR(DATFINIVALRTA,'DD/MM/YYYY') AS FINE_VALIDITA_CARTA
,C.S_DENOMINAZIONE AS SALA_ES
,CASE
WHEN NVL(SCDUP,0) = '0'
THEN 'NO'
WHEN SCDUP > 0
THEN 'SI'
END AS DUPLICATO
FROM
DEMIRTAFRC A
INNER JOIN SMART_CARD B
ON A.CODSRE = B.COD_SM
LEFT JOIN RIVENDITA C
ON B.S_POSTAZIONE_UM = TO_CHAR(C.COD_RIVENDITA)
INNER JOIN DANACARDPRFCFR D ON A.CODPRF= D.CARDPRFCFR
WHERE
(B.D_ELETTRIFICAZIONE BETWEEN TO_DATE(DATAINIZIO,'DD/MM/YYYY') AND TO_DATE(DATAFINE,'DD/MM/YYYY')
AND A.MDLCSG = 'CBM' AND CODSRE IS NOT NULL)
AND nvl(NUMEROCV, ' ') = (CASE WHEN nvl(NUMEROCV, ' ') <> ' '
THEN A.CODRTA
ELSE null
END)
AND nvl(PROFILO, 0) = (CASE WHEN nvl(PROFILO, 0) <> 0
THEN B.COD_REQUISITI
ELSE null
END)
AND NVL(SALAES, 0) = (CASE WHEN NVL(SALAES, 0) <> 999
THEN B.S_POSTAZIONE_UM
ELSE null
END)
ORDER BY A.DATETR DESC;
END SP_S_RICCFEMESSE;
NULL никогда не равен NULL. Таким образом, если какой-либо из операторов CASE перейдет в ветвь ELSE, оператор будет оценен как FALSE. Кроме того, в Oracle пустая строка — это то же самое, что и NULL (да, это спорно, но Oracle был таким уже почти сорок лет, так оно и есть), что означает, что это всегда будет ЛОЖЬ: NUMEROCV <> ''
.
Простое решение: не используйте CASE в предложении WHERE. Это намного понятнее:
AND (NUMEROCV is null or NUMEROCV = A.CODRTA)
AND (PROFILO = 0 or PROFILO = B.COD_REQUISITI)
AND (SALAES = 999 or SALAES = B.S_POSTAZIONE_UM))
Если у вас много критериев, вы можете динамически создавать sql
Объявить sql_statement
sql_statement VARCHAR2(...);
sql_statement := 'SELECT .... WHERE ' // your select
IF PROFILO <> 0 THEN // your criteria here
sql_statement := sql_statement || ' AND B.COD_REQUISITI = ' || PROFILO // your criteria here;
EXECUTE IMMEDIATE(sql_statement);