MySQL SELECT AS - mysql

Is there a way out to achieve something as below?
The below query is only to convey the intention. I do understand that it is syntactically incorrect.
SELECT
T_DATE,
T_NAME,
(SELECT MAX(DUR) WHERE STATUS = 'Y') AS UPD_MAX,
(SELECT AVG(DUR) WHERE STATUS = 'Y') AS UPD_AVG,
(SELECT MAX(DUR) WHERE STATUS = 'N') AS READ_MAX,
(SELECT AVG(DUR) WHERE STATUS = 'N') AS READ_AVG
FROM
TABLE_1
WHERE
T_NAME LIKE 'ab%cd%'
GROUP BY
T_DATE,
T_NAME

Use conditional aggregation:
SELECT T_DATE, T_NAME,
MAX(CASE WHEN STATUS = 'Y' THEN DUR END) AS UPD_MAX,
AVG(CASE WHEN STATUS = 'Y' THEN DUR END) AS UPD_AVG,
MAX(CASE WHEN STATUS = 'N' THEN DUR END) AS READ_MAX,
AVG(CASE WHEN STATUS = 'N' THEN DUR END) AS READ_AVG
FROM TABLE_1
WHERE T_NAME LIKE 'ab%cd%'
GROUP BY T_DATE, T_NAME;

try something like that:
SELECT
T_DATE,
T_NAME,
a.UPD_MAX,
c.UPD_AVG,
b.READ_MAX,
d.READ_AVG
FROM TABLE_1
INNER JOIN (SELECT T_NAME, MAX(DUR) AS UPD_MAX FROM TABLE_1 WHERE STATUS = 'Y' GROUP BY T_NAME) as a ON T_NAME=a.T_NAME
INNER JOIN (SELECT T_NAME, MAX(DUR) AS READ_MAX FROM TABLE_1 WHERE STATUS = 'N' GROUP BY T_NAME) as b ON T_NAME=b.T_NAME
INNER JOIN (SELECT T_NAME, AVG(DUR) AS UPD_AVG FROM TABLE_1 WHERE STATUS = 'Y' GROUP BY T_NAME) as c ON T_NAME=c.T_NAME
INNER JOIN (SELECT T_NAME, AVG(DUR) AS READ_AVG FROM TABLE_1 WHERE STATUS = 'N' GROUP BY T_NAME) as d ON T_NAME=d.T_NAME
WHERE T_NAME LIKE 'ab%cd%'
GROUP BY
T_DATE,
T_NAME

Related

Query optimization needed because of too many sub queries and sub query dependency in where conditions

I'm writing code for the production report.
I had written this query
SELECT
P.*,
(
SELECT
COUNT(id) AS cnt
FROM
bales
WHERE
create_date < '2019-11-01' AND product_id = P.id AND(TYPE = 'bale' OR TYPE = 'bag')
) AS before_prod,
(
SELECT
COUNT(id) AS cnt
FROM
bales
WHERE
(
dispatched = '0' OR disp_bunch = '0'
) AND dispatch_date < '2019-11-01' AND product_id = P.id AND(TYPE = 'bale' OR TYPE = 'bag')
) AS before_dispatched,
(
SELECT
COUNT(id) AS cnt
FROM
bales
WHERE
create_date BETWEEN '2019-11-01' AND '2019-11-06' AND product_id = P.id AND(TYPE = 'bale' OR TYPE = 'bag')
) AS production,
(
SELECT
COUNT(id) AS cnt
FROM
bales
WHERE
(
dispatched = '0' OR disp_bunch = '0'
) AND dispatch_date BETWEEN '2019-11-01' AND '2019-11-06' AND product_id = P.id AND(TYPE = 'bale' OR TYPE = 'bag')
) AS production_dispatched,
C.name AS category_name
FROM
products P
INNER JOIN category C ON
C.id = P.category
This query is working but as I have too many records in all tables it takes too much time.
also, I need only records where before_prod, before_dispatched, production, production_dispatched all these subquery results should be greater than 0.
I tried to use having clause but it also takes too much time.
I have also tried php for loop, * LOGIC: first all products than in for loop its production. but it was much slower.*
How can I optimize my query?
You can use join instead and select case to sum your data that matches your conditions.
select p.*, t.*
from products p
inner join (
select t2.id, sum(case when create_date < '2019-11-01' then 1 else 0 end) as before_prod
, sum(case when (dispatched = '0' or disp_bunch = '0') and create_date < '2019-11-01' then 1 else 0 end) as before_dispatched
, sum(case when create_date between '2019-11-01' and '2019-11-06' then 1 else 0 end) as production
, sum(case when (dispatched = '0' or disp_bunch = '0') and create_date between '2019-11-01' and '2019-11-06' then 1 else 0 end) as production_dispatched
from bales t1
inner join product t2 on t2.id= t1.product_id
inner join category t3 on t3.id = t2.category
where t1.TYPE in ('bale', 'bag')
group by t2.id) t
on t.id = p.id

