ORA-00920: Invalid relational operator (no missing/extra parenthesis) - oracle

I have an error when I try to execute the following query and I don't understand why.
SELECT DISTINCT lpad(obj.no, 4, '0') || ' - ' || obj.nom, obj.no
FROM TABLE(objects_pkg.get_all()) obj
WHERE obj.start_date <=
(CASE
WHEN util_pkg.is_date_valid(p_date => :v_start_date) ̲T̲H̲E̲N
to_date(:v_start_date, 'YYYY-MM-DD')
ELSE
trunc(SYSDATE)
END)
I checked for missing / extra parenthesis but I couldn't find any.
I tried several ways of structuring the CASE like the following but none of them worked.
SELECT DISTINCT lpad(obj.no, 4, '0') || ' - ' || obj.nom, obj.no
FROM TABLE(objects_pkg.get_all()) obj
WHERE (CASE
WHEN util_pkg.is_date_valid(p_date => :v_start_date) ̲T̲H̲E̲N
CASE WHEN obj.start_date <= to_date(:v_start_date, 'YYYY-MM-DD') THEN 1 ELSE 0 END
ELSE
CASE WHEN obj.start_date <= trunc(SYSDATE) THEN 1 ELSE 0 END
END) = 1
The error is always the same and is always triggered on the first T̲H̲E̲N̲ keyword of the first WHEN. I tried with and without the parenthesis, I tried to remove the THEN keyword and I tried a lot of things but nothing worked. The error is: ORA-00920: Invalid relational operator
I've also tried to change the entire where clause to the following but it didn't help.
SELECT DISTINCT lpad(obj.no, 4, '0') || ' - ' || obj.nom, obj.no
FROM TABLE(objects_pkg.get_all()) obj
WHERE (
(
TRIM(:v_start_date) ̲I̲S NULL
AND util_pkg.is_date_valid(p_date => :v_start_date)
AND obj.start_date <= to_date(:v_start_date, 'YYYY-MM-DD')
)
OR
(
(
:v_start_date IS NULL
OR NOT util_pkg.is_date_valid(p_date => :v_start_date)
)
AND obj.start_date <= trunc(SYSDATE)
)
)
For the above query, the error is triggered on the first I̲S̲ keyword within the WHERE clause (TRIM(:v_start_date) I̲S̲ NULL) but the error is still an ORA-00920.
Note: util_pkg.is_date_valid returns a BOOLEAN

I think your issue is that you are not testing the value from util_pkg.is_date_valid.
The WHEN part of the CASE statement needs to be tested against something.
CASE
WHEN util_pkg.is_date_valid(p_date => :v_start_date) >= ? ̲T̲H̲E̲N ...

Related

In a CASE statement, can you store WHEN subquery result for use in the THEN output?

