Update table based on sub select of two other tables - mysql

I'm really new here and I really need help. I am trying to update a table based on data joined from another select statement.
SELECT DISTINCT A.business_unit_AP
, A.VOUCHER_ID
, A.JOURNAl_ID
, A.UNPOST_SEQ
, A.APPL_JRNL_ID
, A.PYMNT_CNT
, A.VOUCHER_LINE_NUM
, A.DISTRIB_LINE_NUM,A.dst_acct_type
, A.LEDGER
, A.PROCESS_INSTANCE
FROM PS_PROJ_RES_TMP A
LEFT OUTER JOIN ps_proj_res_cal_vw B
ON a.business_unit_ap = B.BUSINESS_UNIT_AP
AND B.PROJECT_ID = A.PROJECT_ID
AND A.ACTIVITY_ID = B.ACTIVITY_ID
AND A.RESOURCE_ID = B.RESOURCE_ID
WHERE A.SYSTEM_SOURCE ='BAP'
AND b.business_unit_ap is null*
So basically the statement above select data from PS_PROJ_RES_TMP table that doesn't exist in PS_PROJ_RES_CAL_VW. Am i right? Then based on the data pulled, I will then update PS_VCHR_ACCTG_LINE.
I formulated this script but its taking too long. And i ended up updating the whole table.
UPDATE PS_VCHR_ACCTG_LINE C
SET C.PC_DISTRIB_STATUS = 'N'
WHERE EXISTS
(
SELECT DISTINCT A.business_unit_AP
, A.VOUCHER_ID
, A.JOURNAl_ID
, A.UNPOST_SEQ
, A.APPL_JRNL_ID
, A.PYMNT_CNT
, A.VOUCHER_LINE_NUM
, A.DISTRIB_LINE_NUM
, A.dst_acct_type
, A.LEDGER
, A.PROCESS_INSTANCE
FROM PS_PROJ_RES_TMP A
LEFT OUTER JOIN ps_proj_res_cal_vw B
ON a.business_unit_ap = B.BUSINESS_UNIT_AP
AND B.PROJECT_ID = A.PROJECT_ID
AND A.ACTIVITY_ID = B.ACTIVITY_ID
AND A.RESOURCE_ID = B.RESOURCE_ID
WHERE b.business_unit_ap is null
AND b.PROJECT_ID is null
AND b.ACTIVITY_ID is null
AND b.RESOURCE_ID is null
AND C.BUSINESS_UNIT = a.business_unit_ap
AND C.VOUCHER_ID = A.VOUCHER_ID
AND C.unpost_seq = A.unpost_seq
AND c.appl_jrnl_id = A.appl_jrnl_id
AND c.PYMNT_CNT = A.pymnt_cnt
AND C.voucher_line_num = A.voucher_line_num
AND C.distrib_line_num = A.distrib_line_num
AND C.dst_acct_type = A.dst_acct_type
AND C.ledger = A.ledger
AND A.SYSTEM_SOURCE ='BAP'
);
Where did i go wrong? Thank you so much for the help :)