MySQL select query, adding max value from another table

Trying to add another column with a new table, would appreciate any help/suggestions!
Current query:
SELECT parent.name AS parentname, a.name AS accname,
parent.code AS parentcode, a.code AS acccode,
parent.guid AS parentguid, a.guid AS accguid,
a.account_type AS accttype,
sum(case when date_format(post_date, '%Y-%m-%d') <= '2017-12-31' then (s.value_num/s.value_denom) else '0' end) AS 'value2017-12-31',
sum(case when date_format(post_date, '%Y-%m-%d') <= '2018-01-25' then (s.value_num/s.value_denom) else '0' end) AS 'value2018-01-25'
FROM transactions AS t INNER JOIN splits AS s ON s.tx_guid = t.guid
INNER JOIN accounts AS a ON a.guid = s.account_guid
INNER JOIN accounts AS parent ON parent.guid = a.parent_guid
WHERE a.hidden = 0 AND a.account_type NOT IN ('INCOME', 'EXPENSE')
AND parent.name <>''
AND a.guid = '3f3fc442a98225f481bb72e0fd526cbb'
GROUP by accname, parentname ORDER by acccode
And that works fine, gives 1 row of results. I'd now like to add another column to the results, I believe a left outer join from the prices table of the record that is the closest date before 2017-12-31. My attempt:
SELECT parent.name AS parentname, a.name AS accname,
parent.code AS parentcode, a.code AS acccode,
parent.guid AS parentguid, a.guid AS accguid,
a.account_type AS accttype,
sum(case when date_format(post_date, '%Y-%m-%d') <= '2017-12-31' then (s.value_num/s.value_denom) else '0' end) AS 'value2017-12-31',
sum(case when date_format(post_date, '%Y-%m-%d') <= '2018-01-25' then (s.value_num/s.value_denom) else '0' end) AS 'value2018-01-25',
MAX(case when date_format(p.date, '%Y-%m-%d') <= '2017-12-31' then (p.value_num/p.value_denom) else '0' end) AS 'price2017-12-31'
FROM transactions AS t INNER JOIN splits AS s ON s.tx_guid = t.guid
INNER JOIN accounts AS a ON a.guid = s.account_guid
INNER JOIN accounts AS parent ON parent.guid = a.parent_guid
LEFT OUTER JOIN prices as p ON p.commodity_guid = a.commodity_guid
WHERE a.hidden = 0 AND a.account_type NOT IN ('INCOME', 'EXPENSE')
AND parent.name <>''
AND a.guid = '3f3fc442a98225f481bb72e0fd526cbb'
GROUP by accname, parentname ORDER by acccode
It's obviously incorrect as it's now changing the values of value2017-12-31 and value2018-01-25. I get the price correctly using a separate query:
SELECT p.value_num/p.value_denom as calcprice
FROM `prices` as p
WHERE commodity_guid = '77be249d12d9889e90f08dde7c671eb0'
AND date_format(p.date, '%Y-%m-%d') <= '2017-12-31'
order
by date DESC
limit 1
Is there any way to combine them rather than using temp tables?

get record in sql

I have a table with the following fields:
SELECT `sms_id`,
`u_id`,
`sender_id`,
`mobile_no`,
`message`,
`campaign_name`,
`status`,
`request_id`,
`route_id`,
`totalnumber`,
`msgcreadit`,
`date1`,
`deductbal`,
`submited`
FROM `send_sms`
WHERE 1
I want to select u_id whose status ="pending", but I want the latest pending status according to the [date1] date field and I also want the count of individual u_ids with status ="pending".
How can I do it?
In MySQL you can do:
SELECT s.*
FROM `send_sms` s
WHERE s.status = 'pending' AND
s.date1 = (SELECT MAX(s2.date1) FROM send_sms s2 WHERE s2.u_id = s.u_id and s2.status = 'pending');
Just another approach:
SELECT s.*
FROM `send_sms` s
LEFT JOIN `send_sms` s2
ON s.date1 < s2.date1
AND s2.u_id = s.u_id
AND s2.status = 'pending'
WHERE s.status = 'pending'
AND s2.status IS NULL

MYSQL- Help making a query

