MYSQL Update a huge SQL query - mysql

In my system I want to get attendance data of employee from the DB, so I wrote a huge SQL query, and it gives me relevant details. But now I need an updated version of particular results. So I don’t know how to put this query within the update statement.
select * from(
select concat('pre:', date) as date,concat('pre:',employee_no) as employee_no,concat('pre:',name_with_initials) as name,concat('pre:',sign_in_at) as sign_in_at,concat('pre:',sign_out_at) as sign_out_at,emp from( SELECT date, present.employee_no,employee_details.name_with_initials,present.sign_in_at, present.sign_out_at,employee_details.employee_no as emp from (
SELECT employee_no,date,sign_in_at,sign_out_at FROM complete_shifts WHERE date = '2013-06-17' UNION ALL
SELECT employee_no,date,sign_in_at,'00:00:00 ' AS sign_out_at FROM incomplete_shifts WHERE date = '2013-06-17' UNION ALL
SELECT employee_no,date,sign_in_at,'00:00:00 ' AS sign_out_at FROM incomplete_shift_records WHERE date = '2013-06-17'
)as present inner join employee_details on present.employee_no = employee_details.employee_no
) as final_present
union all
select concat('ab:',date)as date,concat('ab:',employee_no)as employee_no,concat('ab:',name_with_initials)as name,concat('ab:',sign_in_at)as sign_in_at,concat('ab:',sign_out_at)as sign_out_at, emp from(
select '2013-06-17' AS date,absent.employee_no,employee_details.name_with_initials,'00:00:00'as sign_in_at , '00:00:00' as sign_out_at,employee_details.employee_no as emp from (
select * from ( SELECT employee_details.employee_no FROM employee_details left outer join resigned_emps on
employee_details.employee_no = resigned_emps.employee_no where resigned_emps.date is null or resigned_emps.date>'2013-06-17'
) as available_emps left outer join (
select employee_no from complete_shifts where date = '2013-06-17' union
select employee_no from incomplete_shifts where date = '2013-06-17' union
select employee_no from incomplete_shift_records where date = '2013-06-17'
) as present on available_emps.employee_no = present.employee_no where present.employee_no is null
) as absent inner join employee_details on absent.employee_no = employee_details.employee_no
) as final_absent
)as final left outer join( SELECT leave.employee_no as lv_emp
FROM leave_dates inner join leave on leave_dates.leave_id = leave.leave_id where leave_dates.date = '2013-06-17')as leave_emps
on final.emp = leave_emps.lv_emp;

With such a large query, you should just put the results in a temporary table and update from that.
create temporary table toupdate as
<your query goes here>;
Now you can investigate the data that will be updated, to be sure that it really is ok.
Next you can do the update as a join:
update table_to_update t join
toupdate
on t.key = toupdate.key
set t.col = toupdate.col
Because you don't give the column or table details, this is just the structure of such a solution.

Instead of "select *", use the appropriate unique field to fetch the records to update, ex EmpID. Finally use this result as inner query result to update query.
Example
Update ... set ... where empid in (your select query goes here)

Related

How can I optimize this MySQL query in a stored procedure?