It is pretty much impossible for an outsider to figure out the issues with your query. The problem of updating all the rows would seem to be because the logic in the query, on the data in the table, causes a match for all rows.
There is one easy thing you can do to improve performance. The distinct is not necessary when using exists. So the following should be equivalent:
UPDATE PS_VCHR_ACCTG_LINE C
SET C.PC_DISTRIB_STATUS = 'N'
WHERE EXISTS
(
SELECT 1
FROM PS_PROJ_RES_TMP A
LEFT OUTER JOIN ps_proj_res_cal_vw B
ON a.business_unit_ap = B.BUSINESS_UNIT_AP
AND B.PROJECT_ID = A.PROJECT_ID
AND A.ACTIVITY_ID = B.ACTIVITY_ID
AND A.RESOURCE_ID = B.RESOURCE_ID
WHERE b.business_unit_ap is null
AND b.PROJECT_ID is null
AND b.ACTIVITY_ID is null
AND b.RESOURCE_ID is null
AND C.BUSINESS_UNIT = a.business_unit_ap
AND C.VOUCHER_ID = A.VOUCHER_ID
AND C.unpost_seq = A.unpost_seq
AND c.appl_jrnl_id = A.appl_jrnl_id
AND c.PYMNT_CNT = A.pymnt_cnt
AND C.voucher_line_num = A.voucher_line_num
AND C.distrib_line_num = A.distrib_line_num
AND C.dst_acct_type = A.dst_acct_type
AND C.ledger = A.ledger
AND A.SYSTEM_SOURCE ='BAP';
If your original query runs quickly, then I would suggest putting the results in a temporary table and using that for the update.
I would speculate that the performance problem is actually due to ps_proj_res_cal_vw, which I further speculate is a view of some sort. MySQL doesn't always do a good job with optimizing views.

Related

Get data from a "log" table to a mySQL query

I need to check the data in a log table to see if the user has previously read a post. My log table is named foretag_kontaktervisadbrf2017 and it contains information about who has read a post. How can I edit my query so that i get information telling me if i have read a post or not?
This is my query so far:
SELECT
brfbolagsverket.BrfNamn
, brfextra.BrfId
, brfextra.Organisationsnr
, brfextra.Gatuadress
, brfextra.Ort
, brfextra.Lagenheter
, brfextra.ByggAr
, BrfHarFastighet.Fangdatum
FROM
(((((brfextra LEFT JOIN BrfHarFastighet ON brfextra.Organisationsnr = BrfHarFastighet.Organisationsnr)
LEFT JOIN brfkonkurs ON brfextra.Organisationsnr = brfkonkurs.Organisationsnr)
LEFT JOIN brfavford ON brfextra.Organisationsnr = brfavford.Organisationsnr)
LEFT JOIN brffusion ON brfextra.Organisationsnr = brffusion.Organisationsnr)
LEFT JOIN brflikvidation ON brfextra.Organisationsnr = brflikvidation.Organisationsnr)
LEFT JOIN brfbolagsverket ON brfextra.Organisationsnr = brfbolagsverket.Organisationsnr
WHERE
(((brfkonkurs.BolagetsStatusKod) IS NULL)
AND ((brfavford.BolagetsStatusKod) IS NULL)
AND ((brffusion.BolagetsStatusKod) IS NULL)
AND ((brflikvidation.BolagetsStatusKod) IS NULL OR (brflikvidation.BolagetsStatusKod) = 34))
In the result I need the following additional columns from the log table:
BrfId, BrfNamn, Organisationsnr, LogEntry
1, Billy, Organisationsnr, You have shown this post before
2, Carl, Organisationsnr, NULL
3, Kent, Organisationsnr, NULL
4, Sara, Organisationsnr, You have shown this post before
Please help with code I need to add to my query. I lack coding experience.
I would do this by adding a subselect like the example below. Hope it helps point you in the right direction.
SELECT
brfbolagsverket.BrfNamn
, CASE WHEN (SELECT COUNT(*) FROM foretag_kontaktervisadbrf2017 AS L WHERE L.Organisationsnr = B.Organisationsnr AND L.Foretag_kontaktID = 1247) > 0 THEN 'Lest' ELSE 'Inte lest' END AS NotificationRead
, brfextra.BrfId
, brfextra.Organisationsnr
, brfextra.Gatuadress
, brfextra.Ort
, brfextra.Lagenheter
, brfextra.ByggAr
, BrfHarFastighet.Fangdatum
FROM (((((
brfextra AS B
LEFT JOIN BrfHarFastighet ON brfextra.Organisationsnr = BrfHarFastighet.Organisationsnr)
LEFT JOIN brfkonkurs ON brfextra.Organisationsnr = brfkonkurs.Organisationsnr)
LEFT JOIN brfavford ON brfextra.Organisationsnr = brfavford.Organisationsnr)
LEFT JOIN brffusion ON brfextra.Organisationsnr = brffusion.Organisationsnr)
LEFT JOIN brflikvidation ON brfextra.Organisationsnr = brflikvidation.Organisationsnr)
LEFT JOIN brfbolagsverket ON brfextra.Organisationsnr = brfbolagsverket.Organisationsnr
WHERE (((brfkonkurs.BolagetsStatusKod) Is Null) AND ((brfavford.BolagetsStatusKod) Is Null) AND ((brffusion.BolagetsStatusKod) Is Null) AND ((brflikvidation.BolagetsStatusKod) Is Null Or (brflikvidation.BolagetsStatusKod)=34))
Im sorry if i post wrong - don't know how to reply properly to Werner Waage answer.
The query is slow when search gets more than 50-70 records - i tried to change to select like
(SELECT Foretag_kontaktervisadBrfID FROM foretag_kontaktervisadbrf2017 AS L WHERE L.Organisationsnr = B.Organisationsnr AND L.Foretag_kontaktID = '1247') AS NotificationRead
but its slow to.
My log table foretag_kontaktervisadbrf2017 have unique posts like this
Foretag_kontaktervisadBrfID, Foretag_kontaktID, Organisationsnr, Date001
1, Billy01, Acme_01, 2018-01-01
2, Carl01, Acme_02, 2018-01-02
3, Billy01, Acme_02, 2018-04-15
4, Carl01, Acme_03, 2018-14-14
Any way to get my previous speed back to the new query?
My original SQL-query worked fast even with results of 1000 records/post.
Here is another approach without using subselects, it assumes that the table foretag_kontaktervisadbrf2017 contains 0 or 1 row per user.
SELECT
brfbolagsverket.BrfNamn
, CASE WHEN L.Foretag_kontaktID IS NOT NULL THEN 'Lest' ELSE 'Inte lest' END AS NotificationRead
, brfextra.BrfId
, brfextra.Organisationsnr
, brfextra.Gatuadress
, brfextra.Ort
, brfextra.Lagenheter
, brfextra.ByggAr
, BrfHarFastighet.Fangdatum
FROM (((((
brfextra AS B
LEFT JOIN BrfHarFastighet ON brfextra.Organisationsnr = BrfHarFastighet.Organisationsnr)
LEFT JOIN brfkonkurs ON brfextra.Organisationsnr = brfkonkurs.Organisationsnr)
LEFT JOIN brfavford ON brfextra.Organisationsnr = brfavford.Organisationsnr)
LEFT JOIN brffusion ON brfextra.Organisationsnr = brffusion.Organisationsnr)
LEFT JOIN brflikvidation ON brfextra.Organisationsnr = brflikvidation.Organisationsnr)
LEFT JOIN brfbolagsverket ON brfextra.Organisationsnr = brfbolagsverket.Organisationsnr
LEFT JOIN foretag_kontaktervisadbrf2017 AS L ON L.Organisationsnr = B.Organisationsnr AND L.Foretag_kontaktID = 1247 -- This id probably needs to come from somewhere else, join in the users etc..
WHERE (((brfkonkurs.BolagetsStatusKod) Is Null) AND ((brfavford.BolagetsStatusKod) Is Null) AND ((brffusion.BolagetsStatusKod) Is Null) AND ((brflikvidation.BolagetsStatusKod) Is Null Or (brflikvidation.BolagetsStatusKod)=34))

MySQL query is taking too much time

I have query below:
SELECT t.t_id
, t.usr_idx
, t.t_is_for
, t.tg_ids
, t.created_time
, t.allow_reply
, u.usr_name
, u.usr_avatar
, u.show_profile
, IF(u.usr_timeline != '',CONCAT('https://s3.amazonaws.com/tuurnts3thumbnail/',u.usr_timeline),'') as usr_timeline
, u.node_userid
, t.t_time
FROM tuu_tuurnt t
JOIN tuu_user u
ON t.usr_idx = u.usr_idx
AND u.usr_state = 1
LEFT
JOIN tuu_post p
ON t.t_id = p.t_id
AND p.usr_idx = 44756
LEFT
JOIN tuu_friend f
ON f.frd_my_idx = 44756
AND f.frd_your_idx = t.usr_idx
LEFT
JOIN tuu_friend fl
ON fl.frd_your_idx = 44756
AND fl.frd_my_idx = t.usr_idx
WHERE t.status = 0
AND NOT EXISTS ( SELECT b.tuu_b_by_usr_idx
FROM tuu_blocked as b
WHERE b.tuu_b_usr_idx = 44756
AND t.usr_idx = b.tuu_b_by_usr_idx
)
GROUP
BY t.t_id
ORDER
BY t.t_time DESC
, t.t_id DESC
LIMIT 0,30;
It takes almost 7-8 second to give result but when I remove order by t.t_time and t.t_id then it runs within 1 sec max.
Is there anything I am doing wrong?
Without an index, MySQL must begin with the first row and then read through the entire table to find the relevant rows. The larger the table, the more this costs. See How MySQL Uses Indexes for details. See also this topic about using indexes and aliases together.

ROW Prior to the MAX row, not the MIN

I have the below query to find the row prior to MAX row. i feel like i am missing something, can somebody please help with it. I ammlooking forward to get the b.usercode_1 as row prior to a.usercode_1 not the min or any other random row but the ROW prior to the MAX.
Please suggest.
Select distinct
c.ssn
, c.controlled_group_Status CG_status
, c.last_name || ' , '|| c.first_name FULL_NAME
, a.usercode_1 Current_REG
, a.eff_date effective_since1
, b.usercode_1 PRIOR_REG
, b.eff_date effective_since2
, d.term_eff_date
from employee_eff_date c
, emp_cg_data a
, emp_cg_data b
, emp_ben_elects d
where c.control_id = 'XYZ'
and c.controlled_group_Status <> 'D'
and c.eff_date = (select max( c1.eff_date)
from emp_cg_data c1
where c.control_id = c1.control_id
and c.ssn = c1.ssn)
and a.control_id = c.control_id
and a.ssn = c.ssn
and a.eff_date = (select max(a1.eff_date )
from emp_cg_data a1
where a.control_id = a1.control_id
and a.ssn = a1.ssn)
and a.usercode_1 = 'REG26'
and b.control_id = c.control_id
and b.ssn = c.ssn
and b.eff_date = (select max( b1.eff_date)
from emp_cg_data b1
where b.control_id = b1.control_id
and b.ssn = b1.ssn
and b1.eff_date < a.eff_date)
and b.usercode_1 like 'REG%'
and d.control_id = c.control_id
and d.ssn = c.ssn
and d.life_event_date = (select max( d1.life_event_date)
from emp_ben_elects d1
where d.control_id = d1.control_id
and d.ssn = d1.ssn)
and d.le_seq_no= (select max( d1.le_seq_no)
from emp_ben_elects d1
where d.control_id = d1.control_id
and d.ssn = d1.ssn
and d.life_event_date = d1.life_event_date)
and d.term_eff_date is null
;
NOTE: this is not a complete answer... its a helpful suggestion of what you should start with.
you are doing a Cartesian Product of the four tables, filtered by a WHERE... so something like this
Implicit Join -- generally not a good practice as it can be very difficult to keep the where filters apart from the join conditions.
SELECT *
FROM tableA a, TableB b
WHERE b.id = a.id
another way to write a JOIN (the more generally accepted way)
SELECT *
FROM tableA a
JOIN tableB b ON b.id = a.id
Use the ON clause to join two tables together.
You should change your joins to this format so that others can read your query and understand it better.
suggestion to solve your problem
a fairly simple way to get the second to last row is to use a row counter.
so something like
SELECT *, #row_count := #row_count + 1
FROM tableA a
JOIN tableB b on b.id = a.id AND -- any other conditions for the join.
CROSS JOIN (SELECT #row_count := 0) t
then from here you can get the MAX row, whether thats the ID or something else. and then get the #row_num -1. aka the previous row.

Duplicates in MySQL query

I want to do the query directly a Magento database in MySQL but it gives me duplicates. Could you please help me?
SELECT DISTINCT
`catalog_product_entity`.`sku`
, `catalog_product_flat_1`.`name`
, `catalog_product_entity_text`.`value` AS `description`
, `catalog_product_flat_1`.`url_key`
, `catalog_product_flat_1`.`small_image`
, `catalog_product_flat_1`.`price`
, `catalog_product_flat_1`.`special_price`
, `catalog_product_flat_1`.`designer_value`
, `catalog_product_flat_1`.`color_value`
FROM
`ac_magento_gold`.`catalog_product_flat_1`
INNER JOIN `ac_magento_gold`.`catalog_product_entity`
ON (`catalog_product_flat_1`.`entity_id` = `catalog_product_entity`.`entity_id`) AND (`catalog_product_entity`.`sku` = `catalog_product_flat_1`.`sku`) AND (`catalog_product_flat_1`.`sku` NOT REGEXP '(SZ|SIZE|GIFT)')
INNER JOIN `ac_magento_gold`.`catalog_product_entity_text`
ON (`catalog_product_entity_text`.`entity_id` = `catalog_product_entity`.`entity_id`) AND (`catalog_product_entity_text`.`attribute_id`= 61)
INNER JOIN `ac_magento_gold`.`cataloginventory_stock_item`
ON (`cataloginventory_stock_item`.`product_id` = `catalog_product_entity`.`entity_id`) AND (`cataloginventory_stock_item`.`product_id` = `catalog_product_flat_1`.`entity_id`) AND (`catalog_product_entity_text`.`entity_id` = `cataloginventory_stock_item`.`product_id`) AND (`cataloginventory_stock_item`.is_in_stock = 1) LIMIT 6;
If you have multiple websites or stores (or even stock_id), that could be the reason you are getting duplicates. You need to specify the relevant store_id or website_id or stock_id in your joins.
For example,
INNER JOIN `ac_magento_gold`.`catalog_product_entity_text`
ON (`catalog_product_entity_text`.`entity_id` = `catalog_product_entity`.`entity_id`)
AND (`catalog_product_entity_text`.`attribute_id`= 61)
should be
INNER JOIN `ac_magento_gold`.`catalog_product_entity_text`
ON (`catalog_product_entity_text`.`entity_id` = `catalog_product_entity`.`entity_id`)
AND (`catalog_product_entity_text`.`attribute_id`= 61)
AND `catalog_product_entity_text`.`store_id` = 0
or whatever your store_id is. Actually, the query makes even more sense (to me at least) with the parentheses rearranged like so:
INNER JOIN `ac_magento_gold`.`catalog_product_entity_text`
ON (
`catalog_product_entity_text`.`entity_id` = `catalog_product_entity`.`entity_id`
AND `catalog_product_entity_text`.`attribute_id`= 61
AND `catalog_product_entity_text``.store_id` = 0
)
You might also have to rewrite the following:
INNER JOIN `ac_magento_gold`.`cataloginventory_stock_item`
ON (`cataloginventory_stock_item`.`product_id` = `catalog_product_entity`.`entity_id`)
AND (`cataloginventory_stock_item`.`product_id` = `catalog_product_flat_1`.`entity_id`)
AND (`catalog_product_entity_text`.`entity_id` = `cataloginventory_stock_item`.`product_id`)
AND (`cataloginventory_stock_item`.is_in_stock = 1)
to:
INNER JOIN `ac_magento_gold`.`cataloginventory_stock_item`
ON (`cataloginventory_stock_item`.`product_id` = `catalog_product_entity`.`entity_id`
AND `cataloginventory_stock_item`.`product_id` = `catalog_product_flat_1`.`entity_id`
AND `catalog_product_entity_text`.`entity_id` = `cataloginventory_stock_item`.`product_id`
AND `cataloginventory_stock_item`.is_in_stock = 1
AND `cataloginventory_stock_item`.`stock_id` = 1)
again, depending on which stock_id you are interested in. As far as I know, catalog_product_entity only contains one of each entity_id, so no website_id, store_id, or stock_id has to be specified. I also believe that catalog_product_flat_1 is specific to one store_id or website_id or something, but I am not sure.

SQL calculating time between assignments

I have to write an SQL statement which contain a field that contain two different values consecutively but in the way I have wrote it, it return always null because it is interpreted as having the two value in the same time!
My conditions should be : (ci.field = 'Group' and ci.oldString = 'Triage' ) and (ci.field='assignee' and ci.newString is not NULL)
That means calculate time between: when the issue is assigned to group named Triage and when the issue is assigned to a person.
How can I fix it?
My SQL statement:
select TIMEDIFF(a.created,b.created)
from
(select g.created, g.issueid as groupid1
from changegroup g
join changeitem ci on (ci.groupid = g.id)
join jiraissue ji on (ji.id = g.issueid)
join project p on (p.id = ji.project)
join priority pr on (pr.id = ji.priority)
where ci.field = 'Group'
and ci.oldString = 'Triage'
and ci.field='assignee'
and ci.newString is not NULL
and p.pname = 'Test'
and pr.pname='P1'
and ji.created between '2011-08-11 14:01:00' and '2011-08-12 14:11:00'
) a
left join (
select ji.created, ji.id as groupid2
from jiraissue ji
join changegroup g on (g.issueid = ji.id)
join project p on (p.id = ji.project)
where p.pname = 'Test'
and ji.created between '2011-08-11 14:01:00' and '2011-08-12 14:11:00'
) b ON (a.groupid1 = b.groupid2);
This is the table from which I should retrieve data
See my comment about the quality of your question but a hint at how to solve this goes like (assuming you can make sure this doesn't create 1-n joins)
select groupid_orsomething_else, TIMEDIFF(a.created, b.created)
from yourtable
left join
(select groupid_orsomething_else, created
from yourtable
where field = 'Group' and oldstring is 'Triage'
) a
on a.groupid_orsomething_else = yourtable.groupid_orsomething_else
left join
(select groupid_orsomething_else, created
from yourtable
where field = 'assignee' and oldstring is null) b
on b.groupid_orsomething_else = yourtable.groupid_orsomething_else