I am getting nested exception is java.sql.SQLSyntaxErrorException: ORA-00909: invalid number of arguments - sql

this is my query,
SELECT
MAX(CASE WHEN rownumber='1' THEN DISPOSITON END) AS Dispostion
,MAX(CASE WHEN rownumber='1' THEN SUB_DISPOSITION END) AS SUB_DISPOSITION
,CUST_NAME
,MOBILE_NO
,EMAIL_ID
,LINE_OF_BUSINESS
,PRODUCT_CODE
,REGISTRATION_NUMBER
FROM
(
SELECT
ROW_NUMBER() OVER (PARTITION BY task_id ORDER BY CREATED_DATE ASC) AS rownumber
,a.DISPOSITON
,a.SUB_DISPOSITION
,b.CUST_NAME
,b.MOBILE_NO
,b.EMAIL_ID
,b.LINE_OF_BUSINESS
,b.PRODUCT_CODE
,b.REGISTRATION_NUMBER
FROM CLICK_TO_CALL_AUDIT_LOG a
INNER JOIN IM_DATA b
ON a.task_id=b.task_code
AND UPPER(a.DISPOSITON) = UPPER(:Dis)
AND UPPER(a.SUB_DISPOSITION) in (UPPER(:subDis))
AND a.CREATED_DATE BETWEEN to_timestamp(:before , 'dd-mm-yy hh24:mi:ss')
AND to_timestamp(:current, 'dd-mm-yy hh24:mi:ss')
WHERE b.ALLOCATED_USER IN (:userNameList)
AND b.IS_LATEST = 'Y'
AND b.TASK_STATUS <> 'JUNK LEAD'
AND b.LINE_OF_BUSINESS = :LOB
) R
GROUP BY
CUST_NAME
,MOBILE_NO
,EMAIL_ID
,LINE_OF_BUSINESS
,PRODUCT_CODE
,REGISTRATION_NUMBER;

This:
AND UPPER(a.SUB_DISPOSITION) in (UPPER(:subDis))
should most probably be rewritten so that it represents rows (instead of a, presumably, comma-separated list of values). Something like this:
and upper(a.sub_disposition) in (select trim(regexp_substr(upper(:subDis), '[^,]+', 1, level))
from dual
connect by level <= regexp_count(:subDis, ',') + 1
)
The same goes for
WHERE b.ALLOCATED_USER IN (:userNameList)
I presumed that variables (such as userNameList) looks like e.g. 'Scott,Tiger,Wood,King'. If it looks differently, code should also be adjusted.

Related

How to create a view from existing table records, but also adding new records that do not exist

