MySQL SELECT query with another SELECT - mysql

I have the next sql query:
SELECT CONCAT(v.p_sery, v.p_id) AS sery,
(SELECT COUNT(1) FROM v where p_delivery_result = 1) AS delivery_count,
(SELECT COUNT(1) FROM v where p_delivery_result = 2) AS ND1,
(SELECT COUNT(1) FROM v where p_delivery_result = 3) AS ND2,
(SELECT COUNT(1) FROM v where p_delivery_result = 4) AS ND3,
(SELECT COUNT(1) FROM v where p_delivery_result = 5) AS ND4,
(SELECT COUNT(1) FROM v where p_delivery_result = 6) AS ND5,
(SELECT COUNT(1) FROM v where p_delivery_result = 7) AS ND6,
(SELECT COUNT(1) FROM v where p_delivery_result = 8) AS ND7
FROM (
SELECT p_sery, p_id, d.p_delivery_result
FROM registries AS a, registry_regulations r, delivery d
WHERE a.p_id = r.registry_id AND d.p_id = r.regulation_id AND (SELECT
STR_TO_DATE(a.p_date_created, '%Y-%m-%d') BETWEEN '2017-04-01' AND '2017-06-01')
) as v;
But this not working.
Error: Table v doesn't exist
What I do wrong?
I have this tables:
And I want get the count of one of the status in table delivery

You cannot access the derived table from the context of a correlated subquery. Try this query instead:
SELECT CONCAT(v.p_sery, v.p_id) AS sery,
COUNT(CASE WHEN p_delivery_result = 1 THEN 1 END) AS delivery_count,
COUNT(CASE WHEN p_delivery_result = 2 THEN 1 END) AS ND1,
COUNT(CASE WHEN p_delivery_result = 3 THEN 1 END) AS ND2,
COUNT(CASE WHEN p_delivery_result = 4 THEN 1 END) AS ND3,
COUNT(CASE WHEN p_delivery_result = 5 THEN 1 END) AS ND4,
COUNT(CASE WHEN p_delivery_result = 6 THEN 1 END) AS ND5,
COUNT(CASE WHEN p_delivery_result = 7 THEN 1 END) AS ND6,
COUNT(CASE WHEN p_delivery_result = 8 THEN 1 END) AS ND7
FROM (
SELECT p_sery, p_id, d.p_delivery_result
FROM registries AS a
JOIN registry_regulations r ON a.p_id = r.registry_id
JOIN delivery d d.p_id = r.regulation_id
WHERE STR_TO_DATE(a.p_date_created, '%Y-%m-%d')
BETWEEN '2017-04-01' AND '2017-06-01') as v;
Note: Always uses modern, explicit JOIN syntax instead of old-fashioned, implicit syntax.

just remove as before V
FROM (
SELECT p_sery, p_id, d.p_delivery_result
FROM registries AS a, registry_regulations r, delivery d
WHERE a.p_id = r.registry_id AND d.p_id = r.regulation_id AND (SELECT
STR_TO_DATE(a.p_date_created, '%Y-%m-%d') BETWEEN '2017-04-01' AND '2017-06-01')
) v

Related

Count number of ratings