I have a report outputting the results of a query which was designed to provide links to a webpage:
SELECT
a,
b,
c,
'string' ||
(SELECT sso_code
FROM men_sso
WHERE sso_parm LIKE '%URL_LINK~' || ipp_code || '%'
ORDER BY sso_cred, sso_cret
FETCH FIRST 1 ROWS ONLY
) AS URL
FROM men_ipp
This works well, but I was asked to amend it so that if the records needed to generate the URL were missing (ie. sso_code can't be retrieved), it outputs a warning message instead of the subquery output.
Since there's always going to be a string of a set length (6 characters in this example), my solution was to create a CASE statement which is evaluating the length of the subquery output, and if the answer is greater than 6 characters it returns subquery result itself, otherwise it returns a warning message to the user. This looks like:
SELECT
a,
b,
c,
CASE
WHEN
LENGTH('string' ||
(SELECT sso_code
FROM men_sso
WHERE sso_parm LIKE '%IPP_URL_LINK~' || (ipp_code) || '%'
ORDER BY sso_cred, sso_cret
FETCH FIRST 1 ROWS ONLY)
) > 6
THEN
('string' ||
(SELECT sso_code
FROM men_sso
WHERE sso_parm LIKE '%IPP_URL_LINK~' || (ipp_code) || '%'
ORDER BY sso_cred, sso_cret
FETCH FIRST 1 ROWS ONLY)
ELSE 'warning message'
END AS URL
FROM men_ipp
The statment works fine, however the processing time is nearly doubled because it's having to process the subquery twice. I want to know if there's any way to store the result of the subquery in the WHEN, so it doesn't need to be run a second time in the THEN? eg. as a temporary variable or similar?
I've tried to declare a variable like this:
DECLARE URLLINK NVARCHAR(124);
SET URLLINK = 'string' ||
(SELECT sso_code
FROM men_sso
WHERE sso_parm LIKE '%URL_LINK~' || ipp_code || '%'
ORDER BY sso_cred, sso_cret
FETCH FIRST 1 ROWS ONLY
)
However this causes the query to error saying the it Encountered the symbol "https://evision.dev.uwl.tribalsits.com/urd/sits.urd/run/siw_file_load.sso?" when expecting one of the following: := . ( # % ; not null range default character
You can use NULLIF to make the result null if it is "string" (i.e., you appended nothing to it from your subquery). Then use NVL to convert to the warning message. Something like this:
SELECT
a,
b,
c,
nvl(nullif(
'string' ||
(SELECT sso_code
FROM men_sso
WHERE sso_parm LIKE '%IPP_URL_LINK~' || (ipp_code) || '%'
ORDER BY sso_cred, sso_cret
FETCH FIRST 1 ROWS ONLY),'string'),'warning message')
FROM men_ipp
Use a CTE.
with temp as
(SELECT sso_code
FROM men_sso
WHERE sso_parm LIKE '%IPP_URL_LINK~' || (ipp_code) || '%'
ORDER BY sso_cred, sso_cret
FETCH FIRST 1 ROWS ONLY
)
select a, b, c,
case when sso_code is null then 'warning message'
else 'string' || sso_code
end as url
from men_ipp full outer join temp on 1 = 1;
Use a sub-query:
SELECT a,
b,
c,
CASE
WHEN LENGTH(sso_code) > 6
THEN sso_code
ELSE 'warning message'
END AS URL
FROM (
SELECT a,
b,
c,
'string' ||
( SELECT sso_code
FROM men_sso
WHERE sso_parm LIKE '%IPP_URL_LINK~' || ipp_code || '%'
ORDER BY sso_cred, sso_cret
FETCH FIRST 1 ROWS ONLY ) AS sso_code
FROM men_ipp
)

Laravel run complex query without disabling mysql strict mode

I have quite a complex query which is like:
SELECT
COALESCE (
SUM (
CASE WHEN `closed_job_reports`.`job_report_id` IS NOT NULL THEN 1 ELSE 0 END
),
0
) AS `CLOSED`,
COALESCE (
SUM (
CASE WHEN `job_reports`.`id` IS NULL
AND `jobs`.`deadline` <= CURRENT_TIMESTAMP() THEN 1 ELSE 0 END
),
0
) AS `OVERDUE`,
COALESCE (
SUM (
CASE WHEN (
`assigned_jobs`.`assigned_job_id` IS NULL
AND `pending_jobs`.`id` IS NOT NULL
AND `jobs`.`deadline` > NOW ()
)
OR (
`assigned_jobs`.`assigned_job_id` IS NOT NULL
AND `jobs`.`deadline` > NOW ()
AND `job_reports`.`id` IS NULL
) THEN 1 ELSE 0 END
),
0
) AS `PENDING`,
COALESCE (
SUM (
CASE WHEN `closed_job_reports`.`job_report_id` IS NULL
AND `job_reports`.`id` IS NOT NULL THEN 1 ELSE 0 END
),
0
) AS `AWAITING_CLOSURE`,
COALESCE (
SUM (
CASE WHEN (
`job_reports`.`id` IS NULL
OR `assigned_jobs`.`assigned_job_id` IS NULL
)
AND (
`jobs`.`deadline` > NOW ()
) THEN 1 ELSE 0 END
),
0
) AS `OPEN`,
COALESCE (
COUNT (*),
0
) AS `TOTAL`,
COALESCE (
SUM (
`job_reports`.`distance_travelled`
),
0
) AS `distance_travelled`,
COALESCE (
ROUND(
SUM (
CASE WHEN (
`job_reports`.`id` IS NOT NULL
AND `jobs`.`job_category_id` = 2
) THEN ABS (
TIMESTAMPDIFF (
SECOND, `job_reports`.`end_time`,
`job_reports`.`start_time`
)
) ELSE 0 END
) / 3600,
2
),
0
) AS `hours_worked`,
COALESCE (
COUNT (`job_reports`.`id`),
0
) AS `num_reported_sites`,
COALESCE (
SUM (
CASE WHEN `jobs`.`job_category_id` = 2
AND `job_reports`.`id` IS NOT NULL THEN 1 ELSE 0 END
),
0
) AS `pm_num_reported_jobs`,
COALESCE (
SUM (
CASE WHEN `jobs`.`job_category_id` = 2 THEN 1 ELSE 0 END
),
0
) AS `pm_num_jobs`
FROM
`jobs`
INNER JOIN `job_categories` ON `job_categories`.`id` = `jobs`.`job_category_id`
LEFT OUTER JOIN `assigned_jobs` ON `jobs`.`id` = `assigned_jobs`.`job_id`
LEFT OUTER JOIN `job_reports` ON `assigned_jobs`.`assigned_job_id` = `job_reports`.`assigned_job_id`
LEFT OUTER JOIN `closed_job_reports` ON `job_reports`.`id` = `closed_job_reports`.`job_report_id`
LEFT OUTER JOIN `pending_jobs` ON `jobs`.`id` = `pending_jobs`.`new_job_id`
WHERE
`jobs`.`date_added` BETWEEN '2022-01-01' AND '2022-02-17'
-- GROUP BY
-- `closed_job_reports`.`job_report_id`, `job_reports`.`id`, `assigned_jobs`.`assigned_job_id`, `pending_jobs`.`id`, `closed_job_reports`.`job_report_id`, `job_reports`.`id`, `assigned_jobs`.`assigned_job_id`
ORDER BY
`jobs`.`id` DESC
I can easily run it from PhpMyAdmin and get what I want like what is shown below:
but when running from laravel with the DB::select method, I get a syntax error:
SQLSTATE[42000]: Syntax error or access violation: 1140 Mixing of
GROUP columns (MIN(),MAX(),COUNT(),...) with no GROUP columns is
illegal if there is no GROUP BY clause (SQL: SELECT
...
I have a lot of such queries that I would be running. I checked this post:
Syntax error or access violation: 1140 Mixing of GROUP columns (MIN(),MAX(),COUNT(),...)
but mine seems to be a little more complicated owing to the fact that I have to query from several related tables. I have seen other people recommend disabling mysql strict mode, but I don't want to do that.
I know some of you might have encountered this issue with complicated queries. Please what steps or techniques you use in resolving some of these issues? Thanks.
Okay. so you've got a really complex query like mine? Well, I found out I did not need a view from the database because it was unnecessary in my case.
First, I had to break down my query into smaller parts and one at a time. This was after I was pointed to the Laravel docs https://laravel.com/docs/9.x/queries#raw-expressions
I started with the main table from the original query - jobs and proceeded to adding the joins to the query.
The grouping of the data was the most complicated part. That was what I had problems with. So after breaking down the query, I had to change what I was using for the original grouping of data. Grouping the data into job category name (or job category id) made it simpler.
In the end, the displayed results I was getting looked much better.
Here is a code to illustrate.
I have made some modifications to the original queries but still maintaining the joins that I needed.
$users = DB::table('jobs')
->select(DB::raw(
'job_categories.category_name, COUNT(jobs.id) as jobs_count, COUNT(assigned_jobs.assigned_job_id) AS assigned_jobs_count,
COUNT(recurring_jobs.job_id) AS recurring_jobs_count,
COALESCE(SUM(
CASE WHEN
assigned_jobs.assigned_job_id IS NULL
THEN 1 ELSE 0
END
), 0) AS unassigned_jobs_count,
COUNT(job_reports.id) AS reported_jobs_count,
COALESCE(SUM(
CASE WHEN job_reports.id IS NULL
THEN 1 ELSE 0
END
), 0) AS unreported_jobs_count,
COALESCE(SUM(
CASE WHEN closed_job_reports.job_report_id IS NOT NULL THEN 1 ELSE 0
END
), 0) AS closed_jobs_count,
COALESCE(SUM(
CASE WHEN job_reports.id IS NOT NULL AND closed_job_reports.job_report_id IS NULL THEN 1 ELSE 0
END
), 0) AS reported_unclosed_jobs_count,
COALESCE(SUM(
CASE WHEN
(job_reports.id IS NULL AND jobs.deadline > NOW() AND assigned_jobs.assigned_job_id IS NULL)
THEN 1 ELSE 0
END
), 0) AS opened_only_jobs_count,
COALESCE(SUM(
CASE WHEN
job_reports.id IS NULL AND jobs.deadline > NOW() AND assigned_jobs.assigned_job_id IS NOT NULL OR
(job_reports.id IS NULL AND jobs.deadline > NOW() AND pending_jobs.id IS NOT NULL)
THEN 1 ELSE 0
END
),0) AS pending_jobs_count,
COALESCE(SUM(
CASE WHEN job_reports.id IS NULL AND jobs.deadline <= NOW() THEN 1 ELSE 0
END
), 0) AS overdue_jobs_count
'
))
->groupBy('job_categories.category_name')
->join('job_categories', 'job_categories.id', '=', 'jobs.job_category_id')
->leftJoin('assigned_jobs', 'jobs.id', '=', 'assigned_jobs.job_id')
->leftJoin('pending_jobs', 'jobs.id', '=', 'pending_jobs.new_job_id')
->leftJoin('job_reports', 'job_reports.assigned_job_id', '=', 'assigned_jobs.assigned_job_id')
->leftJoin('closed_job_reports', 'closed_job_reports.job_report_id', '=', 'job_reports.id')
->leftJoin('recurring_jobs', 'recurring_jobs.job_id', '=', 'jobs.id')
->get();
I hope this helps someone to troubleshoot their issues with the error
SQLSTATE[42000]: Syntax error or access violation: 1140 Mixing of GROUP columns (MIN(),MAX(),COUNT(),...) with no GROUP columns is illegal if there is no GROUP BY clause
when using laravel or other similar framework...

Oracle function to select multiple rows in a single row not working

I am loading a file into a staging record using Application Engine. when ever there is blank in BU,Deptid etc... I have to capture what all columns are blank and update error text field with those values.
UPDATE SYSADM.PS_VI_EMP_TS SET ERR_TEXT =
SELECT ERROR FROM (SELECT * FROM (
SELECT CASE WHEN BUSINESS_UNIT = ' ' THEN 'BUSINESS_UNIT IS NULL' ELSE ' ' END AS ERROR FROM SYSADM.PS_VI_EMP_TS WHERE USERID='JCOOPER' AND ACTION = 'E' AND PROCESS_INSTANCE = '7852429'
UNION
SELECT CASE WHEN DEPTID = ' ' THEN 'DEPTID IS NULL' ELSE ' ' END AS ERROR FROM SYSADM.PS_VI_EMP_TS WHERE USERID='JCOOPER' AND ACTION = 'E' AND PROCESS_INSTANCE = '9852429'
UNION
SELECT CASE WHEN PROJECT_ID =' ' THEN 'PROJECT_ID IS NULL' ELSE ' ' END AS ERROR FROM SYSADM.PS_VI_EMP_TS WHERE USERID='JCOOPER' AND ACTION = 'E' AND PROCESS_INSTANCE = '9852429'
)) WHERE ERROR <> ' '
WHERE USERID='JCOOPER' AND ACTION = 'E' AND PROCESS_INSTANCE = '9852429'
The above script results as below.
ERROR
BUSINESS_UNIT IS NULL
DEPTID IS NULL
I want the result as below.
ERROR
BUSINESS_UNIT IS NULL,DEPTID IS NULL
I am using ListAgg function but facing errors as below.Any help would be great.
SELECT LISTAGG(BUSINESS_UNIT, ';') WITHIN GROUP(ORDER BY USERID)
FROM SYSADM.PS_VI_EMP_TS WHERE USERID='JCOOPER'
GROUP BY BUSINESS_UNIT
Facing the error:
ORA-00923: FROM keyword not found where expected
00923. 00000 - "FROM keyword not found where expected"
*Cause:
*Action:
Error at Line: 47 Column: 43
You overcomplicated things. You don't need two unions and listagg at all. Simple use concatenation of case... when, write your select like here:
select case business_unit when ' ' then 'BUSINESS_UNIT IS NULL; ' end ||
case deptid when ' ' then 'DEPTID IS NULL; ' end ||
case project_id when ' ' then 'PROJECT_ID IS NULL; ' end as error
from ps_vi_emp_ts
where userid = 'JCOOPER' and action = 'E' and process_instance = '9852429'
demo
If your table has primary key then use it for update. Otherwise you can use merge with rowid. Or do it the way you did it if it worked for you, especially if there is only one row meeting criteria.

If Else logic converting to Select case - Oracle

IF inputVariable = '0'
THEN
DELETE existingTemptable
WHERE status != 999;
ELSE
IF inputVariable = '1'
THEN
DELETE existingTemptable
WHERE status = 999;
ELSE
DELETE existingTemptable
WHERE status != 999
AND date < utils.dateadd('MONTH', -6, SYSTIMESTAMP);
END IF;
END IF;
This If logic is present on a temp table and I have to remove the temp table and make it only select query , so approached with WITH CTE but stuck in the below
what should be in the where clause
with existingTemptable as
(
//got the temp table here
), myTable as
(
Select * from existingTemptable
**where
status = CASE WHEN inputVariable = '0' THEN 999
WHEN inputVariable != '0' AND inputVariable != '1' THEN 999
ELSE status
END**
)Select * from myTable
What to put in WHERE clause so that it mimics the If logic above
You have to be careful if inputVariable or status (or both) may be null. The rest is a direct application of logical rules one learns (or should learn) in middle school.
select *
from existingTemptable
where inputVariable = '0' and (status = 999 or status is null)
or
inputVariable = '1' and (status != 999 or status is null)
or
(inputVariable is null or inputVariable not in ('0', '1'))
and (status = 999 or status is null) and date >= [whatever]
Note - even in the absence of null handling, you can't write the where clause with a case expression; that's because in one branch you require "not equal", and you can't do it with a simple case expression.

LINQ: A query body must end with a select clause or a group clause and other errors

I have the following SQL statement:
CASE
WHEN wt.pmtlr_oi IS NULL OR (SELECT COUNT(*) FROM mc.SCHEDENTRY WITH (NOLOCK) WHERE wt_oi = wt.wtskoi AND shedref_oi NOT IN (SELECT shdoi FROM mc.SCHDULE WITH (NOLOCK) WHERE aenm LIKE '%Breakin%')) = 0 AND wt.pmtlr_oi IS NULL
THEN 'Break-In'
ELSE 'Planned'
END AS schedule
which I have translated into:
Schedule = wt.pmtlr_oi == null || (from sch in SCHEDENTRies where wt_oi == wt.wtskoi && shedref_oi !(from sc in SCHDULEs
where sc.Aenm.Contains("Breakin") select sc.Shdoi)).Count() == 0 && wt.pmtlr_oi == null ? "Break-In" : "Planned"}
Here's how it looks in the select statement:
select new {Schedule = wt.pmtlr_oi == null || (from sch in SCHEDENTRies where wt_oi == wt.wtskoi && shedref_oi !(from sc in SCHDULEs
where sc.Aenm.Contains("Breakin") select sc.Shdoi)).Count() == 0 && wt.pmtlr_oi == null ? "Break-In" : "Planned"});
However when I try and run it there are some problems which I do not know how to fix. The first one is that the compiler doesn't appear to like the NOT IN found here:
&& shedref_oi !(from sc in SCHDULEs
I get a "A query body must end with a select clause or a group clause" error.
The compiler also doesn't like this:
select sc.Shdoi)).Count() == 0
On the outer parenthesis I get a "Syntax error ',' expected" error and on the period I get a "Statement expected" error message.
I would appreciate some help in troubleshooting this.
EDIT:
OK, After the comments I have corrected the LINQ statement to look like this:
select new {Schedule = wt.pmtlr_oi == null || (from sch in SCHEDENTRies where wt_oi == wt.wtskoi && !(from sc in SCHDULEs
where sc.Aenm.Contains("Breakin") select sc.Shdoi).Contains(shedref_oi)).Count() == 0 && wt.pmtlr_oi == null ? "Break-In" : "Planned"});
and the compiler likes it. However, it still doesn't like the .Count(). I get a "Statement expected" error. Am I incorrect in using .Count() for the sql SELECT COUNT(*)?

Resources