SET #count := (SELECT count(*)
FROM dbo.ManyToManyTable SRSG
JOIN tableA SG on SRSG.a = SG.a
JOIN tableB SR on SRSG.b = SR.a
WHERE SR.c = INPUT_VALUE);
IF (#count > 0)
THEN
SELECT SG.fieldA, SG.fieldB
FROM dbo.ManyToManyTable SRSG
JOIN tableA SG on SRSG.a = SG.a
JOIN tableB SR on SRSG.b = SR.a
WHERE SR.c = INPUT_VALUE;
ELSE
SELECT SG.a, SG.b FROM dbo.tableA SG WHERE SG.b = "default value";
END IF;
It's for a MySQL database. This works for me, but I don't like the duplicate select query. However, I have no idea how to fix it under the constraint which is the logic has be within one stored procedure.
You could write this as a single query:
with cte as (
SELECT SG.fieldA, SG.fieldB
FROM dbo.ManyToManyTable SRSG JOIN
tableA SG
on SRSG.salesGroupId = SG.salesGroupId JOIN
tableB SR
on SRSG.salesRegionId = SR.salesRegionId
WHERE SR.AField = INPUT_VALUE
)
select *
from cte
union all
select SG.a, SG.b
from dbo.tableA SG
where SG.b = 'default value' and
not exists (select 1 from cte);
MySQL tends to materialize CTEs (always?), so this should run the query once rather than twice.
A quick, but partial speedup is to replace
SET #count = ( SELECT COUNT(*) ... );
IF (#count > 0)
with this (using the rest of that initial SELECT):
IF ( EXISTS ( SELECT 1 FROM ... ) )
Also for performance, be sure to have in SRSG:
PRIMARY KEY(a,b)
INDEX(b,a)
and don't bother with an AUTO_INCREMENT.

Mysql where if condition

Basically I have a table all customer will have a default row with customer_group_id=0
But some of this customer will belong to customer_group_id=1
When that happen a new row is created for customer with customer_group_id=1 therefore now I have 2 rows for same customer but different customer_group_id.
Now when I fetch the data I need first to select * from customer table where customer_group_id =1 but if doesn't exist give me then with customer_group_id = 0 which is the default, and continue until it returns all data.
Anyone know the best way to achieve this fast?
UPDATE: screen shoot show 2 rows with same customer_id different customer_group_id:
I need to one or the other no both so hierarchy is: if customer_group_id=1 exist then return that row and ignore the ohter otherwise return default which is customer_group_id=0
My full query:
SELECT `main_table`.*, `secondTable`.* FROM `customer` AS `main_table`
LEFT JOIN `customer_group` AS `secondTable` ON main_table.customer_id = secondTable.customer_id
WHERE (secondTable.customer_group_id = '1' )
AND (`secondTable`.`is_active` = '1')
If you have only two groups, then aggregation is simple:
select customer_id, max(customer_group_id)
from t
group by customer_id;
In MySQL 8+, you can implement a more customer prioritization using row_number():
select t.*
from (select t.*,
row_number() over (partition by customer_id order by customer_group_id desc) as seqnum
from t
) t
where seqnum = 1;
What you can do is fetch all the rows for the customers with customer_group_id=1 and then use UNION ALL to fetch the rows of the customers that do not have any row with customer_group_id=1 by using NOT EXISTS:
select * from tablename
where customer_group_id=1
union all
select * from tablename t
where t.customer_group_id=0
and not exists (
select 1 from tablename
where customer_id = t.customer_id and customer_group_id=1
)
For the rows with customer_group_id = 0 verify that there are no rows with customer_group_id = 1 for the same customer_id. You can use a NOT EXISTS subquery:
SELECT c.*, g.*
FROM customer AS c
JOIN customer_group AS g ON c.customer_id = g.customer_id
WHERE NOT EXISTS (
SELECT *
FROM customer_group AS g2
WHERE g2.customer_id = c.customer_id
AND g2.customer_group_id = 1
AND g.customer_group_id = 0
)

insert into table(var1) select from itself

I want to insert into the last column (number of people in that room) and
I want to use
insert into table(n_people_in_room)
select count(people_id)
from table
group by room
This is obvious wrong because i need to join the table with itself on people_id but i didn't. What is the right code?
Here's one way to do it, using an inline view to get the N_People_In_Room totals:
I'd do it as a SELECT first:
SELECT t.peopleid
, t.room
, t.n_people_in_room AS `old_npir`
, s.n_people_in_room AS `new_npir`
FROM mytable t
JOIN ( SELECT c.room
, COUNT(1) AS n_people_in_room
FROM mytable c
GROUP BY c.room
) s
ON s.room = t.room
Convert that into an UPDATE by repacing SELECT ... FROM with UPDATE, and adding a SET clause...
UPDATE mytable t
JOIN ( SELECT c.room
, COUNT(1) AS n_people_in_room
FROM mytable c
GROUP BY c.room
) s
ON s.room = t.room
SET t.n_people_in_room = s.n_people_in_room

Count distinct values with SELECT query results with error

I have a weird situation. I need to select all data from table name with distinct values from other table.
Here is database scheme of database that I need to get distinct values:
When I run both queries without INNER JOIN they run without error but when I use INNER JOIN I got error
This is query that I used:
SELECT * FROM `todo`
INNER JOIN
SELECT `task`.`status`,COUNT(*) as count FROM `task`
ON `todo`.`id`=`task`.`id_list` WHERE `todo`.`user_id` = 43
As you can see I need to get total count of status column from other table. Can it be done using one single query or do I need to run two querys to get data...
You need to wrap the join In parenthesis
SELECT td.*, t.*
FROM `todo` td
JOIN
( SELECT `status`, SUM(status=0) as status_0, SUM(status=1) as status_1 , id_list
FROM `task`
GROUP BY id_list
) t ON td.id= t.id_list
WHERE td.user_id = 43
You can do this in one query. Even without a subquery:
SELECT ta.status, COUNT(*) as count
FROM todo t INNER JOIN
task ta
ON t.id = ta.id_list
WHERE t.user_id = 43
GROUP BY ta.status;
EDIT:
If the above produces what you want, then you probably need:
SELECT t.*, ta.status, taa.cnt
FROM todo t INNER JOIN
task ta
ON t.id = ta.id_list INNER JOIN
(SELECT count(*) as cnt, ta.status
FROM task ta
GROUP BY ta.status
) taa
on ta.status = taa.status
WHERE t.user_id = 43 ;
You seem to want a summary at the status level, which is only in task. But you want the information at the row level for todo.

Combining multiple cte

Is it possible to combine a result of two cte to another cte. I wrote a query combining two cte. The result gave a three column data in which I want to group the third column and averaging the second column. The second column resulted from a case sum statement.
If you are asking whether you can re-use CTEs after they have been used in a query, the answer is no. You can't do this:
with A
as (
-- query
)
select A.*
from A;
-- this is a separate query
select id
, count(*)
from A
group by
id
You can, however, combine CTEs in all kinds of ways, as long as you do it in a single statement. You can do this, which uses the hypothetical CTE A in two CTEs and the final query:
with A
as (
-- some query
)
, ACustomers
as (
select *
from Customers
join A
on ....
)
, AVendors
as (
select *
from Vendors
join A
on ....
)
select A.StateId
, ACount = COUNT(*)
, CustomerCount = (select count(*) from ACustomers ac where ac.StateId = A.StateId )
, VendorCount = (select count(*) from AVendors av where av.StateId = A.StateId )
from A
group by
A.StateId