alternative syntax using join - mysql

I have this query which works fine.
I need the rows where the subcategory belongs to the company
OR
The company has access to default subcategories (c.plannerdefaults =1 )and the subcategory is a default subcategory (s.company =0)
SELECT distinct
s.category from planner_subcat s, company c
where
(
c.id = 66
and c.plannerdefaults = 1
and s.company = 0
)
or s.company = 66
The thing is, and maybe my thinking is wrong here, I got the impression that if a query starts with
select col from table1, table2
then there is something wrong with the methodology, but in this case I could not think of an alternative using a join.
Is there one?

I would write the query this way:
SELECT s.category
FROM company c
JOIN planner_subcat s
ON c.id = s.company OR (c.plannerdefaults = 1 AND s.company = 0)
WHERE c.id = 66;

I am not sure what is your goal here.
Why do you want to re-write the query, are you seeing performance issues?
If you are looking for alternative syntax.
Here is one syntax using sub-query. This query could be a little faster and it will reduce the row locks if the tables are huge (not sure you will have to test it) also id this relation 1 planner-to-many companies then you don't need the DISTINCT function unless it is a different relation then add it back
SELECT s.category
FROM planner_subcat AS s
WHERE s.company IN(66,0) AND (
s.company = 66 OR EXISTS (SELECT 1 FROM company AS c WHERE id = 66 AND plannerdefaults = 1 AND s.company = 0 AND company = s.company )
)
if you simply want the query to have a newer syntax only then try this
SELECT DISTINCT s.category
FROM planner_subcat AS s
INNER JOIN company AS c ON c.company = s.company
WHERE s.company IN(0,66) AND ( s.company = 66 OR ( c.id = 66 AND c.plannerdefaults = 1 AND s.company = 0 ) )
But I think my first query will be better in your case since you would not need to use DISTINCT any more. I would think MySQL will not execute the sub query every time unless company = 0 since the company = 66 condition will satisfy the condition then is no reason to do more checking.

Related

Query is neglecting one of where clause, any idea why it is happening?

