How to create advanced check condition - oracle

I have an Oracle table and I would like to create a check condition like this :
ALTER TABLE MyTable
ADD CONSTRAINT MyTable_CHK2 CHECK (
case Dimension
When 1 then
nvl(dimensiontype1,-1)<>-1
when 2 then
nvl(dimensiontype1,-1)<>-1 and nvl(dimensiontype2,-1)<>-1
when 3 then
nvl(dimensiontype1,-1)<>-1 and nvl(dimensiontype2,-1)<>-1 and nvl(dimensiontype3,-1)<>-1
else
true
end
)
disable
The query is not working. I'm having the error : Missing Keyword.
Anyone know how to solve that please ?
Thanks.

You probably want an AND / OR expression
ALTER TABLE MyTable
ADD CONSTRAINT MyTable_CHK2 CHECK
(
( Dimension = 1 and nvl(dimensiontype1,-1) <> - 1 ) OR
( Dimension = 2 and (nvl(dimensiontype1,-1) <> - 1 and nvl(dimensiontype2,-1)<> -1 ) ) OR
( Dimension = 3 and (nvl(dimensiontype1,-1) <> -1 and nvl(dimensiontype2,-1)<> -1 and nvl(dimensiontype3,-1) <> -1))
) disable ;

Check constraint should be:
(dimension=1 and dimensiontype1 is not null)
or (dimension=2 and dimensiontype1 is not null and dimensiontype2 is not null)
or (dimension=3 and dimensiontyp1 is not null and dimensiontype2 is not null and dimensionType 3 is not null)

Related

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 - Updating table based on field from another table

I have a Task table and a Project table. I'm trying to update the Percent Complete field in the Project table with the value of the Percent Complete field from the Tasks table. But I only want to update the field when the sequence code from the Task table is equal to 1. My failed attempt looks like this:
UPDATE inv_projects prj
SET prj.percent_complete = (SELECT NVL(tsk.prpctcomplete, 0)
FROM prtask tsk
WHERE tsk.prprojectid = prj.prid)
WHERE (SELECT tsk.prwbssequence
FROM prtask tsk
WHERE prj.prid = tsk.prprojectid) = 1;
I'm getting the error:
Error starting at line : 1 in command -
...
Error report -
ORA-01427: single-row subquery returns more than one row
I'm not quite sure what's going wrong.
Presumably, you want the sequence filtering in the subquery, like so
UPDATE inv_projects prj
SET prj.percent_complete = (
SELECT NVL(tsk.prpctcomplete, 0)
FROM prtask tsk
WHERE tsk.prprojectid = prj.prid AND sk.prwbssequence = 1
)
This assumes that (prprojectid, prwbssequence) is unique in the task table, which seems consistent with your problem statement.
If there are projects without a task of sequence 1, and you don't want to update them, then use exists:
UPDATE inv_projects prj
SET prj.percent_complete = (
SELECT NVL(tsk.prpctcomplete, 0)
FROM prtask tsk
WHERE tsk.prprojectid = prj.prid AND sk.prwbssequence = 1
)
WHERE EXISTS (
SELECT 1
FROM prtask tsk
WHERE tsk.prprojectid = prj.prid AND sk.prwbssequence = 1
)
Or maybe your intent is to set the completion percent to 0 in this case; if so, move NVL() outside of the subquery:
UPDATE inv_projects prj
SET prj.percent_complete = NVL(
(
SELECT tsk.prpctcomplete
FROM prtask tsk
WHERE tsk.prprojectid = prj.prid AND sk.prwbssequence = 1
),
0
)

Unexpected NULL in multi-column correlated update

I want to run a multi-column correlated update of this kind:
UPDATE t1 t1_alias
SET (table_name, tablespace_name) = (
SELECT table_name, tablespace_name
FROM t2 t2_alias
WHERE t1_alias.table_name = t2_alias.table_name
);
But my attempt:
update customer up
set (customer_name, account, active) = (
select tmp.name, tmp.account, case when tmp.active = 'Yes' then 1 else 0 end
from customer_temp tmp
where up.agent = substr(tmp.agent, -4) and up.customer_code = tmp.code
);
... throws:
ORA-01407: cannot update ("FOO"."CUSTOMER"."CUSTOMER_NAME") to NULL
The source table customer_temp has no null values so I must be getting matches wrong. What is my error or misconception?
Presumably, there are some rows in the target table that have no match in the subquery.
You can avoid this with by adding an exists condition that filters out "unmatched" rows:
update customer up
set (customer_name, account, active) = (
select tmp.name, tmp.account, case when tmp.active = 'Yes' then 1 else 0 end
from customer_temp tmp
where up.agent = substr(tmp.agent, -4) and up.customer_code = tmp.code
)
where exists (
select 1
from customer_temp tmp
where up.agent = substr(tmp.agent, -4) and up.customer_code = tmp.code
);