Solved! Thanks for all the help!
How do I fix this query
So the Pet's table's fields are
Pet_Code,Name,Employee_code,Type,Sex
And the Employees table's fields are
Employee_code,Last_Name,First_Name,Department
This is what I tried but didn't work:
SELECT First_Name,Last_Name
FROM employees E,pets P
WHERE P.Employee_code=E.Employee_code AND COUNT(Type='C') > Count(Type='D');
Ok you can try this:
SELECT DISTINCT
E.Employee_code, E.Last_Name, E.Department,
(SELECT COUNT(*) FROM pet WHERE Employee_code = E.Employee_code AND Type = 'C') AS cats,
(SELECT COUNT(*) FROM pet WHERE Employee_code = E.Employee_code AND Type = 'D') AS dogs
FROM employee E
LEFT JOIN pet P ON E.Employee_code = P.Employee_code
GROUP BY E.Employee_code
HAVING cats > dogs
it is like previous one, But more simply
I think you could try this:
SELECT
Employee_code,
Last_Name,
First_Name,
SUM(CASE WHEN Type = 'C' THEN 1 ELSE 0 END) AS CAT,
SUM(CASE WHEN Type = 'D' THEN 1 ELSE 0 END) AS DOG
FROM Employees_TABLE E
JOIN PET_TABLE P ON E.Employee_code = P.Employee_code
GROUP BY Employee_code
HAVING SUM(CASE WHEN Type = 'C' THEN 1 ELSE 0 END) > SUM(CASE WHEN Type = 'D' THEN 1 ELSE 0 END)
Maybe you can try with this:
SELECT e.First_Name, e.Last_Name
FROM employees e INNER JOIN pets p ON e.Employee_code = p.Employee_code
WHERE
(SELECT COUNT(*)
FROM pets p1
WHERE p1.Type = 'C' AND p.Employee_code = p1.Employee_code) >
(SELECT COUNT(*)
FROM pets p1
WHERE p1.Type = 'D' AND p.Employee_code = p1.Employee_code)
GROUP BY e.Employee_code;
It might not be an optimal solution, but should do the job.
select min(e.First_Name), min(e.Last_Name)
from emp e left outer join pets p
on p.Employee_Code = e.Employee_Code
group by e.Employee_Code
having
count(case when Type = 'C' then 1 end) >
count(case when Type = 'D' then 1 end)

Is it possible for a query that use a subquery to return multiple rows?

SELECT p.value AS __color__,
milestone AS __group__,
milestone,
priority,
time AS created,
COUNT(t.id) as 'total open tickets',
SUM(c.value) as 'Total Dev LOE',
SUM(d.value) as 'Total QALOE'
FROM ticket t
LEFT JOIN ticket_custom c ON (t.id = c.ticket AND c.name = 'devloe')
LEFT JOIN ticket_custom d ON (t.id = d.ticket AND d.name = 'qaloe')
LEFT JOIN enum p ON p.name = t.priority AND p.type = 'priority'
WHERE t.milestone = '$MILESTONE'
AND status <> 'closed'
GROUP BY milestone, priority, DATE(FROM_UNIXTIME(time/1000000)) DESC
Then add subquery to return the sum total devloe and qaloe for each priority.
Select p.value AS __color__
, milestone AS __group__
, milestone
, priority
, time AS created
, Count(t.id) as 'total open tickets'
, Sum( Case When c.name = 'devloe' Then c.value End ) As 'Total Dev LOE'
, Sum( Case When c.name = 'qaloe' Then c.value End ) As 'Total QALOE'
, PriorityCounts.Total_Dev_LOE As Priority_Total_QALOE
, PriorityCounts.Total_QALOE As Priority_Total_QALOE
From ticket As t
Left Join ticket_custom As c
On t.id = c.ticket
And c.name In('devloe', 'qaloe')
Left Join enum p
On p.name = t.priority
AND p.type = 'priority'
Join (
Select t1.priority,
, Sum( Case When c1.name = 'devloe' Then c1.value End ) As Total_Dev_LOE
, Sum( Case When c1.name = 'qaloe' Then c1.value End ) As Total_QALOE
From ticket As t1
Left Join ticket_custom As c1
On t1.id = c1.ticket
And c1.name In('devloe', 'qaloe')
Group By t1.priority
) As PriorityCounts
On PriorityCounts.priority = t.priority
Where t.milestone = '$MILESTONE'
And status <> 'closed'
Group By milestone, priority, DATE(FROM_UNIXTIME(time/1000000)) DESC
Doesn't answer your question, but you could simplify the query:
SELECT p.value AS __color__,
milestone AS __group__,
milestone,
priority,
time AS created,
COUNT(t.id) as 'total open tickets',
SUM(CASE WHEN c.name = 'devloe' THEN c.value ELSE 0 END) as 'Total Dev LOE',
SUM(CASE WHEN c.name = 'qaloe' THEN c.value ELSE 0 END) as 'Total QALOE'
FROM TICKET t
LEFT JOIN TICKET_CUSTOM c ON c.ticket = t.id
AND c.name IN ('devloe', 'qaloe')
LEFT JOIN ENUM p ON p.name = t.priority
AND p.type = 'priority'
WHERE t.milestone = '$MILESTONE'
AND status <> 'closed'
GROUP BY milestone, priority, DATE(FROM_UNIXTIME(time/1000000)) DESC