I am trying to create a view from an existing views data, but also if there are certain lines that do not exist per part/date combo, then have those lines be created. I have the below query that is showing what I currently have for the particular s_date/part_no combos:
SELECT
s_date,
part_no,
issue_group,
s_level,
qty_filled
FROM
current_view
WHERE
part_no = 'xxxxx'
AND s_date IN (
'201802',
'201803'
)
ORDER BY
s_date,
part_no,
issue_group,
DECODE(s_level, '80', 1, '100', 2, 'Late', 3)
Which produces the below:
I know how to create a view with that data, that's the easy part. But what I'm needing is a line for each issue_group and s_level combo, and if it's a created line, to put 0 as the qty_filled.
Every part_no / s_date combo should have 6 rows that go with it
- issue_group = '1' / s_level = '80'
- issue_group = '1' / s_level = '100'
- issue_group = '1' / s_level = 'Late'
- issue_group = '2/3 ' / s_level = '80'
- issue_group = '2/3 ' / s_level = '100'
- issue_group = '2/3 ' / s_level = 'Late'
So if one of the above combinations already exists for the current s_date/part_no, then it obviously takes the qty_filled info from the current view. If not, a new line is created, and qty_filled = 0. So I'm trying to get it to look like this:
I've only shown 1 part, with a couple dates, just to get the point across. There are 10k+ parts within the table and there will never be more than 1 part/date combo for each of the 6 issue_group/s_level combos.
The idea is to generate the rows using CROSS JOIN and then bring in the extra information with a LEFT JOIN. In Oracle syntax, this looks like:
WITH v as (
SELECT v.*
FROM current_view v
WHERE part_no = 'xxxxx' AND
s_date IN ('201802', '201803')
)
SELECT d.s_date, ig.part_no, ig.issue_group, l.s_level,
COALESCE(v.qty_filled, 0) as qty_filled
FROM (SELECT DISTINCT s_date FROM v) d CROSS JOIN
(SELECT DISTINCT part_no, ISSUE_GROUP FROM v) ig CROSS JOIN
(SELECT '80' as s_level FROM DUAL UNION ALL
SELECT '100' FROM DUAL UNION ALL
SELECT 'LATE' FROM DUAL
) l LEFT JOIN
v
ON v.s_date = d.s_date AND v.part_no = ig.part_no AND
v.issue_group = ig.issue_group AND v.s_level = l.s_level
ORDER BY s_date, part_no, issue_group,
(CASE s_level WHEN '80' THEN 1 WHEN '100' THEN 2 WHEN 'Late' THEN 3 END)
One solution could be to generate a cartesian product of all expected rows using a cartesian product between the (fixed) list of values, and then LEFT JOIN it with current_view.
The following query guarantees that you will get a record for each given s_date/part_no/issue_group/s_level tuple. If no record matches in current_view, the query will display a 0 quantity.
SELECT
sd.s_date,
pn.part_no,
ig.issue_group,
sl.s_level,
COALESCE(cv.qty_filled, 0) qty_filled
FROM
(SELECT '201802' AS s_date UNION SELECT '201803') AS sd
CROSS JOIN (SELECT 'xxxxx' AS part_no) AS pn
CROSS JOIN (SELECT '1' AS issue_group UNION SELECT '2') AS ig
CROSS JOIN (SELECT '80' AS s_level UNION SELECT '100' UNION SELECT 'Late') AS sl
LEFT JOIN current_view cv
ON cv.s_date = sd.s_date
AND cv.part_no = pn.part_no
AND cv.issue_group = ig.issue_group
AND cv.s_level = ig.s_level
ORDER BY
sd.s_date,
pn.part_no,
ig.issue_group,
DECODE(sl.s_level, '80', 1, '100', 2, 'Late', 3)
NB : you did not tag your RDBMS. This should work on most of them, excepted Oracle, where you need to add FROM DUAL to each select in the queries that list the allowed values, like :
(SELECT '201802' AS s_date FROM DUAL UNION SELECT '201803' FROM DUAL) AS sd

PL/SQL: Invalid Number error