I want to calculate number of every rating group by given date range. I wrote the following query which is working perfect:
SELECT c.day,
(SELECT COUNT(DISTINCT user_id) FROM ratings r WHERE DATE(r.created_at) = c.day AND r.rating = 1 AND r.campaign_id = 2) AS rating1s,
(SELECT COUNT(DISTINCT user_id) FROM ratings r WHERE DATE(r.created_at) = c.day AND r.rating = 2 AND r.campaign_id = 2) AS rating2s,
(SELECT COUNT(DISTINCT user_id) FROM ratings r WHERE DATE(r.created_at) = c.day AND r.rating = 3 AND r.campaign_id = 2) AS rating3s,
(SELECT COUNT(DISTINCT user_id) FROM ratings r WHERE DATE(r.created_at) = c.day AND r.rating = 4 AND r.campaign_id = 2) AS rating4s,
(SELECT COUNT(DISTINCT user_id) FROM ratings r WHERE DATE(r.created_at) = c.day AND r.rating = 5 AND r.campaign_id = 2) AS rating5s
FROM calendar c
WHERE c.day >= '2018-08-01'
GROUP BY c.day
ORDER BY c.day
LIMIT 0, 31
But this is not an optimized way due to 5 sub queries and query is taking almost 2mins on my localhost, how can I optimize this query? The sample output is attached and I need same output.
You can rephrase this as conditional aggregation:
SELECT DATE(r.created_at),
COUNT(DISTINCT CASE WHEN r.rating = 1 THEN r.user_id END) as raging_1,
COUNT(DISTINCT CASE WHEN r.rating = 2 THEN r.user_id END) as raging_2,
COUNT(DISTINCT CASE WHEN r.rating = 3 THEN r.user_id END) as raging_3,
COUNT(DISTINCT CASE WHEN r.rating = 4 THEN r.user_id END) as raging_4,
COUNT(DISTINCT CASE WHEN r.rating = 5 THEN r.user_id END) as raging_5
FROM ratings r
WHERE r.campaign_id = 2 AND
r.created_at >= '2018-08-01'
GROUP BY DATE(r.created_at);
COUNT(DISTINCT) can be expensive. Remove it if you can.
Otherwise, it might be faster to do the DISTINCT once:
SELECT dte,
SUM( r.rating = 1 ) as raging_1,
SUM( r.rating = 2 ) as raging_2,
SUM( r.rating = 3 ) as raging_3,
SUM( r.rating = 4 ) as raging_4,
SUM( r.rating = 5 ) as raging_5
FROM (SELECT DISTINCT user_id, rating, DATE(r.created_at) as dte
FROM ratings r
WHERE r.campaign_id = 2 AND
r.created_at >= '2018-08-01'
) urd
GROUP BY dte;
This returns rows for each day that has at least one rating. If some days would have all zeroes, then you'll need an outer join of some sort. That adds almost nothing to the performance, so it can be tacked on if one of the above solutions works.
Here is a query I made using #Gordon's answer:
SELECT DATE(r.created_at),
COUNT(
DISTINCT
CASE
WHEN r.rating = 1
THEN user_id
ELSE 0
END
) as rating1s,
COUNT(
DISTINCT
CASE
WHEN r.rating = 2
THEN user_id
ELSE 0
END
) as rating2s,
COUNT(
DISTINCT
CASE
WHEN r.rating = 3
THEN user_id
ELSE 0
END
) as rating3s,
COUNT(
DISTINCT
CASE
WHEN r.rating = 4
THEN user_id
ELSE 0
END
) as rating4s,
COUNT(
DISTINCT
CASE
WHEN r.rating = 5
THEN user_id
ELSE 0
END
) as rating5s
FROM ratings r
WHERE r.campaign_id = 2 AND
DATE(r.created_at) >= '2018-08-01'
GROUP BY DATE(r.created_at)
This is still not optimized but much better than my initial solution.

Combining all data with a unique ID - MySQL

