This question already has an answer here:
MySQL pivot row into dynamic number of columns
(1 answer)
Closed 6 years ago.
I have statement like this one :
SELECT
COUNT(*)AS will
FROM
ae_orders o
LEFT JOIN
ae_orders_items oi ON oi.order_uid = o.uid
WHERE
po_date >= '2016-01-01' AND po_date <= '2016-01-31' AND status_text LIKE '%wil%'
This query is a count(*) so the result is only one field.
But i would like to execute this query 6-7 time in one time changing only the (like '%will%') part of this statement and get the result of each count side by side.
Wanted result :
I try left join, full join like this
(
SELECT
COUNT(*) AS will
FROM
ae_orders o
LEFT JOIN
ae_orders_items oi ON oi.order_uid = o.uid
WHERE
po_date >= '2016-01-01' AND po_date <= '2016-01-31' AND status_text LIKE '%wil%'
) AS will
LEFT JOIN
(
SELECT
COUNT(*) AS will
FROM
ae_orders o
LEFT JOIN
ae_orders_items oi ON oi.order_uid = o.uid
WHERE
po_date >= '2016-01-01' AND po_date <= '2016-01-31' AND status_text LIKE '%phi%'
) AS phil
I'm not really sure this is possible. If someone have a solution.
Solution
After reading some of your comments i found an other way to get and display my data.
Here is the statement to get my solution.
SELECT
'Will' AS USER,
COUNT(*) AS TOTAL
FROM
ae_orders o
LEFT JOIN
ae_orders_items oi ON oi.order_uid = o.uid
WHERE
po_date >= '2016-01-01' AND po_date <= '2016-01-31' AND status_text LIKE '%wil%'
UNION
SELECT
'Phil' AS USER,
COUNT(*) AS TOTAL
FROM
ae_orders o
LEFT JOIN
ae_orders_items oi ON oi.order_uid = o.uid
WHERE
po_date >= '2016-01-01' AND po_date <= '2016-01-31' AND status_text LIKE '%phi%'
UNION
SELECT
'Peter' AS USER,
COUNT(*) AS TOTAL
FROM
ae_orders o
LEFT JOIN
ae_orders_items oi ON oi.order_uid = o.uid
WHERE
po_date >= '2016-01-01' AND po_date <= '2016-01-31' AND status_text LIKE '%Pet%'
Instead of getting result side by side i get result one above the other.
As noted, your scenario is trying to pivot on a condition. Since all 3 queries are the same date range, just change to SUM( CASE/WHEN ) and you will have 1 row with all 3 counts.
SELECT
SUM( case when status_text LIKE '%wil%' then 1 else 0 end ) as CountWill,
SUM( case when status_text LIKE '%phi%' then 1 else 0 end ) as CountPhil,
SUM( case when status_text LIKE '%Pet%' then 1 else 0 end ) as CountPeter
from
ae_orders o
LEFT JOIN ae_orders_items oi
ON oi.order_uid = o.uid
WHERE
po_date >= '2016-01-01'
AND po_date <= '2016-01-31'
Related
when i'm running my program, the results of the number instead make a number merge and make the number into many results.
SELECT pengiriman_supply.po_nomor
, data_supplier.nama_supplier
, data_barang.nama_barang,
((sum(pengiriman_supply.jumlah))-(ifnull(masuk.terima,0))) as total
FROM pengiriman_supply INNER JOIN data_supplier ON pengiriman_supply.idsupplier = data_supplier.id_supplier
INNER JOIN data_barang ON pengiriman_supply.idbarang = data_barang.idbarang
left JOIN masuk on masuk.refrence = pengiriman_supply.po_nomor
where pengiriman_supply.tanggal between date_sub(curdate(), interval 120 day) and curdate()
group by pengiriman_supply.po_nomor
ORDER BY pengiriman_supply.po_nomor desc;
the results is this
enter image description here
Seems you are trying to get the sum() per po number. lets put this in a subquery then join again those tables you want info to show.
select t.po_nomor
, p.nama_supplier
, p1.nama_barangfrom
, t.total
from
(select t1.po_nomor
, (sum(t1.jumlah)-coalesce(t4.terima,0)) as total
from pengiriman_supply t1
inner join data_supplier t2 on t1.idsupplier = t2.id_supplier
inner join data_barang t3 on t1.idbarang = t3.idbarang
left join masuk t4 on t4.refrence = t1.po_nomor
where t1.tanggal between date_sub(curdate(), interval 120 day) and curdate()
group by t1.po_nomor) t
inner join pengiriman_supply s on s.po_nomor = t.po_nomor
inner join data_supplier p on s.idsupplier = p.id_supplier
inner join data_barang p1 on t.idbarang = p1.idbarang
order by t.po_nomor desc;
I need my query to select unix timestamps which range from a particular past date till now?For example I need to select '2013-01-01' till current date. I was able to do it for a particular year. Any help would be appreciated.
SELECT mdl_user_info_data.data, mdl_user.firstname, mdl_user.lastname, mdl_user.id AS userid, SUM( mdl_quiz.fcpd ) AS cpdtotal
FROM mdl_grade_grades
INNER JOIN mdl_user ON mdl_grade_grades.userid = mdl_user.id
INNER JOIN mdl_grade_items ON mdl_grade_grades.itemid = mdl_grade_items.id
INNER JOIN mdl_quiz ON mdl_grade_items.itemname = mdl_quiz.name
INNER JOIN mdl_course ON mdl_grade_items.courseid = mdl_course.id
INNER JOIN mdl_user_info_data ON mdl_user.id = mdl_user_info_data.userid
WHERE mdl_user_info_data.fieldid =1
AND mdl_grade_items.itemname IS NOT NULL
AND YEAR( FROM_UNIXTIME( mdl_grade_grades.timemodified ) ) =2013
GROUP BY mdl_user.id
To check for a timestamp value between a given datetime in the past, and the current datetime, something like this:
AND mdl_grade_grades.timemodified >= '2013-07-25 15:30'
AND mdl_grade_grades.timemodified < NOW()
Simply replace this line:
AND YEAR(FROM_UNIXTIME(mdl_grade_grades.timemodified)) = 2013
to:
AND FROM_UNIXTIME(mdl_grade_grades.timemodified)
BETWEEN '2012-01-01 12:00'
AND now()
It seems that you are storing unix timestamp in your timemodified column. You should consider changing it to timestamp type - this will allow to take advantage of index on that field. Now, your query (and this query as well) is slow because it has to compute FROM_UNIXTIME() on every row in that table and only then compare year or date.
UPDATE:
If you don't want to change types, using this should make your query work much faster (provided that there is an index on timemodified column):
AND mdl_grade_grades.timemodified
BETWEEN unix_timestamp('2012-01-01 12:00')
AND unix_timestamp(now())
try below query
SELECT mdl_user_info_data.data, mdl_user.firstname, mdl_user.lastname, mdl_user.id AS userid, SUM( mdl_quiz.fcpd ) AS cpdtotal
FROM mdl_grade_grades
INNER JOIN mdl_user ON mdl_grade_grades.userid = mdl_user.id
INNER JOIN mdl_grade_items ON mdl_grade_grades.itemid = mdl_grade_items.id
INNER JOIN mdl_quiz ON mdl_grade_items.itemname = mdl_quiz.name
INNER JOIN mdl_course ON mdl_grade_items.courseid = mdl_course.id
INNER JOIN mdl_user_info_data ON mdl_user.id = mdl_user_info_data.userid
WHERE mdl_user_info_data.fieldid =1
AND mdl_grade_items.itemname IS NOT NULL
AND mdl_grade_grades.timemodified < date('d-m-Y')
GROUP BY mdl_user.id
You can create a Stored Procedure and pass the date as parameter to it.
Here I made it more flexible by adding end date too.
CREATE PROCEDURE `NewProc`(IN StartDate date,IN EndDate date)
BEGIN
SELECT mdl_user_info_data.data, mdl_user.firstname, mdl_user.lastname, mdl_user.id AS userid, SUM( mdl_quiz.fcpd ) AS cpdtotal
FROM mdl_grade_grades
INNER JOIN mdl_user ON mdl_grade_grades.userid = mdl_user.id
INNER JOIN mdl_grade_items ON mdl_grade_grades.itemid = mdl_grade_items.id
INNER JOIN mdl_quiz ON mdl_grade_items.itemname = mdl_quiz.name
INNER JOIN mdl_course ON mdl_grade_items.courseid = mdl_course.id
INNER JOIN mdl_user_info_data ON mdl_user.id = mdl_user_info_data.userid
WHERE mdl_user_info_data.fieldid =1
AND mdl_grade_items.itemname IS NOT NULL
AND mdl_grade_grades.timemodified between StartDate and EndDate
GROUP BY mdl_user.id
END;
AND DATE(FROM_UNIXTIME(mdl_grade_grades.timemodified)) between '2013-01-01' and
DATE(NOW());
I currently have data organized in 2 tables as such:
Meetings
meet_id
meet_category
Orders
order_id
meet_id
order_date
I need to write a single query that returns the total number of meetings, the number of meetings with a category of "long" and the number of meetings with a category of "short".
Count only the meetings that have at least one order_date after March 1, 2011.
The output should be in 3 fields and 1 row
So far I what I have is:
SELECT COUNT(m.meet_id),
COUNT(SELECT m.meet_id WHERE m.meet_category = 'long'),
COUNT(SELECT m.meet_id WHERE m.meet_category = 'short')
FROM Meetings m
INNER JOIN Orders o
ON m.meet_id = o.meet_id
WHERE o.order_date >= '2011-03-01';
That is what first comes to mind, but this query doesn't work and I am not even sure if my approach is the correct one. All help appreciated!
Try this:
SELECT COUNT(m.meet_id),
SUM(CASE WHEN m.meet_category = 'long' THEN 1 ELSE 0 END),
SUM(CASE WHEN m.meet_category = 'short' THEN 1 ELSE 0 END)
FROM Meetings m where meet_id in
(select meet_id
FROM Orders o
WHERE o.order_date >= '2011-03-01');
try this
select count(1) as total_count,innerqry.*
(
select count(m.meet_id), meet_catagory
Meetings m
INNER JOIN Orders o
ON m.meet_id = o.meet_id
and m.meet_id in
(select meet_id from orders where order_date>= '2011-03-01')
group by meet_category
) innerqry
if you want only one row and you have few known meeting types try this
SELECT COUNT(m.meet_id),
SUM(CASE WHEN m.meet_category = 'long' THEN 1 ELSE 0 END),
SUM(CASE WHEN m.meet_category = 'short' THEN 1 ELSE 0 END)
FROM Meetings m
INNER JOIN Orders o
ON m.meet_id = o.meet_id
WHERE m.meet_id in
(select meet_id from orders where order_date>'2011-03-01')
Try this:
SELECT COUNT(m.meet_id),
(select count(*) from meetings m2 join orders o2 on o2.meet_id = m2.meet_id where m2.meet_category = 'long' and o2.order_date >= '2011-03-01'),
(select count(*) from meetings m2 join orders o2 on o2.meet_id = m2.meet_id where m2.meet_category = 'short' and o2.order_date >= '2011-03-01')
FROM mettings m
INNER JOIN Orders o
ON m.meet_id = o.meet_id
WHERE o.order_date >= '2011-03-01';
You must implement two indipendent subqueries because you want a total number in your main query without grouped by meet_id, so if you try to link subquery with field in main query you have an error about grouped by fields.
I have this query that gives me back more than one result. I would like to edit it so that it only will give me one result per o.Customer_ID and then have that be the order that would be closest to today with o.OrderPlaceServerTime.
Here's the Query I have:
SELECT
o.Order_ID,
o.Customer_ID,
o.OrderPlaceServerTime,
o.CustomerOrderTotal
FROM
Orders o
LEFT JOIN Order_LineDetails oln
ON oln.Order_ID = o.Order_ID
WHERE
o.OrderPlaceServerTime >= '2012-09-01 00:00:00'
AND o.OrderPlaceServerTime <= '2012-12-01 00:00:00'
AND o.CustomerOrderTotal >= '50'
AND oln.Product_ID = '75'
What would I need to change to achieve this?
I would like to edit it so that it only will give me one result per o.Customer_ID
So, first you should get the latest order for the qualifying Customer IDs, by grouping the qualifying order by customer ID and picking the max or OrderPlaceServerTime. Then you would join those records with the Orders on customer ID and the OrderPlaceServerTime to pick the other two attributes of interest.
SELECT
o.Order_ID,
o.Customer_ID,
o.OrderPlaceServerTime,
o.CustomerOrderTotal
FROM
Orders o
JOIN (
SELECT
o.Customer_ID,
MAX(o.OrderPlaceServiceTime) 'MaxOrderPlaceServiceTime'
FROM
Orders o
LEFT JOIN Order_LineDetails oln
ON oln.Order_ID = o.Order_ID
WHERE
o.OrderPlaceServerTime >= '2012-09-01 00:00:00'
AND o.OrderPlaceServerTime <= '2012-12-01 00:00:00'
AND o.CustomerOrderTotal >= '50'
AND oln.Product_ID = '75'
GROUP BY o.Customer_ID
) AS A
ON
o.Customer_ID = A.Customer_ID AND
o.OrderPlaceServiceTime = A.MaxOrderPlaceServiceTime
If I understood correctly what you need, this should be the query :
SELECT * FROM
( SELECT
o.Order_ID,
o.Customer_ID,
o.OrderPlaceServerTime,
o.CustomerOrderTotal
FROM
Orders o
LEFT JOIN Order_LineDetails oln
ON oln.Order_ID = o.Order_ID
WHERE
o.OrderPlaceServerTime >= '2012-09-01 00:00:00'
AND o.OrderPlaceServerTime <= '2012-12-01 00:00:00'
AND o.CustomerOrderTotal >= '50'
AND oln.Product_ID = '75'
ORDER BY o.Customer_ID, o.OrderPlaceServerTime DESC ) AS tab1
GROUP BY o.Customer_ID;
I am trying to make a query that says If the customer has no invoice, but has an appointment in the last 6 months, please give me their clientId and name The following result returns and empty set.
SELECT clients.clientId, clients.studentFirstName, clients.studentLastName
FROM clients, invoices, appointments
WHERE (NOT EXISTS
(SELECT *
FROM invoices, clients
WHERE invoices.clientId = clients.clientId))
AND (EXISTS
(SELECT * FROM appointments, clients
WHERE appointments.clientId = invoices.clientId
AND appointments.date >= DATE_ADD(curdate(), INTERVAL 6 MONTH)));
EDIT: The query that ended up working was created after a little tweaking of john's answer:
SELECT a.clientID,
a.studentFirstName,
a.studentLastName
FROM clients a
LEFT JOIN invoices b
on a.clientID = b.clientID
LEFT JOIN appointments c
on a.clientID = c.clientID
WHERE b.clientId IS NULL AND
c.`date` >= DATE_SUB(curdate(), INTERVAL 6 MONTH)
Use LEFT JOIN instead.
SELECT a.ClientID,
a.studentFirstName,
a.clients.studentLastName
FROM clients a
LEFT JOIN invoices b
on a.ClientID = b.ClientID
LEFT JOIN appointments c
on a.ClientID = c.ClientID
WHERE b.Client IS NULL AND
c.`Date` >= DATE_SUB(curdate(), INTERVAL 6 MONTH)
Are you sure it's supposed to be DATE_ADD and not DATE_SUB ?
You can use joins:
SELECT a.clientId,
a.studentFirstName,
a.studentLastName
FROM clients a
JOIN appointments b ON a.clientId = b.clientId
AND b.date >= CURDATE() - INTERVAL 6 MONTH
LEFT JOIN invoices c ON a.clientId = c.clientId
WHERE c.clientId IS NULL