remove rows from table having full outer join condition

I have used full outer join condition in my joining query for joining two tables and the sample code is as below
select * from(
select TO_CHAR(ROUND(col11)) as today1,TO_CHAR(ROUND(col12)) as today2 from T1
full outer join
select TO_CHAR(ROUND(col21)) as yes1,TO_CHAR(ROUND(col22)) as yes2 from T2
) MAIN
where MAIN.today1<>0 and MAIN.today2<>0 and MAIN.yes1<>0 and MAIN.yes2<>0
sample output expected as below
today1 today2 yes1 yes2
somevalue somevalue null null
null null some value somevalue
somevalue somevalue somevalue some value
0 0 0 0
I am trying to remove rows having all zero values using above where clause but output doubles and also row with zero values apperas. Can I know where I am going wrong. Any help much appreciated.
trying to remove rows having all zero values
use:
AND NOT ( MAIN.today1=0 and MAIN.today2=0 and MAIN.yes1=0 and MAIN.yes2=0 )
which can be transformed, using De Morgan's laws: ===> https://en.wikipedia.org/wiki/De_Morgan%27s_laws into:
AND ( NOT MAIN.today1=0 OR NOT MAIN.today2=0 OR NOT MAIN.yes1=0 OR NOT MAIN.yes2=0 )
which can be further simplified to:
AND ( MAIN.today1<>0 OR MAIN.today2<>0 OR MAIN.yes1<>0 OR MAIN.yes2<>0 )
Note: if you want to also get NULL values, you must use IS NULL operator:
where ( MAIN.today1<>0 OR MAIN.today1 IS NULL )
and ( MAIN.today2<>0 OR MAIN.today2 IS NULL )
and ( MAIN.yes1<>0 OR MAIN.yes1 IS NULL )
and ( MAIN.yes2<>0 OR MAIN.yes2 IS NULL )

How to compare multiple columns under same row in a table?

Following columns of a table should not be equal in my where clause.
cd_delivery_address
cd_mail_delivery_address
cd_st_code
cd_mail_st_code
cd_zip
cd_mail_zip
Please find my code snippet to achieve this:
select * from table cd
where
(
(cd_mail_delivery_address <> cd_delivery_address or
(cd_mail_delivery_address is null and cd_delivery_address is not null) or
(cd_mail_delivery_address is not null and cd_delivery_address is null)
)
and (
cd.cd_city <> cd.cd_mail_city or
(cd.cd_city is null and cd_mail_city is not null) or
(cd_city is not null and cd_mail_city is null))
and (
cd.st_code <> cd.cd_mail_st_code or
(cd.st_code is null and cd_mail_st_code is not null) or
(st_code is not null and cd_mail_st_code is null)
)
and (
cd.cd_zip <> cd.cd_mail_zip or
(cd.cd_zip is null and cd_mail_zip is not null) or
(cd_zip is not null and cd_mail_zip is null)
)
)
All columns are varchar2 and i get correct output for this code. But is it a better way to compare multiple columns in pl sql? can i improve this code? Any suggestion would be helpful.
You could replace your null checks with NVL function something like this:
...
NVL(cd_mail_delivery_address,'_') <> NVL(cd_delivery_address,'_')
...
it's definitively more readable but I'm not sure about query efficency
I have done it for two columns using a join:
select a.cd_delivery_address,b.cd_mail_delivery_address
from cd a inner join cd b
where a.cd_delivery_address <> b.cd_mail_delivery_address and
a.cd_delivery_address = b.cd_delivery_address
Here null checking condition will be omitted and will reduce the number of conditions, but there is a performance impact since join is involved.

Resources