I have this data that I got from my current query.
What I want to do is combine and make it a single row where the type is Senior, the cashamount and Tenderamount are the same as well.
This is my desired result:
I'm getting my data from this table:
Here's my query:
SELECT a.DATE as `DATE`, a.employee as `EMPLOYEE`, a.TYPEID, a.NAME as
`NAME`, (select (case when a.typeid = 1 then a.amount else NULL end)) as
`CASHAMOUNT`,
(select (case when a.typeid <> 1 then a.amount else NULL end)) as
`TENDERAMOUNT`, (select gndtndr.IDENT from gndtndr where gndtndr.TYPE = 12
and `gndtndr`.`CHECK`= a.CHECK and gndtndr.DATE = a.DATE) as `ID`,
from gndtndr a
where STR_TO_DATE(a.DATE, '%m/%d/%Y') BETWEEN '20170901' AND '20170901'
order by STR_TO_DATE(a.DATE, '%m/%d/%Y')
My MySQL is a bit rusty, but give this a try!
SELECT a.Date, a.Employee, a.Name, a.ID, SUM(b.Amount) AS CashAmount,
SUM(c.Amount) AS TenderAmount FROM
(SELECT DISTINCT Date, Employee, Name, ID FROM gndtndr WHERE Type = 12) AS a
LEFT JOIN gndtndr AS b
ON a.ID = b.ID AND b.TypeID = 1
LEFT JOIN gndtdr AS c
ON a.ID = c.ID and c.TypeID <> 1
GROUP BY a.Date, a.Employee, a.Name, a.ID
I've figured it out :) I just have to define the type conditions in my where clause where the type is 1(for cash).
SELECT a.DATE as `DATE`, a.employee as `EMPLOYEE`, a.TYPEID, a.NAME as
`NAME`, (select sum(gndtndr.amount) from gndtndr where gndtndr.typeid = 1
and gndtndr.`CHECK` = a.`CHECK` and gndtndr.DATE = a.DATE) as `CASHAMOUNT`,
(select (case when a.typeid <> 1 then a.amount else NULL end)) as
`TENDERAMOUNT`, (select gndtndr.IDENT from gndtndr where gndtndr.TYPE = 12
and `gndtndr`.`CHECK`= a.CHECK and gndtndr.DATE = a.DATE) as `ID` from
gndtndr a
where a.TYPEID <> 1 and STR_TO_DATE(a.DATE, '%m/%d/%Y') BETWEEN '20170901'
AND '20170901' order by STR_TO_DATE(a.DATE, '%m/%d/%Y')

[HY000][1111] Invalid use of group function

I have searched a lot ,but none of other questions with error 1111 solves my problem.
My needs are to count the distinct phone number of some id
The following code works:
SELECT
a.id_borrow_application,
count(DISTINCT c.phone_no) CVG_CALL_OUT_COUNTS_6M
FROM t_snow_borrow_application_id a
JOIN t_snow_call_mobile b
JOIN t_snow_call_record_201612 c ON
(
a.id_borrow_application = b.id_borrow_application
AND b.id = c.id_call_mobile
)
WHERE c.call_type = 0
GROUP BY a.id_borrow_application;
But when I want to write 4 similar queries together,the error in title
happens.
[HY000][1111] Invalid use of group function
SELECT
a.id_borrow_application,
sum(CASE WHEN call_type = 0
THEN count(DISTINCT c.phone_no)
ELSE 0 END) CVG_CALL_OUT_COUNTS_6M,
sum(CASE WHEN call_type = 0 AND c.days <= 30
THEN count(DISTINCT c.phone_no)
ELSE 0 END) CVG_CALL_OUT_COUNTS_1M,
sum(CASE WHEN call_type = 1
THEN count(DISTINCT c.phone_no)
ELSE 0 END) CVG_CALL_IN_COUNTS_6M,
sum(CASE WHEN call_type = 1 AND c.days <= 30
THEN count(DISTINCT c.phone_no)
ELSE 0 END) CVG_CALL_IN_COUNTS_1M
FROM t_snow_borrow_application_id a
JOIN t_snow_call_mobile b
JOIN t_snow_call_record_201612 c ON
(
a.id_borrow_application = b.id_borrow_application
AND b.id = c.id_call_mobile
)
GROUP BY a.id_borrow_application;
Do I have to write 4 queries?
You are nesting aggregate function which is not allowed in MySQL.
You don't actually need the sum function for count distinct phone_nos for different conditions. Take the count (distinct outside the case and remove sum function and else clause of the case.
Try this:
select a.id_borrow_application,
count(distinct case when call_type = 0 then c.phone_no end) CVG_CALL_OUT_COUNTS_6M,
count(distinct case when call_type = 0
and c.days <= 30 then c.phone_no end) CVG_CALL_OUT_COUNTS_1M,
count(distinct case when call_type = 1 then c.phone_no end) CVG_CALL_IN_COUNTS_6M,
count(distinct case when call_type = 1
and c.days <= 30 then c.phone_no end) CVG_CALL_IN_COUNTS_1M
from t_snow_borrow_application_id a
join t_snow_call_mobile b
join t_snow_call_record_201612 c on (
a.id_borrow_application = b.id_borrow_application
and b.id = c.id_call_mobile
)
group by a.id_borrow_application;

