mysql join slow performance - mysql

i have 3 table with structures
plans
- id
- cost_center_code
- cost_element_code
- val_usd
commitments
- id
- cost_center_code
- cost_element_code
- val_usd
actuals
- id
- cost_center_code
- cost_element_code
- val_usd
i want join 3 table using 2 key (cost_center_code,cost_element_code) and show sum val_usd from each table
this my current query and took 15-20s
select
plans.cost_center_code,
plans.cost_element_code,
sum(plans.val_usd) as plan_usd,
sum(commitments.val_usd) as commitment_usd,
sum(actuals.val_usd) as actual_usd
from `plans`
left join `commitments`
on
`plans`.`cost_center_code` = `commitments`.`cost_center_code`
and `plans`.`cost_element_code` = `commitments`.`cost_element_code`
left join `actuals`
on
`plans`.`cost_center_code` = `actuals`.`cost_center_code`
and `plans`.`cost_element_code` = `actuals`.`cost_element_code`
where
date(`plans`.`document_date`) = '2021-07-27'
and date(`commitments`.`document_date`) = '2021-07-27'
and date(`actuals`.`document_date`) = '2021-07-27'
and `plans`.`deleted_at` is null
group by `plans`.`cost_center_code`, `plans`.`cost_element_code`
limit 10
[edit]
my query result
EXPLAIN query result

Related

Select range date from and to and also select specific id

I want to select a date range with specific provider ID and this query should print 2 data only since there's only 2 row with provider id = 1
SQL Query:
SELECT logs_tb.logs_id
,logs_tb.time_in
,logs_tb.status
,logs_tb.provider_id
,users_tb.user_first_name
,users_tb.user_last_name
,users_tb.user_contactno
,users_tb.user_city
,users_tb.user_avatar
,users_tb.user_email
,users_tb.user_contactno
,users_tb.user_uuid
FROM logs_tb
,users_tb
WHERE logs_tb.provider_id = 1
AND logs_tb.log_date BETWEEN '2022-03-25' AND '2022-03-26'
ORDER BY logs_tb.logs_id desc;
Table:
Output:
I used ON condition, thank you M.Hermant
Query:
SELECT logs_tb.logs_id, logs_tb.time_in, logs_tb.status, logs_tb.provider_id, users_tb.user_first_name, users_tb.user_last_name, users_tb.user_contactno, users_tb.user_city, users_tb.user_avatar, users_tb.user_email, users_tb.user_contactno, users_tb.user_uuid
FROM users_tb
INNER JOIN logs_tb
ON users_tb.user_id = logs_tb.user_id
WHERE (logs_tb.log_date BETWEEN '2022-03-25' AND '2022-03-26') AND logs_tb.provider_id = 1
ORDER BY logs_tb.log_date desc;
Output:

MySql Retrieving Data from multiple Tables then Insert limited values In another table

I have many tables with the same structure for each of my costumers.
All information are distinct for each table.
For some reason, I need to create some temporary table with the same structure with 200 values everytime I run.
So let's assume I have 3 tables.
Costumer1, Costumer2, Costumer3.
All those tables have id, user_name, contact_name, contact_email, sent1, sent2, sent3, sent4, status.
I need some query to put inside costumer_tmp, only 200 values in total, from all those 3 tables, everytime I run the script. And everytime I run cant repeat the last values I got before.
So for example:
Costumer1
id = 29
user_name = test1
contact_name = contact1
contact_email = contact1#mail.com
sent1 = yes
sent2 = no
sent3 = no
sent4 = no
status = In Progress
Costumer2
id = 37
user_name = test2
contact_name = contact123
contact_email = contact123#mail.com
sent1 = yes
sent2 = no
sent3 = no
sent4 = no
status = In Progress
Costumer3
id = 87
user_name = test3
contact_name = contact231
contact_email = contact231#mail.com
sent1 = yes
sent2 = no
sent3 = no
sent4 = no
status = In Progress
How to Insert on costumer_tmp only 2 records of those 3 and next time I run the script don't repeat those 2 records, just insert only 1 record remaining.
Your requirement is a bit weird, but if I understand weel, how about something like : (not tested)
insert into costumer_tmp
select * from Costumer1 one where one.id not in (select id from costumer_tmp)
union all
select * from Costumer2 two where two.id not in (select id from costumer_tmp)
union all
select * from Costumer3 three where three.id not in (select id from costumer_tmp) LIMIT 200

joining tables takes very long time symfony 2.7