I have two tables, activity and users. I am trying to fetch data by using multiple where clauses.
SELECT SUM(activity.step_points) AS s_points
, `activity`.`user_id`
, `users`.`id`
, `users`.`app_id`
, `users`.`country_id`
FROM `activity`
LEFT JOIN `users` ON `users`.`id` = `activity`.`user_id`
WHERE `users`.`is_active` = 1 AND
`users`.`is_test_account` = 0 AND
`users`.`app_id` = 3 AND
`users`.`country_id` = 1 AND
`users`.`phone` NOT LIKE "%000000%" OR
`users`.`phone` IS NULL AND
`users`.`is_subscribed` = 1 AND
(`users`.`email` NOT LIKE "%#mycompanyname.net" OR
`users`.`email` IS NULL) AND
YEAR(`activity`.`created_at`) = "2021" AND
MONTH(`activity`.`created_at`) = "06"
GROUP BY `activity`.`user_id`
ORDER BY `s_points` DESC LIMIT 100 OFFSET 0
But I think users.country_id = 1 is getting neglected. You can see I want only rows that belong to country id 1. But I am getting country id 2, 3 too.
Why is it happening?
You need to properly use parentheses in the WHERE clause so the OR does not dominate over the ANDs:
SELECT . . .
FROM activity a JOIN
users u
ON u.id = a.id
WHERE u.is_active = 1 AND
u.is_test_account = 0 AND
u.app_id = 3 AND
u.country_id = 1 AND
(u.phone NOT LIKE '%000000%' OR u.phone IS NULL) AND
u.is_subscribed = 1 AND
(u.email NOT LIKE '%#mycompanyname.net OR u.email IS NULL) AND
(a.created_at >= '2021-01-01' AND a.created_at < '2022-01-01'
Note the other changes to the code:
You are filtering on both tables, so an outer join is not appropriate. The WHERE clause turns it into an inner join anyway.
Table aliases make the code easier to write and to read.
All the backticks just make the code harder to write and read and are not needed.
SQL's standard delimiter for strings is single quotes. Use them unless you have a good reason for preferring double quotes.
For date comparisons, it can be faster to avoid functions, hence the change for the year comparison. This helps the optimizer.

Query gets very slows if i add a where

SELECT a.emp_id,s.name, s.department,s.register, z.Compoff_Count as Extra, ifnull(COUNT(DISTINCT TO_DAYS(a.punchdate)),0) as Monthly_Count
FROM machinedata a left join
(SELECT a.emp_id, ifnull(COUNT(DISTINCT TO_DAYS(a.punchdate)),0) as Compoff_Count
FROM machinedata a
RIght JOIN time_dimension c on c.db_date = a.punchdate
where ( year(c.db_date) = 2016 and month(c.db_date) = 8 and (c.holiday_flag = 't' or c.weekend_flag ='t' ))
GROUP BY a.emp_id) Z
on z.emp_id = a.emp_id
RIght JOIN time_dimension c on c.db_date = a.punchdate
left join emp s on s.emp_id = a.emp_id
where (year(c.db_date) = 2016 and month(c.db_date) = 8 and c.holiday_flag = 'f' and c.weekend_flag ='f' )
GROUP BY emp_id
The above query works fine.. but if i add s.department='yes' in the last where the query takes more than 40 seconds.
What shall i do to improve the query performance ?
Your initial query can be simplified I believe by using "conditional aggregates" which places case expressions inside the count() function. This avoids repeated sans of data and unnecessary joins to derived tables.
You should also avoid using functions on data to suit where clause conditions i.e. Instead of YEAR() and MONTH() simply use date boundaries. This allows an index on the date column to be used in the query execution.
I'm not sure if you really need to use TO_DAYS() but I suspect it isn't needed either.
SELECT
a.emp_id
, s.name
, s.department
, s.register
, COUNT(DISTINCT CASE WHEN (c.holiday_flag = 't' OR
c.weekend_flag = 't') THEN c.db_date END) AS Compoff_Count
, COUNT(DISTINCT CASE WHEN NOT (c.holiday_flag = 't' OR
c.weekend_flag = 't') THEN a.punchdate END) AS Monthly_Count
FROM time_dimension c
LEFT JOIN machinedata a ON c.db_date = a.punchdate
LEFT JOIN emp s ON a.emp_id = s.emp_id
WHERE c.db_date >= '2016-08-01'
AND c.db_date < '2016-09-01'
GROUP BY
a.emp_id
, s.name
, s.department
, s.register
If this re-write produces correct results then you could try adding and s.department='yes' into the where clause to assess the impact. If it is still substantially slower then get an explain plan and add it to the question. The most likley cause of slowness is lack of an index but without an explain plan it's not possible to be certain.
Please note that this suggestion is just that; and is prepared without sample data and expected results.

optimize sql select with many Joins

How can I optimize this mysql statement?
SELECT DISTINCT p.name
FROM Something_Meta s1
JOIN Something_Meta s2 ON s1.fk_somethingId = s2.fk_somethingId
JOIN Products p ON s2.fk_productId = p.id
JOIN
(
select fk_id from Restricted where fk_foo != 233 and fk_id NOT IN
(
Select fk_id from Restricted where fk_foo = 233
)
)
r ON r.fk_id = p.id
WHERE s1.fk_somethingId = 63 AND s2.fk_somethingId <> s1.fk_somethingId
order by p.name ASC
My tables are like that
Product (id,name )
Restricted (id,fk_id,fk_foo )
Something_Meta (id,fk_id,fk_somethingId )
fk_id is foreign key to product (id)
Probably that sql statement needs optimization..
select fk_id from Restricted where fk_foo != 233 and fk_id NOT IN
(
Select fk_id from Restricted where fk_foo = 233
)
The whole query statement needs more than 1.5 sec to run which are many secs for a website for a single query.
You could try an index on (fk_foo, fk_id) which would cover your entire query:
create index ix_restricted_fk_foo_fk_id(fk_foo, fk_id) on restricted
First off : the DISTINCT is a bit of a red flag. If you need to filter out the doubles then there's probably an error somewhere (either in the query or the design) causing the doubles.
Second; you could write your query like this:
SELECT DISTINCT p.name
FROM Something_Meta s1
JOIN Something_Meta s2 ON s1.fk_somethingId = s2.fk_somethingId
JOIN Products p ON s2.fk_productId = p.id
WHERE s1.fk_somethingId = 63 AND s2.fk_somethingId <> s1.fk_somethingId
AND NOT EXISTS ( SELECT *
FROM Restricted r
WHERE r.fk_foo != 233
AND r.fk_id = p.id )
AND EXISTS ( SELECT *
FROM Restricted r2
WHERE r2.fk_foo = 233
AND r2.fk_id = p.id )
order by p.name ASC
As I don't have a clue about the Something_Meta tables I'll simply focus on the Restricted table and suggest you put an index on fk_foo and fk_id. Said index is NOT part of the query, but rather of the table, so you have to define it upfront, once.
CREATE INDEX idx_Restricted ON Restricted (fk_id, fk_foo)
Once the index is there; any query that might benefit from it will automagically use it in the background; no need for you to adapt the query for it.
Side-note; since you obviously are looking for the product I find it curious you don't 'focus' your query on Products.
SELECT p.name
FROM Products p
JOIN etc...

How to optimize this complected query?

While working with following query on mysql, Its getting locked,
SELECT event_list.*
FROM event_list
INNER JOIN members
ON members.profilenam=event_list.even_loc
WHERE (even_own IN (SELECT frd_id
FROM network
WHERE mem_id='911'
GROUP BY frd_id)
OR even_own = '911' )
AND event_list.even_active = 'y'
GROUP BY event_list.even_id
ORDER BY event_list.even_stat ASC
The Inner query inside IN constraint has many frd_id, So because of that above query is slooow..., So please help.
Thanks.
Try this:
SELECT el.*
FROM event_list el
INNER JOIN members m ON m.profilenam = el.even_loc
WHERE el.even_active = 'y' AND
(el.even_own = 911 OR EXISTS (SELECT 1 FROM network n WHERE n.mem_id=911 AND n.frd_id = el.even_own))
GROUP BY el.even_id
ORDER BY el.even_stat ASC
You don't need the GROUP BY on the inner query, that will be making the database engine do a lot of unneeded work.
If you put even_own = '911' before the select from network, then if even_own IS 911 then it will not have to do the subquery.
Also why do you have a group by on the subquery?
Also run explain plan top find out what is taking the time.
This might work better:
( SELECT e.*
FROM event_list AS e
INNER JOIN members AS m ON m.profilenam = e.even_loc
JOIN network AS n ON e.even_own = n.frd_id
WHERE n.mem_id = '911'
AND e.even_active = 'y'
ORDER BY e.even_stat ASC )
UNION DISTINCT
( SELECT e.*
FROM event_list AS e
INNER JOIN members AS m ON m.profilenam = e.even_loc
WHERE e.even_own = '911'
AND e.even_active = 'y' )
ORDER BY e.even_stat ASC
Since I don't know whether the JOINs one-to-many (or what), I threw in DISTINCT to avoid dups. There may be a better way, or it may be unnecessary (that is, UNION ALL).
Notice how I avoid two things that are performance killers:
OR -- turned into UNION
IN (SELECT...) -- turned into JOIN.
I made aliases to cut down on the clutter. I moved the ORDER BY outside the UNION (and added parens to make it work right).

MAX() Function not working as expected

I've created sqlfiddle to try and get my head around this http://sqlfiddle.com/#!2/21e72/1
In the query, I have put a max() on the compiled_date column but the recommendation column is still coming through incorrect - I'm assuming that a select statement will need to be inserted on line 3 somehow?
I've tried the examples provided by the commenters below but I think I just need to understand this from a basic query to begin with.
As others have pointed out, the issue is that some of the select columns are neither aggregated nor used in the group by clause. Most DBMSs won't allow this at all, but MySQL is a little relaxed on some of the standards...
So, you need to first find the max(compiled_date) for each case, then find the recommendation that goes with it.
select r.case_number, r.compiled_date, r.recommendation
from reporting r
join (
SELECT case_number, max(compiled_date) as lastDate
from reporting
group by case_number
) s on r.case_number=s.case_number
and r.compiled_date=s.lastDate
Thank you for providing sqlFiddle. But only reporting data is given. we highly appreciate if you give us sample data of whole tables.
Anyway, Could you try this?
SELECT
`case`.number,
staff.staff_name AS ``case` owner`,
client.client_name,
`case`.address,
x.mx_date,
report.recommendation
FROM
`case` INNER JOIN (
SELECT case_number, MAX(compiled_date) as mx_date
FROM report
GROUP BY case_number
) x ON x.case_number = `case`.number
INNER JOIN report ON x.case_number = report.case_number AND report.compiled_date = x.mx_date
INNER JOIN client ON `case`.client_number = client.client_number
INNER JOIN staff ON `case`.staff_number = staff.staff_number
WHERE
`case`.active = 1
AND staff.staff_name = 'bob'
ORDER BY
`case`.number ASC;
Check below query:
SELECT c.number, s.staff_name AS `case owner`, cl.client_name,
c.address, MAX(r.compiled_date), r.recommendation
FROM case c
INNER JOIN (SELECT r.case_number, r.compiled_date, r.recommendation
FROM report r ORDER BY r.case_number, r.compiled_date DESC
) r ON r.case_number = c.number
INNER JOIN client cl ON c.client_number = cl.client_number
INNER JOIN staff s ON c.staff_number = s.staff_number
WHERE c.active = 1 AND s.staff_name = 'bob'
GROUP BY c.number
ORDER BY c.number ASC
SELECT
case.number,
staff.staff_name AS `case owner`,
client.client_name,
case.address,
(select MAX(compiled_date)from report where case_number=case.number),
report.recommendation
FROM
case
INNER JOIN report ON report.case_number = case.number
INNER JOIN client ON case.client_number = client.client_number
INNER JOIN staff ON case.staff_number = staff.staff_number
WHERE
case.active = 1 AND
staff.staff_name = 'bob'
GROUP BY
case.number
ORDER BY
case.number ASC
try this