working in mysql but not in db2. SQL State: 42601] DB2 SQL Error: SQLSTATE=42601, SQLERRMC==;sum(day(p.create_dt);CONCAT

Below is my query
select YEAR(p.create_dt) as year,
month(p.create_dt) as month,
p.system as systemName,
p.status as status,
sum(day(p.create_dt) = '01') as count1,
sum(day(p.create_dt) = '02') as count2
from pnm_history p
group by year(p.create_dt),
month(p.create_dt)
order by year(p.create_dt),
month(p.create_dt);
getting error near sum()
Replace the day() calls in MySQL with CASE statements:
SELECT p2.year,
p2.month,
p1.system AS systemName,
p1.status AS status,
p2.count1,
p2.count2
FROM pnm_history p1
INNER JOIN
(
SELECT YEAR(p.create_dt) AS year,
MONTH(p.create_dt) AS month,
SUM(CASE WHEN DAY(p.create_dt) = 1 THEN 1 ELSE 0 END) AS count1,
SUM(CASE WHEN DAY(p.create_dt) = 2 THEN 1 ELSE 0 END) AS count2
FROM pnm_history p
GROUP BY YEAR(p.create_dt),
MONTH(p.create_dt)
) p2
ON YEAR(p1.create_dt) = p2.year AND
MONTH(p1.create_dt) = p2.month
ORDER BY p2.year,
p2.month

mySQL - Limit the number of rows returned in one side of JOIN statement?

Everyone,
I am just curious if there is a way to do this sort of limiting with a query on a mySQL database:
Here are my tables:
Events
event_id event_title creation_time
Images
image_id src event_id
Comments
event_comment_id event_comment event_id
I would like to fetch events sorted by creation time, and get only 3 images and 3 comments for each event.
Any help, resources, or criticism is welcome. Thank you
Here's one approach. Basically, get the rownumber associated with each group of comments/images and only display up to 3:
SELECT E.*,
MAX(CASE WHEN I.rn = 1 THEN I.Image_Id END) Image1,
MAX(CASE WHEN I.rn = 2 THEN I.Image_Id END) Image2,
MAX(CASE WHEN I.rn = 3 THEN I.Image_Id END) Image3,
MAX(CASE WHEN C.rn = 1 THEN C.event_comment_id END) Comment1,
MAX(CASE WHEN C.rn = 2 THEN C.event_comment_id END) Comment2,
MAX(CASE WHEN C.rn = 3 THEN C.event_comment_id END) Comment3
FROM Events E
LEFT JOIN (SELECT #curRow:=IF(#prevRow = event_id, #curRow + 1, 1) rn,
Image_Id, src, event_id, #prevRow:= event_id
FROM Images
JOIN (SELECT #curRow := 0) r
) I ON E.event_id = I.Event_id
LEFT JOIN (SELECT #curRow2:=IF(#prevRow2 = event_id, #curRow2 + 1, 1) rn,
event_comment_id, event_comment, event_id, #prevRow2:= event_id
FROM Comments
JOIN (SELECT #curRow2 := 0) r
) C ON E.event_id = C.Event_id
GROUP BY E.Event_Id
ORDER BY E.Event_Id, E.creation_time DESC
And here is the SQL Fiddle.