I have the following query which takes more than 20 secs (20138ms) to return the results.
$locale = 'en'; // test
$query = $this->getEntityManager()->createQuery('
SELECT
product.id, product.productnr, ProductGrp.productgrp' . $locale . ', Criteria.criteria'.$locale.'
FROM
Productbundle:product product
JOIN
Productbundle:Criteria Criteria WITH Criteria.criteriaid = product.criteriaid
JOIN
Productbundle:ProductGrp ProductGrp WITH ProductGrp.partgrpid = product.partgrpid
WHERE
product.productnr =:productnr
')
->setMaxResults(1)
->setParameter('productnr', $productnr)
->getResult();
when I ran the query from "runnable query" it took about 20 secs (20.7809) in phpmyadmin.
runnable query :
SELECT o0_.id AS id0, o0_.productnr AS productnr1, o1_.productgrpen AS productgrpen2, o2_.criteriaen AS criteriaen3
FROM product o0_
INNER JOIN Criteria o2_ ON (o2_.criteriaid = o0_.criteriaid)
INNER JOIN ProductGrp o1_ ON (o1_.partgrpid = o0_.partgrpid)
WHERE o0_.productnr = 'ABC1234'
LIMIT 1;
However when I ran the following code in phpmyadmin it takes less than 2seconds to return the results
SELECT product.id, product.productnr,ProductGrp.productgrpen ,Criteria.criteriaen
FROM `product`
INNER JOIN ProductGrp ON ProductGrp.partgrpid = product.partgrpid
INNER JOIN Criteria ON Criteria.criteriaid = product.criteriaid
Where productnr = 'ABC1234'
LIMIT 1
table size
-------------------------------
|Product | over 5mill rows |
-------------------------------
|ProductGrp | over 200 rows |
-------------------------------
|Criteria | over 600 rows |
-------------------------------
Symfony version : 2.7
Indexes although not listed, I would suggest the following
table indexed on
Product (productnr, id, criteriaid, partgrpid )
Criteria (criteriaid ) -- would expect as primary key
ProductGrp (partgrpid ) -- also would expect
Also, how many "locale" string version columns do you have / support.

MySQL: Use value from table 2 instead of table 1 when exists in table 2

I have a transport planner written in PHP and MySQL,
To get the task rules per day, I use the following query:
SELECT planning.*,
planning_dagen.planning_id,
planning_dagen.dagen,
planning_dagen.data_import,
routenummer_wijzigingen.routenummer AS temp_routenummer
FROM planning
LEFT JOIN planning_dagen
USING (planning_id)
LEFT JOIN routenummer_wijzigingen
USING (planning_id)
WHERE :datum >= planning.datum
AND :datum <= geldig_tot
AND (frequentie = 'dagelijks' AND dayofweek(:datum) = planning_dagen.dagen
OR (frequentie = 'eenmalig' AND date(:datum) = planning.datum)
OR (frequentie = 'wekelijks' AND 0 = (abs(datediff(:datum, planning.datum)) % 7))
OR (frequentie = 'twee-wekelijks' AND 0 = (abs(datediff(:datum, planning.datum)) % 14))
OR (frequentie = 'maandelijks'
AND ceil(dayofmonth(:datum)/7) = ceil(dayofmonth(planning.datum)/7)
AND dayofweek(:datum) = dayofweek(planning.datum)))
AND dayofweek(:datum) <> '1'
AND dayofweek(:datum) <> '7'
In the planning table there is a column called routenummer (routenumber) which is used in most conditions (standard routenumber).
But as you can see I have also a routenummer_wijzigingen table which is used to give a task a different routenumber for certain day.
For example I have a task which returns every tuesday and wednesday and has routenumber 10. But on tuesday 2015-02-03 I need this task done by routenumber 9.
So I insert a rule in the routenummer_wijzigingen table which has the following columns:
routenummer_wijzigingen_id
planning_id
routenummer
datum
So when a date is selected and that date and planning_id exists in the routenummer_wijzigingen table, it has to take the routenumber from the routenummer_wijzigingen table instead of the planning table.
How can I achieve this?
You should modify join condition with routenummer_wijzigingen table (including datum). Then you should use CASE in your SELECT clause to decide which routenummer to choose.
SELECT planning.*,
planning_dagen.planning_id,
planning_dagen.dagen,
planning_dagen.data_import,
CASE
WHEN routenummer_wijzigingen.routenummer is not NULL
THEN routenummer_wijzigingen.routenummer
ELSE planning.routenummer
END AS temp_routenummer
FROM planning
...
LEFT JOIN routenummer_wijzigingen rw on
planning.planning_id=rw.planning_id and rw.datum=...

Update table with subquery works on mysql but error on oracle

I have table named TABLE_A looks like this :
ID DATA VALUE LM
---------------------------------
1 7 9 NULL
2 10 5 NULL
3 4 7 NULL
This is not actually my table, i use this to shorten my question.
Now I want to update table_a with subquery.
This is my query :
UPDATE TABLE_A,
(SELECT VALUE AS VAL FROM TABLE_A WHERE ID = 2) AS TEMP
SET TABLE_A.LM = TABLE_A.VALUE + TEMP.VAL
WHERE TABLE_A.ID = 1
This query works on Mysql but in oracle I got error :
[Err] ORA-00971: missing SET keyword
EDIT :
This is my table [SDM_ABSENSI] :
PERIODE TGL_IN TGL_OUT IN OUT LM TL
------------------------------------------------------------------
20141011 11/01/2014 11/01/2014 08:00 17:00 NULL NULL
20141012 12/01/2014 13/01/2014 22:00 07:30 NULL NULL
20141013 13/01/2014 13/01/2014 08:00 17:00 NULL NULL
My query :
UPDATE SDM_ABSENSI A
(
SELECT PERIODE, TGL_IN, TGL_OUT, IN, OUT,
TO_DATE(TO_CHAR(TGL_IN,'YYYY-MM-DD')||' '||IN,'YYYY-MM-DD hh24:mi') AS MASUK,
TO_DATE(TO_CHAR(TGL_OUT,'YYYY-MM-DD')||' '||OUT,'YYYY-MM-DD hh24:mi') AS KELUAR
FROM SDM_ABSENSI
WHERE SUBSTR(PERIODE,0,6) = '201410'
)ABSEN
SET A.LM = (24*60) * (ABSEN.KELUAR - ABSEN.MASUK),
A.TL = CASE WHEN (24*60) * (ABSEN.KELUAR - ABSEN.MASUK) < 0
THEN 0 ELSE (24*60) * (ABSEN.KELUAR - ABSEN.MASUK)
END
WHERE SUBSTR(A.PERIODE,0,6) = '201410'
AND A.PERIODE = ABSEN.PERIODE
And i got error :
[Err] ORA-00971: missing SET keyword
Please help,
Thanks in advance
Oracle does not support Update from Join Syntax. Instead you can use Merge. Try this.
MERGE
INTO SDM_ABSENSI
USING (
SELECT PERIODE, TGL_IN, TGL_OUT, IN, OUT,
TO_DATE(To_char(TGL_IN,'YYYY-MM-DD')||' '||IN,'YYYY-MM-DD hh24:mi') AS MASUK,
TO_DATE(TO_CHAR(TGL_OUT,'YYYY-MM-DD')||' '||OUT,'YYYY-MM-DD hh24:mi') AS KELUAR
FROM SDM_ABSENSI
WHERE SUBSTR(PERIODE,0,6) = '201410'
) ABSEN
ON SDM_ABSENSI.PERIODE = ABSEN.PERIODE
WHEN MATCHED THEN
UPDATE
SET SDM_ABSENSI.LM = ( 24 * 60 ) * ( ABSEN.KELUAR - ABSEN.MASUK ),
SDM_ABSENSI.TL = CASE
WHEN ( 24 * 60 ) * ( ABSEN.KELUAR - ABSEN.MASUK ) < 0 THEN 0
ELSE ( 24 * 60 ) * ( ABSEN.KELUAR - ABSEN.MASUK )
END
I don't think you can write such a subquery in Oracle. You should maybe checkout the update statement as its defined in the oracle documentation, here http://docs.oracle.com/cd/B19306_01/appdev.102/b14261/update_statement.htm
Having said that, what do you really want to do here? What value and under which conditions do you want to assign to the column LM?
That query doesn't look so good, in my opinion. You're trying to build a temporary table from the data stored in table_a and update that same table_a with values from that temporal table... but how? With the maximum of the temporal table? With the value of the same register when the condition is met?
I don't see how that query could work in MySQL either to be honest.
To sum up, could you provide additional info?
[EDIT] Just saw the modification in the question. You can remove the subquery from where it is and place it in the where statement...
UPDATE TABLE_A
SET TABLE_A.LM = TABLE_A.VALUE + (SELECT VALUE AS VAL FROM TABLE_A WHERE ID = 2)
WHERE TABLE_A.ID = 1