I am creating a procedure for which I collect data by repeatedly running the following query.
SELECT ATTRIBUTE_VALUE,
COUNT(src1) CNT1,
COUNT(src2) CNT2
FROM (
SELECT a.ATTRIBUTE_VALUE,
1 src1,
TO_NUMBER(NULL) src2
FROM (
SELECT DECODE(
L,
1, IP_ADDRESS,
DECODE(
L,
2, IP_SUBNET_MASK,
DECODE(
L,
3, IP_DEFAULT_GATEWAY
)
)
) ATTRIBUTE_VALUE
FROM ( SELECT LEVEL L FROM DUAL X CONNECT BY LEVEL <= 3 ),
REUT_LOAD_IP_ADDRESSES
WHERE LIP_IPT_NAME = 'CE'
AND IP_LNT_ID IN (
SELECT LNT_ID
FROM REUT_LOAD_NTN
WHERE LNT_ID IN (
SELECT RLPN.LPN_LNT_ID
FROM REUT_LOAD_PI_NTN RLPN
WHERE LPN_LPI_ID IN (
SELECT RLPI.LPI_ID
FROM REUT_LOAD_PAC_INS RLPI
WHERE RLPI.LPI_DATE_ADDED IN (
SELECT MAX(RLPI2.LPI_DATE_ADDED)
FROM REUT_LOAD_PAC_INS RLPI2
WHERE RLPI2.PI_JOB_ID = P_ORDER_ID
)
)
)
AND IP_CEASE_DATE IS NULL
AND LNT_SERVICE_INSTANCE = 'PRIMARY'
)
It is running fine in SQL developer but when executing it as a procedure, I am getting INVALID NUMBER ERROR (ORA-01722: invalid number) at
AND IP_LNT_ID IN (
SELECT LNT_ID, in the code.
Can I get any help?
The error is pretty clear. You're comparing a number to another type of value.
Example:
SELECT 'x'
FROM DUAL
WHERE 1 IN (SELECT 'a'
FROM DUAL)
This means that IP_LNT_ID, LNT_ID, LPN_LNT_ID and LPI_ID have to be NUMBER. And LPI_DATE_ADDED and LPI_DATE_ADDED should both be date or timestamp.
If this is not possible you could compare everything as char:
SELECT ATTRIBUTE_VALUE, COUNT(src1) CNT1, COUNT(src2) CNT2
FROM (SELECT a.ATTRIBUTE_VALUE, 1 src1, TO_NUMBER(NULL) src2
FROM (SELECT
DECODE(L,1,IP_ADDRESS,DECODE(L,2,IP_SUBNET_MASK,DECODE(L,3,IP_DEFAULT_GATEWAY) ) ) ATTRIBUTE_VALUE
FROM
(
SELECT LEVEL L FROM DUAL X CONNECT BY LEVEL <= 3
),
REUT_LOAD_IP_ADDRESSES
WHERE LIP_IPT_NAME = 'CE'
AND to_char(IP_LNT_ID) IN (
SELECT LNT_ID
FROM REUT_LOAD_NTN
WHERE to_char(LNT_ID) IN (
SELECT RLPN.LPN_LNT_ID
FROM REUT_LOAD_PI_NTN RLPN
WHERE to_char(LPN_LPI_ID) IN (
SELECT RLPI.LPI_ID
FROM REUT_LOAD_PAC_INS RLPI
WHERE to_char(RLPI.LPI_DATE_ADDED) IN (
SELECT MAX(RLPI2.LPI_DATE_ADDED)
FROM REUT_LOAD_PAC_INS RLPI2
WHERE RLPI2.PI_JOB_ID = P_ORDER_ID
)
)
)
AND IP_CEASE_DATE IS NULL
AND LNT_SERVICE_INSTANCE = 'PRIMARY'
)
But this should be avoided on any cost. Unfortunately some times we have to cheat a little from time to time to work with our existing infrasructure ;-)
You need to make sure:
REUT_LOAD_IP_ADDRESSES.IP_LNT_ID
and
REUT_LOAD_NTN.LNT_ID
Have the same data type or cast/convert one or other so that they have the same data type.
There are multiple other issues:
You have aggregated and non-aggregated values:
SELECT ATTRIBUTE_VALUE,
COUNT(src1) CNT1,
COUNT(src2) CNT2
FROM ( ... )
Without a GROUP BY clause.
src2 is TO_NUMBER(NULL) which is just NULL and COUNT(NULL) will always be 0 so your query is:
SELECT ATTRIBUTE_VALUE,
COUNT(src1) CNT1,
0 CNT2
...
This code:
SELECT DECODE(
L,
1, IP_ADDRESS,
DECODE(
L,
2, IP_SUBNET_MASK,
DECODE(
L,
3, IP_DEFAULT_GATEWAY
)
)
) ATTRIBUTE_VALUE
FROM ( SELECT LEVEL L FROM DUAL X CONNECT BY LEVEL <= 3 ),
REUT_LOAD_IP_ADDRESSES
Can be rewritten as:
SELECT DECODE(
L,
1, IP_ADDRESS,
2, IP_SUBNET_MASK,
3, IP_DEFAULT_GATEWAY
) ATTRIBUTE_VALUE
FROM ( SELECT LEVEL L FROM DUAL X CONNECT BY LEVEL <= 3 ),
REUT_LOAD_IP_ADDRESSES
Or, without the join as:
SELECT attribute_value
FROM REUT_LOAD_IP_ADDRESSES
UNPIVOT ( attribute_value FOR L IN (
IP_ADDRESS AS 1,
IP_SUBNET_MASK AS 2,
IP_DEFAULT_GATEWAY AS 3
) )
The innermost query:
SELECT RLPI.LPI_ID
FROM REUT_LOAD_PAC_INS RLPI
WHERE RLPI.LPI_DATE_ADDED IN (
SELECT MAX(RLPI2.LPI_DATE_ADDED)
FROM REUT_LOAD_PAC_INS RLPI2
WHERE RLPI2.PI_JOB_ID = P_ORDER_ID
)
The inner query is restricted to have RLPI2.PI_JOB_ID = P_ORDER_ID but there is no correlation between the outer query so you can retrieve results that do not match P_ORDER_ID but just happen to have the same date as a matching row.

Stuck on Oracle SQL query

We have a query that has been leaving me scratching my head for the past week. The query works on one DB, but not another (apologies for the wall of text):
WITH dataset AS
( SELECT COLLECTION_TIMESTAMP,
TARGET_NAME,
METRIC_NAME,
KEY_VALUE,
KEY_VALUE2,
KEY_VALUE3,
COLUMN_LABEL,
MAX(VALUE) AS VALUE
FROM (SELECT TO_CHAR(COLLECTION_TIMESTAMP, 'DD-MM-YYYY HH24:MI:SS') AS COLLECTION_TIMESTAMP,
TARGET_NAME,
METRIC_NAME,
KEY_VALUE,
KEY_VALUE2,
KEY_VALUE3,
COLUMN_LABEL,
VALUE
FROM (SELECT MAX(COLLECTION_TIMESTAMP)
OVER(
PARTITION BY TARGET_NAME,
METRIC_NAME,
KEY_VALUE,
KEY_VALUE2,
KEY_VALUE3,
COLUMN_LABEL
)
max_my_date,
COLLECTION_TIMESTAMP,
TARGET_NAME,
METRIC_NAME,
KEY_VALUE,
KEY_VALUE2,
KEY_VALUE3,
COLUMN_LABEL,
VALUE
FROM MGMT$METRIC_DETAILS
WHERE METRIC_LABEL LIKE 'SOX%')
WHERE COLLECTION_TIMESTAMP = max_my_date)
WHERE METRIC_NAME = 'ME$SOXREP_USERS'
GROUP BY COLLECTION_TIMESTAMP,
TARGET_NAME,
METRIC_NAME,
KEY_VALUE,
kEY_VALUE2,
KEY_VALUE3,
COLUMN_LABEL
ORDER BY TARGET_NAME ASC,
METRIC_NAME ASC,
COLUMN_LABEL ASC)
SELECT (SELECT NVL(amt.AGENT_HOST_NAME, ' ') AS AGENT_HOST_NAME
FROM MGMT$TARGET t LEFT OUTER JOIN MGMT$AGENTS_MONITORING_TARGETS amt ON t.TARGET_GUID = amt.TARGET_GUID
WHERE t.TARGET_NAME = prf.TARGET_NAME)
AS "HOSTNAME",
(SELECT NVL(PROPERTY_VALUE, ' ')
FROM MGMT$TARGET_PROPERTIES
WHERE PROPERTY_NAME = 'IP_address'
AND TARGET_NAME = (SELECT NVL(amt.AGENT_HOST_NAME, ' ') AS AGENT_HOST_NAME
FROM MGMT$TARGET t LEFT OUTER JOIN MGMT$AGENTS_MONITORING_TARGETS amt ON t.TARGET_GUID = amt.TARGET_GUID
WHERE t.TARGET_NAME = prf.TARGET_NAME))
AS "IP ADDRESS",
(SELECT NVL(PROPERTY_VALUE, ' ')
FROM MGMT$TARGET_PROPERTIES
WHERE PROPERTY_NAME = 'DBVersion'
AND TARGET_NAME = prf.TARGET_NAME)
AS "DB VERSION",
(SELECT NVL(PROPERTY_VALUE, ' ')
FROM MGMT$TARGET_PROPERTIES
WHERE PROPERTY_NAME = 'InstanceName'
AND TARGET_NAME = prf.TARGET_NAME)
AS "DB INSTANCE",
'All database accounts' AS DESCRIPTION,
prf.KEY_VALUE AS "USERNAME",
prf.VALUE AS "PROFILE",
acc.VALUE AS "ACCOUNT STATUS",
CAST(TO_TIMESTAMP(created.VALUE, 'YYYY-MM-DD HH24:MI:SS.FF1') AS DATE) AS "CREATED",
CAST(TO_TIMESTAMP(passwd.VALUE, 'YYYY-MM-DD HH24:MI:SS.FF1') AS DATE) AS "LAST_PWD_CHANGED",
d.VALUE AS "DAYS_SINCE_LAST_PWD_CHANGED",
(SELECT NVL(PROPERTY_VALUE, ' ')
FROM MGMT$TARGET_PROPERTIES
WHERE PROPERTY_NAME = 'orcl_gtp_contact'
AND TARGET_NAME = prf.TARGET_NAME)
AS "ENVIRONMENT ROLES",
CAST(TO_TIMESTAMP(dl.VALUE, 'YYYY-MM-DD HH24:MI:SS.FF1') AS DATE) AS "LAST LOGON",
TO_DATE(prf.COLLECTION_TIMESTAMP, 'DD-MM-YYYY HH24:MI:SS') AS "COLLECTION DATE"
FROM dataset prf,
dataset acc,
dataset created,
dataset passwd,
dataset d,
dataset dl
WHERE prf.TARGET_NAME = acc.TARGET_NAME
AND prf.KEY_VALUE = acc.KEY_VALUE
AND prf.TARGET_NAME = created.TARGET_NAME
AND prf.KEY_VALUE = created.KEY_VALUE
AND prf.TARGET_NAME = passwd.TARGET_NAME
AND prf.KEY_VALUE = passwd.KEY_VALUE
AND prf.TARGET_NAME = d.TARGET_NAME
AND prf.KEY_VALUE = d.KEY_VALUE
AND prf.TARGET_NAME = dl.TARGET_NAME
AND prf.KEY_VALUE = dl.KEY_VALUE
AND prf.COLUMN_LABEL = 'PROFILE'
AND acc.COLUMN_LABEL = 'ACCOUNT STATUS'
AND created.COLUMN_LABEL = 'CREATED'
AND passwd.COLUMN_LABEL = 'LAST PWD CHANGE'
AND d.COLUMN_LABEL = 'Days since last pwd change'
AND dl.COLUMN_LABEL = 'LAST LOGON'
ORDER BY 1 ASC,
4,
5 DESC
On one DB, the query runs just fine. On the other DB though, we get the following:
ORA-01427: single-row subquery returns more than one row
01427. 00000 - "single-row subquery returns more than one row"
*Cause:
*Action:
I've been trying to deconstruct the query in an attempt to figure out which portion of the query is causing the issue, but so far I've had no luck. I understand that a subquery which is supposed to return only one row is returning 2 or more, but I'm struggling to figure out which one it is.
My question: Is there an easier way for me to figure out which portion of the SQL query is causing the issue instead of having to try to deconstruct the query and running it bit by bit?
You can wrap your subqueries to check which one gives more than one row, at least for the queries you don't need to check against a value. For example:
SQL> select
2 (select 1 from dual) as result_1,
3 (select 1 from dual connect by level < 10) as result_2
4 from dual;
(select 1 from dual connect by level < 10) as result_2
*
ERROR at line 3:
ORA-01427: single-row subquery returns more than one row
SQL> select
2 (select count(1) from (select 1 from dual)) as check1,
3 (select count(1) from (select 1 from dual connect by level < 10)) as check_2
4 from dual;
CHECK1 CHECK_2
---------- ----------
1 9
Here you know that the issue is in the second query.

Non duplicate records with max date query on oracle

Hello i have a problem with a simple query. I need to see the max date of some articles in two direfent sites.
This is my actual query:
SELECT a.aa_codart, MAX(t.tr_fechafac), t.tr_tipo
FROM ARTALM a, traspaso t
WHERE t.tr_codart = a.aa_codart
and t.tr_tipomov > 1
and a.aa_codalm = '1'
and (t.tr_tipo >= 1 and t.tr_tipo <=2)
group by a.aa_codart, t.tr_tipo;
And the result:
01..FRB10X80 30/11/07 2
01..FRB10X80 08/03/01 1
01.32122RS 05/02/16 1
01.32122RS 02/07/10 2
01.33052Z 21/09/15 1
01.60042Z 24/02/16 2
I want, for example in the two first rows, see only one row, like this:
01..FRB10X80 30/11/07 2
01.32122RS 05/02/16 1
01.33052Z 21/09/15 1
01.60042Z 24/02/16 2
Taking the max date
Thanks
This calls for an analytical query. This query shows how the ROW_NUMBER() function will assign the value 1 to the row with the article's most recent date. Give it a try first to help understand the final query, coming up next:
SELECT
a.aa_codart,
t.tr_fechafac,
t.tr_tipo,
ROW_NUMBER() OVER (PARTITION BY a.aa_codart ORDER BY t.tr_fechafac DESC) as rnk
FROM artalm a
INNER JOIN trapaso t ON a.aa_codart = t.tr_codart
WHERE t.tr_tipomov > 1
AND a.aa_codalm = '1'
AND t.tr_tipo BETWEEN 1 AND 2
You can't apply the WHERE clause to the rnk column because the column is calculated after the WHERE clause. You can get around this using a nested query:
SELECT * FROM (
SELECT
a.aa_codart,
t.tr_fechafac,
t.tr_tipo,
ROW_NUMBER() OVER (PARTITION BY a.aa_codart ORDER BY t.tr_fechafac DESC) as rnk
FROM artalm a
INNER JOIN trapaso t ON a.aa_codart = t.tr_codart
WHERE t.tr_tipomov > 1
AND a.aa_codalm = '1'
AND t.tr_tipo BETWEEN 1 AND 2
) WHERE rnk = 1;
I apologize in advance for any column names I may have retyped badly. The Oracle syntax should be fine; the column names maybe not so much :)
I think you may want to look at row_number() (then just pick the ones where it is one) something like this.
WITH t
AS (SELECT 'A' aa_codart,
TO_DATE ('17/05/00', 'dd/mm/yy') mydt,
1 tr_tipo
FROM DUAL
UNION ALL
SELECT 'A', TO_DATE ('12/04/00', 'dd/mm/yy'), 2 FROM DUAL
UNION ALL
SELECT 'B', TO_DATE ('30/06/98', 'dd/mm/yy'), 2 FROM DUAL
UNION ALL
SELECT 'C', TO_DATE ('30/06/98 ', 'dd/mm/yy'), 2 FROM DUAL),
t2
AS (SELECT aa_codart,
mydt,
tr_tipo,
ROW_NUMBER ()
OVER (PARTITION BY aa_codart ORDER BY mydt DESC)
rn
FROM t)
SELECT *
FROM t2
WHERE rn = 1

Oracle sql to case conversion for every adjacent characters in a string

With a condition like no two adjacent characters ( from a to z) should be in same case;
I need to change helloworld to HeLlOwOrLd , and used a query like :
SELECT listagg(jumping_char,'') WITHIN GROUP(ORDER BY rn) jumped_word
FROM
(SELECT rn,
CASE
WHEN mod(rn, 2) = 1
THEN upper(split_word)
ELSE lower(split_word)
END jumping_char
FROM
(SELECT regexp_substr('helloworld','.',LEVEL)split_word,
ROWNUM rn
FROM dual
CONNECT BY LEVEL <= LENGTH('helloworld')
)
);
Now I got a string like hello2world should becomes HeLlO2wOrLd.
Any simple ,different queries are appreciated and thanks in advance.
If I understand you correctly, you want to "skip" over non-characters in the input. You can achieve that by using regexp_count() with an offset of rn (instead of simply using rn) in your old solution:
SELECT listagg(jumping_char,'') WITHIN GROUP(ORDER BY rn) jumped_word
FROM
(SELECT rn,
CASE
when mod (regexp_count('hello2world', '[a-zA-Z]', rn), 2) = 1
THEN upper(split_word)
ELSE lower(split_word)
END jumping_char
FROM
(SELECT regexp_substr('hello2world','.',LEVEL)split_word,
ROWNUM rn
FROM dual
CONNECT BY LEVEL <= LENGTH('hello2world')
)
);
UPDATE:
Here's an alternative solution using the MODEL clause, just for completeness' sake:
with t as
(select 'hello2world' txt from dual)
select listagg(case
when mod(v2.char_cnt, 2) = 1
then upper(v2.txt)
else lower(v2.txt)
end,
'') within group(order by v2.rn)
from (
select
v1.txt,
rownum as rn,
sum(case
when regexp_like(txt, '[a-zA-Z]')
then 1
else 0
end) over (partition by 1 order by rownum) as char_cnt
from (
SELECT TXT
FROM T
MODEL
RETURN UPDATED ROWS
PARTITION BY(ROWNUM RN)
DIMENSION BY (0 POSITION)
MEASURES (TXT ,length(txt) NB_MOT)
RULES
(TXT[FOR POSITION FROM 1 TO NB_MOT[0] INCREMENT 1] =
substr(txt[0], CV(POSITION), 1) )
) v1
) v2