I'm building a line chart for a product sales report by using the Google Chart API and are separating the data on a per day basis with basically running the same query in a loop for each day using UNION ALL as glue.
E.g. A report for a whole year will repeat the query, using UNION ALL 365 times.
I'm guessing this is not a -best practice- example so if anyone would be so kind and point me in the right direction of how to optimize this query, I would greatly appreciate it.
SELECT SUM(op.qty) AS qty
FROM uc_order_products op
LEFT JOIN uc_orders o ON o.order_id = op.order_id
LEFT JOIN node n ON n.nid = op.nid
LEFT JOIN node_type nt ON nt.type = n.type
WHERE (o.created > 1247695200) AND (o.created < 1247781600)
AND (o.order_status = 'completed')
AND (nt.type = 'book' OR nt.type = 'digital_movie')
UNION ALL
SELECT SUM(op.qty) AS qty
FROM uc_order_products op
LEFT JOIN uc_orders o ON o.order_id = op.order_id
LEFT JOIN node n ON n.nid = op.nid
LEFT JOIN node_type nt ON nt.type = n.type
WHERE (o.created > 1247781600) AND (o.created < 1247868000)
AND (o.order_status = 'completed')
AND (nt.type = 'book' OR nt.type = 'digital_movie')
UNION ALL
SELECT SUM(.......
Thanks for all the quick replies! With the query example from jspcal, my query ended up like this:
SELECT SUM(op.qty) AS qty, DATE_FORMAT(FROM_UNIXTIME(o.created),'%d-%m-%Y') AS day
FROM uc_order_products op
LEFT JOIN uc_orders o ON o.order_id = op.order_id
LEFT JOIN node n ON n.nid = op.nid
LEFT JOIN node_type nt ON nt.type = n.type
WHERE (o.created > 1247695200) AND (o.created < 1263596400)
AND (o.order_status = 'completed')
AND (nt.type = 'book' OR nt.type = 'digital_movie')
GROUP BY day
And with PHP, I combine a complete date range array (matching array keys with strtotime($data->day) from the query result) to get days with no sale.
you can group by day:
select sum(op.qty) as qty, date_format(o.created, '%Y-%m-%d') as day
from ... where ... o.created >= subdate(now(), interval 1 year) and
o.created <= now() group by day order by day
will report the sum for each day of the year in the data set
You sould be able to convert
WHERE (o.created > 1247695200) AND (o.created < 1247781600)
AND (o.order_status = 'completed')
AND (nt.type = 'book' OR nt.type = 'digital_movie')
WHERE (o.created > 1247781600) AND (o.created < 1247868000)
AND (o.order_status = 'completed')
AND (nt.type = 'book' OR nt.type = 'digital_movie')
....
To something like
WHERE (
(o.created > 1247695200) AND (o.created < 1247781600)
OR (o.created > 1247781600) AND (o.created < 1247868000)
...
)
AND (o.order_status = 'completed')
AND (nt.type = 'book' OR nt.type = 'digital_movie')
Related
I'm trying to join a different table depended on the value of a "task_type" column
What is wrong with the syntax?
Thanks.
SELECT t.*,s.task_name
CASE
WHEN t.task_type = 0 THEN
LEFT JOIN scheduler_tasks s ON s.scheduler_task_id = t.task_id
WHEN t.task_type = 1 THEN
LEFT JOIN invoice_tasks s ON s.uid = t.task_id
END
FROM task_timings t
WHERE t.account_id = ? AND t.start_date >= DATE(?) AND t.start_date <= DATE(?)
I believe you want this:
SELECT t.*,
COALESCE(s.task_name, i.task_name) as task_name
FROM task_timings t LEFT JOIN
scheduler_tasks s
ON s.scheduler_task_id = t.task_id AND
t.task_type = 0 LEFT JOIN
invoice_tasks i
ON i.uid = t.task_id AND t.task_type = 1
WHERE t.account_id = ? AND t.start_date >= DATE(?) AND
t.start_date <= DATE(?);
Can you try like this :
SELECT t.*,s.task_name FROM task_timings t
CASE
WHEN t.task_type = 0 THEN
LEFT JOIN scheduler_tasks s ON s.scheduler_task_id = t.task_id
WHEN t.task_type = 1 THEN
LEFT JOIN invoice_tasks s ON s.uid = t.task_id
END
WHERE t.account_id = ? AND t.start_date >= DATE(?) AND t.start_date <= DATE(?)
i am developing a LMS system for an institute
and i am trying to develop a recovery report on the end of month
the report contains student name total fee package, total received, total receiveable, current month pending installment
here is the installment data of a student with his admission id
and this is the ledger data from where ican pick the fee package and total receiveable fees
and i am using this query for recovery report
SELECT
SUM(l.dr)-SUM(l.cr) as sum_remaining,
f.dr as fee_package,
SUM(i.payment) as this_month_install,
a.reg_id, s.fname
FROM
ledger l, ledger f, student_data s,
admissions a LEFT OUTER JOIN installments i ON a.admissionid = i.admissionid
WHERE
a.admissionid = '58ac4b5421488' AND
a.reg_id = s.reg_id AND
l.reference = '58ac4b5421488' AND
l.details <> 'registration fee' AND
f.reference = '58ac4b5421488' AND
f.details = 'Fee Package' AND
i.install_no <> '1' AND
MONTH(i.pay_date) = '04' AND
YEAR(i.pay_date) = '2017'
GROUP BY a.admissionid
and its giving the result like this
but the result should be like
sum_remaining = 10000
and this_month_install = 10000
please help me to sort out this problem
Thanks in advance
you should start from admission and use inner join for the others table (left join for installments)
SELECT
SUM(l.dr)-SUM(l.cr) as sum_remaining,
f.dr as fee_package,
SUM(i.payment) as this_month_install,
a.reg_id,
s.fname
FROM admissions a
Inner JOIN ledger f ON f.reference = a.admissionid AND f.details = 'Fee Package'
INNER JOIN ledger l ON l.reference = a.admissionid AND l.details <> 'registration fee'
INNER JOIN student_data s ON a.reg_id = s.reg_id
LEFT JOIN installments i ON a.admissionid = i.admissionid AND i.install_no <> '1'
WHERE a.admissionid = '58ac4b5421488'
AND MONTH(i.pay_date) = '04'
AND YEAR(i.pay_date) = '2017'
GROUP BY a.admissionid
you have two row in installments table that match .. try filter just one
SELECT
SUM(l.dr)-SUM(l.cr) as sum_remaining,
f.dr as fee_package,
SUM(i.payment) as this_month_install,
a.reg_id,
s.fname
FROM admissions a
Inner JOIN ledger f ON f.reference = a.admissionid AND f.details = 'Fee Package'
INNER JOIN ledger l ON l.reference = a.admissionid AND l.details <> 'registration fee'
INNER JOIN student_data s ON a.reg_id = s.reg_id
LEFT JOIN installments i ON a.admissionid = i.admissionid
AND i.install_no not in ( '1', '2')
WHERE a.admissionid = '58ac4b5421488'
AND MONTH(i.pay_date) = '04'
AND YEAR(i.pay_date) = '2017'
GROUP BY a.admissionid
i have done this with a sub query
thanks all
select a.admissionid, s.fname,
sum(l.dr)-SUM(l.cr) as sum_remaining, i.*,
f.dr as fee_package from student_data s,
ledger l, ledger f, admissions a
RIGHT outer join (select admissionid,
sum(payment) as this_month_install
from
installments g where g.install_no <> '1' and MONTH(g.pay_date) = '04' and YEAR(g.pay_date) = '2017' group by g.admissionid) i
ON
i.admissionid = a.admissionid where a.reg_id = s.reg_id and
a.status = 'studying' and a.course = 'PH' and
a.campus = 'CIFSD01' and l.reference = a.admissionid and
l.details <> 'registration fee' and f.reference = a.admissionid
and f.details = 'Fee Package' GROUP BY a.std_id
I am including the code I am trying to use. What I want is to get a count of encounter id's for each doctor. I want to capture patients who have had at least 2 visits or who have had one preventive visit. I don't know how to make this work using the having statement. thanks for any assistance.
SELECT e.doctorID, COUNT(DISTINCT e.encounterID) AS VisitCount
FROM enc e
JOIN users u ON e.patientID = u.uid
Left JOIN diagnosis d ON e.encounterID = d.encounterID
LEFT JOIN items it ON d.itemID = it.itemID
LEFT JOIN itemdetail id ON it.itemID = id.itemID
WHERE e.encType = 1 AND e.status = 'CHK' AND e.deleteFlag = 0 AND
e.date BETWEEN DATE_ADD((LAST_DAY(DATE_ADD(CURDATE(),INTERVAL -2 MONTH))), INTERVAL 1 DAY) AND LAST_DAY(DATE_ADD(CURDATE(),INTERVAL -1 MONTH))
AND FLOOR(DATEDIFF(NOW(),u.ptdob)/365.25) >= 18 AND e.doctorID = e.resourceID
GROUP BY e.doctorID, id.value
HAVING
COUNT(e.patientid)>=2 OR
id.value in ('Z00.00', 'Z00.01')
You dont need to include id.value in grp by clause. Try to give valid condition in having clause with id.value
select e.doctorID,
COUNT(distinct e.encounterID) as VisitCount from enc e join users u on e.patientID = u.uid
left join diagnosis d on e.encounterID = d.encounterID left join items it on
d.itemID = it.itemID left join itemdetail id on
it.itemID = id.itemID where e.encType = 1 and e.status ='CHK' and e.deleteFlag = 0 and
e.date between DATE_ADD((LAST_DAY(DATE_ADD(CURDATE(), INTERVAL - 2 MONTH))), INTERVAL 1 DAY)
and LAST_DAY(DATE_ADD(CURDATE(), INTERVAL - 1 MONTH))
and
FLOOR(DATEDIFF(NOW(), u.ptdob) / 365.25) >= 18
and e.doctorID = e.resourceID group by e.doctorID
having COUNT(e.patientid) >= 2
or sum(case when id.value in ('Z00.00','Z00.01') then 1
else 0 end)>=1
I don't know if this is possible but I'm trying to make a select queries with a couple of JOINS with a WHERE statement. What I need is a field based on a particular WHERE and another field with different WHERE.
Current SQL query:
SELECT SUM(a.totaltime), b.user_name, MONTHNAME(a.date)
FROM a
JOIN c on c.id = a.id
JOIN b on b.userid = c.userid
LEFT JOIN d on a.projid = d.projectid
LEFT JOIN e on a.account_id = e.salesorderid
LEFT JOIN f on e.salesorderid = f.salesorderid
LEFT JOIN g on d.projectid = g.projectid
WHERE c.deleted != "1" AND YEAR(DATE(NOW())) AND ( f.cf_991 = '1' OR g.cf_990 = '1')
group by user_name,MONTHNAME(a.date);
This works fine but I need to include another field this time WHERE would be:
WHERE c.deleted != "1" AND YEAR(DATE(NOW())) AND ( f.cf_991 = '0' OR g.cf_990 = '0')
Any help is greatly appreciated thanks
EDIT:
CURRENT OUTPUT IS:
total_time username MONTHNAME(a.date)
22.5 admin April
21 admin June
15 max April
So the above is based on f.cf_991 = '1' OR g.cf_990 = '1'
What I need is this:
total_time username MONTHNAME(a.date) total_time_2
22.5 admin April 5
21 admin June 9
15 max April 13
total_time_2 is based on f.cf_991 = '0' OR g.cf_990 = '0'.
SELECT SUM(CASE WHEN f.cf_991 = '1' OR g.cf_990 = '1' THEN a.totaltime END) as total_time
, b.user_name, MONTHNAME(a.date)
, SUM(CASE WHEN f.cf_991 = '0' OR g.cf_990 = '0' THEN a.totaltime END) as total_time_2
FROM a
JOIN c on c.id = a.id
JOIN b on b.userid = c.userid
LEFT JOIN d on a.projid = d.projectid
LEFT JOIN e on a.account_id = e.salesorderid
LEFT JOIN f on e.salesorderid = f.salesorderid
LEFT JOIN g on d.projectid = g.projectid
WHERE c.deleted != "1"
AND YEAR(CURDATE()) = a_column_containing_a_date
AND (
( f.cf_991 = '1' OR g.cf_990 = '1')
OR
( f.cf_991 = '0' OR g.cf_990 = '0')
)
group by user_name,MONTHNAME(a.date);
Just try this
SELECT
SUM(if(f.cf_991 = '1' || g.cf_990 = '1',a.totaltime,0)),
SUM(if(f.cf_991 = '0' || g.cf_990 = '0',a.totaltime,0)),
b.user_name, MONTHNAME(a.date) FROM a
JOIN c on c.id = a.id
JOIN b on b.userid = c.userid
LEFT JOIN d on a.projid = d.projectid
LEFT JOIN e on a.account_id = e.salesorderid
LEFT JOIN f on e.salesorderid = f.salesorderid
LEFT JOIN g on d.projectid = g.projectid
WHERE c.deleted != "1" AND YEAR(DATE(NOW()))
and (( f.cf_991 = '1' OR g.cf_990 = '1') or( f.cf_991 = '0' OR g.cf_990 = '0') )
group by ser_name,MONTHNAME(a.date);
Hi I have run into a dilemma, I am doing this query:
SELECT GROUP_CONCAT(DISTINCT(ca.category_name) SEPARATOR ', ') AS categories, pr.promo_name, pr.add_value_text, c.contract_id, c.cmeal_plan, c.cmin_markup, c.civa, c.tax_include, c.hotel_id, hi.hname, hi.hstars, im.image_file, pl.plan_name, ra.price
FROM contracts AS c
INNER JOIN hotel_info AS hi ON hi.hotel_id = c.hotel_id AND hi.destination_id = '6460'
INNER JOIN images AS im ON im.foreign_id = hi.hotel_id
INNER JOIN meal_plan AS pl ON pl.plan_code = c.cmeal_plan AND pl.lang = '1'
INNER JOIN hotel_categories AS hc ON hc.hotel_id = hi.hotel_id
INNER JOIN categories AS ca ON ca.category_code = hc.category_code AND ca.lang = '1'
LEFT JOIN
(SELECT
r.hotel_id, AVG(r.double) AS price
FROM
rates AS r ) AS ra
ON ra.hotel_id = hi.hotel_id
LEFT JOIN promotions AS pr ON pr.hotel_id = hi.hotel_id AND FIND_IN_SET(c.contract_id, pr.contract_id) > 0 AND pr.book_start <= '2012-11-01' AND pr.book_end >= '2012-11-02' AND travel_start <= '2012-11-23' AND travel_end >= '2012-11-30' AND pr.lang = '1'
WHERE c.cstart <= '2012-11-01' AND c.cend >= '2012-11-01'
AND hi.status = '1'
AND im.type ='1'
GROUP BY hi.hotel_id
I am getting all the desired results except for the sub select query.. each hotel has a price but it is only giving me back one result and the rest are all null. Is there an error in my query? If any additional information is needed please let me know and thank you in advance for any help!
You are missing the GROUP BY in your subquery, so MySQL will only return one-value. If you want all hotel_id's then you need to GROUP BY that field:
SELECT GROUP_CONCAT(DISTINCT(ca.category_name) SEPARATOR ', ') AS categories,
pr.promo_name,
pr.add_value_text,
c.contract_id,
c.cmeal_plan,
c.cmin_markup,
c.civa,
c.tax_include,
c.hotel_id,
hi.hname,
hi.hstars,
im.image_file,
pl.plan_name,
ra.price
FROM contracts AS c
INNER JOIN hotel_info AS hi
ON hi.hotel_id = c.hotel_id
AND hi.destination_id = '6460'
INNER JOIN images AS im
ON im.foreign_id = hi.hotel_id
INNER JOIN meal_plan AS pl
ON pl.plan_code = c.cmeal_plan
AND pl.lang = '1'
INNER JOIN hotel_categories AS hc
ON hc.hotel_id = hi.hotel_id
INNER JOIN categories AS ca
ON ca.category_code = hc.category_code
AND ca.lang = '1'
LEFT JOIN
(
SELECT r.hotel_id, AVG(r.double) AS price
FROM rates AS r
GROUP BY r.hotel_id <-- add a GROUP BY hotel_id then you will get avg() for each hotel
) AS ra
ON ra.hotel_id = hi.hotel_id
LEFT JOIN promotions AS pr
ON pr.hotel_id = hi.hotel_id
AND FIND_IN_SET(c.contract_id, pr.contract_id) > 0
AND pr.book_start <= '2012-11-01'
AND pr.book_end >= '2012-11-02'
AND travel_start <= '2012-11-23'
AND travel_end >= '2012-11-30'
AND pr.lang = '1'
WHERE c.cstart <= '2012-11-01'
AND c.cend >= '2012-11-01'
AND hi.status = '1'
AND im.type ='1'
GROUP BY hi.hotel_id