I am working to create a graph for POS data. I
SELECT DATE_FORMAT(DATE_ADD(DATE(receipts.datenew - INTERVAL (5*60 + 30) MINUTE), INTERVAL (5*60 + 30) MINUTE), '%Y-%m-%d') AS interval_start,
CONVERT(EXTRACTVALUE(PRODUCTS.ATTRIBUTES, '/properties//entry[#key=\"maincat\"]') USING UTF8) AS MAINCAT,
ROUND(SUM(TICKETLINES.PRICE * TICKETLINES.UNITS), -3) AS DAYSALES
FROM TICKETLINES, TICKETS, RECEIPTS, PRODUCTS
WHERE TICKETLINES.PRODUCT = PRODUCTS.ID
AND TICKETLINES.TICKET = TICKETS.ID
AND TICKETS.ID = RECEIPTS.ID
AND TICKETLINES.PRODUCT IS NOT NULL
AND (receipts.datenew >= DATE_SUB(NOW(), INTERVAL 3 MONTH) AND receipts.person > 0)
GROUP BY DATE(receipts.datenew - INTERVAL (5*60 + 30) MINUTE), MAINCAT
ORDER BY interval_start, MAINCAT
And I get the following data:
interval_start MAINCAT DAYSALES
2016-12-31 Drink 45108000
2016-12-31 Food 49791000
2016-12-31 Other 109000
2017-01-01 Drink 14226000
2017-01-01 Food 27425000
2017-01-01 Other 36000
2017-01-02 Drink 20400000
2017-01-02 Food 25648000
2017-01-02 Other 109000
But I need this format:
interval_start Drink Food
2016-12-31 45108000 36000
2016-12-31 49791000 20400000
2016-12-31 109000 25648000
2017-01-01 27425000 109000
2017-01-01 14226000 49791000
I believe a subquery is the answer, but I am not able to figure it out.
Thanks in advance.
Allan
I have been able to get the data in the correct format with the following query - thank you for pointing me in the right direction:
SELECT DATE_FORMAT(DATE_ADD(DATE(receipts.datenew - INTERVAL (5*60 + 30) MINUTE), INTERVAL (5*60 + 30) MINUTE), '%Y-%m-%d') AS DATEofSALES,
SUM(CASE WHEN CONVERT(EXTRACTVALUE(PRODUCTS.ATTRIBUTES, '/properties//entry[#key=\"maincat\"]') USING UTF8) = 'Drink' THEN ticketlines.price ELSE 0 END) DRINKSALES,
SUM(CASE WHEN CONVERT(EXTRACTVALUE(PRODUCTS.ATTRIBUTES, '/properties//entry[#key=\"maincat\"]') USING UTF8) = 'Food' THEN ticketlines.price ELSE 0 END) FOODSALES,
SUM(CASE WHEN CONVERT(EXTRACTVALUE(PRODUCTS.ATTRIBUTES, '/properties//entry[#key=\"maincat\"]') USING UTF8) = 'Other' THEN ticketlines.price ELSE 0 END) OTHERSALES
FROM TICKETLINES, TICKETS, RECEIPTS, PRODUCTS
WHERE TICKETLINES.PRODUCT = PRODUCTS.ID
AND TICKETLINES.TICKET = TICKETS.ID
AND TICKETS.ID = RECEIPTS.ID
AND TICKETLINES.PRODUCT IS NOT NULL
AND (receipts.datenew >= {ts '2017-02-01 06:00:00.000'} AND receipts.datenew < {ts '2017-03-31 14:28:00.000'} AND receipts.person > 0)
GROUP BY DATE(receipts.datenew - INTERVAL (5*60 + 30) MINUTE) ORDER BY DATEofSALES
Related
i have query
select a.`2021`,
b.`2022`,
a.product,
concat(ceil((b.`2022`-a.`2021`)/ a.`2021` * 100), '%') as growth
from ( SELECT SUM(total) as `2021`,
product,
sum
FROM table
WHERE YEAR(month) = 2021
AND case when day(CURRENT_DATE()) > 10
then QUARTER(month) = QUARTER(CURRENT_DATE() - INTERVAL 1 MONTH)
else QUARTER(month) = QUARTER(CURRENT_DATE() - INTERVAL 3 MONTH)
end
GROUP BY Product ,
YEAR(month) )a
JOIN ( SELECT SUM(total) as `2022`,
Product
FROM table
WHERE YEAR(month) = 2022
AND case when day(CURRENT_DATE()) > 10
then QUARTER(month) = QUARTER(CURRENT_DATE() - INTERVAL 1 MONTH)
else QUARTER(month) = QUARTER(CURRENT_DATE() - INTERVAL 3 MONTH)
end
GROUP BY Product ,
YEAR(month) ) b on a.Product=b.Product;
if the current date is not the end of the quarter then the data that appears is the data in the previous quarter period
I would like your help with the following:
query 1:
SELECT stock.ST_CODE as xCODE, (sum(ordercont.QTY) / 12) as x12WeeksAvg
FROM orders
LEFT JOIN ordercont ON ordercont.O_REF = orders.O_REF
LEFT JOIN stock ON stock.PD_CODE = ordercont.PD_CODE
WHERE stock.ST_CODE IS NOT NULL
AND orders.O_CUSTDATE BETWEEN DATE_SUB( (DATE_ADD(CURDATE(), INTERVAL - WEEKDAY(CURDATE()) DAY)) , INTERVAL 84 DAY)
AND DATE_SUB(DATE(NOW()), INTERVAL DAYOFWEEK(NOW())-1 DAY)
GROUP BY stock.ST_CODE
query 2:
SELECT stock.ST_CODE as xCODE, (sum(ordercont.QTY) / 4) as x4WeeksAvg
FROM orders LEFT JOIN ordercont ON ordercont.O_REF = orders.O_REF
LEFT JOIN stock ON stock.PD_CODE = ordercont.PD_CODE
WHERE stock.ST_CODE IS NOT NULL
AND orders.O_CUSTDATE BETWEEN DATE_SUB( (DATE_ADD(CURDATE(), INTERVAL - WEEKDAY(CURDATE()) DAY)) , INTERVAL 28 DAY)
AND DATE_SUB(DATE(NOW()), INTERVAL DAYOFWEEK(NOW())-1 DAY)
GROUP BY stock.ST_CODE
Is there any way to have the result like this (the queries returns different number of results):
------------------------------------
| xCode | x12WeeksAvg | x4WeeksAvg |
------------------------------------
| ... | ... | ... |
------------------------------------
Thank you!!
Split the BETWEEN condition
orders.O_CUSTDATE BETWEEN DATE_SUB( (DATE_ADD(CURDATE(), INTERVAL - WEEKDAY(CURDATE()) DAY)) , INTERVAL 84 DAY)
AND DATE_SUB(DATE(NOW()), INTERVAL DAYOFWEEK(NOW())-1 DAY)
into two parts
AND orders.O_CUSTDATE >= DATE_SUB( (DATE_ADD(CURDATE(), INTERVAL - WEEKDAY(CURDATE()) DAY)) , INTERVAL 84 DAY)
AND orders.O_CUSTDATE <= DATE_SUB(DATE(NOW()), INTERVAL DAYOFWEEK(NOW())-1 DAY)
and rewrite it to
AND orders.O_CUSTDATE >= CURDATE() - INTERVAL (WEEKDAY(NOW()) + 84) DAY
AND orders.O_CUSTDATE <= CURDATE() - INTERVAL (DAYOFWEEK(NOW()) - 1) DAY
to get shorter and more readable code. Do the same for the second query.
Now the two queries differ only in two expressions
(sum(ordercont.QTY) / 12) as x12WeeksAvg
(sum(ordercont.QTY) / 4) as x4WeeksAvg
orders.O_CUSTDATE >= CURDATE() - INTERVAL (WEEKDAY(NOW()) + 84) DAY
orders.O_CUSTDATE >= CURDATE() - INTERVAL (WEEKDAY(NOW()) + 28) DAY
Given
<X>: orders.O_CUSTDATE >= CURDATE() - INTERVAL (WEEKDAY(NOW()) + 84) DAY
and
<Y>: orders.O_CUSTDATE >= CURDATE() - INTERVAL (WEEKDAY(NOW()) + 28) DAY
you can use conditional aggregation to combine the two queries:
SELECT stock.ST_CODE as xCODE,
(sum(CASE WHEN <X> THEN ordercont.QTY ELSE 0 END) / 12) as x12WeeksAvg,
(sum(CASE WHEN <Y> THEN ordercont.QTY ELSE 0 END) / 4) as x4WeeksAvg
FROM orders
LEFT JOIN ordercont ON ordercont.O_REF = orders.O_REF
LEFT JOIN stock ON stock.PD_CODE = ordercont.PD_CODE
WHERE stock.ST_CODE IS NOT NULL
AND orders.O_CUSTDATE <= CURDATE() - INTERVAL (DAYOFWEEK(NOW()) - 1) DAY
GROUP BY stock.ST_CODE
Replace <X> and <Y> accordingly.
Update
To improve the performance you can add
AND orders.O_CUSTDATE >= CURDATE() - INTERVAL (WEEKDAY(NOW()) + 84) DAY
to the WHERE clause.
Also note that the condition stock.ST_CODE IS NOT NULL will convert your LEFT JOINs to INNER JOINs. So you could as well just write JOIN.
You can subquery them like this to get your desired output:
SELECT A.xCODE,
COALESCE(B.x12WeeksAvg, 'N/A') as x12WeeksAvg,
COALESCE(C.x4WeeksAvg, 'N/A') as x4WeeksAvg
FROM (SELECT DISTINCT ST_CODE as xCODE FROM stock) A
LEFT JOIN (
SELECT stock.ST_CODE as xCODE, (sum(ordercont.QTY) / 12) as x12WeeksAvg
FROM orders
LEFT JOIN ordercont ON ordercont.O_REF = orders.O_REF
LEFT JOIN stock ON stock.PD_CODE = ordercont.PD_CODE
WHERE stock.ST_CODE IS NOT NULL
AND orders.O_CUSTDATE BETWEEN DATE_SUB( (DATE_ADD(CURDATE(), INTERVAL - WEEKDAY(CURDATE()) DAY)) , INTERVAL 84 DAY) AND DATE_SUB(DATE(NOW()), INTERVAL DAYOFWEEK(NOW())-1 DAY)
GROUP BY stock.ST_CODE
) B ON A.xCODE = B.xCODE
LEFT JOIN (
SELECT stock.ST_CODE as xCODE, (sum(ordercont.QTY) / 4) as x4WeeksAvg
FROM orders
LEFT JOIN ordercont ON ordercont.O_REF = orders.O_REF
LEFT JOIN stock ON stock.PD_CODE = ordercont.PD_CODE
WHERE stock.ST_CODE IS NOT NULL
AND orders.O_CUSTDATE BETWEEN DATE_SUB( (DATE_ADD(CURDATE(), INTERVAL - WEEKDAY(CURDATE()) DAY)) , INTERVAL 28 DAY) AND DATE_SUB(DATE(NOW()), INTERVAL DAYOFWEEK(NOW())-1 DAY)
GROUP BY stock.ST_CODE
) C ON A.xCODE = C.xCODE
WHERE COALESCE(B.x12WeeksAvg, C.x4WeeksAvg) IS NOT NULL
I have two tables
1) outreach
id profile_id url
-------------------------
1 2 www.test.com
2 3 www.google.com
3 4 www.example.com
4 2 www.test2.com
5 2 www.test3.com
6 2 www.test4.com
2). outreach_links
id outreach_id start_date created_at cost status
-----------------------------------------------------------------------
1 1 2016-12-01 00:00:00 2016-12-07 00:00:00 100.00 Approved
2 1 2016-12-02 00:00:00 2016-12-09 00:00:00 120.00 Approved
3 1 NUll 2016-12-28 00:00:00 20.00 Pending
4 1 2016-12-05 00:00:00 2016-12-10 00:00:00 35.00 Approved
5 1 2016-12-07 00:00:00 2016-12-13 00:00:00 10.00 Approved
6 2 2016-12-10 00:00:00 2016-12-15 00:00:00 10.00 Pending
7 2 2016-12-13 00:00:00 2016-12-18 00:00:00 10.00 Approved
8 2 2016-12-01 00:00:00 2016-12-28 00:00:00 10.00 Pending
9 2 2016-12-04 00:00:00 2016-12-21 00:00:00 10.00 Approved
10 2 2016-12-09 00:00:00 2016-12-22 00:00:00 15.00 Pending
I am trying to do a count by Month/Year and I thought its working but I think its not working because of "profile_id" issue here is my query:
select monthname(date) as Month, year(date) as Year, month(date) as Mn, UNIX_TIMESTAMP(CONCAT(year(date),"-",month(date),"-","01")) as tt,
(select count(*) from outreach_links where year(outreach_links.created_at) = year and month(outreach_links.created_at) = month and status = "Pending" and created_at>="2016-12-01 00:00:00" and created_at<="2016-12-31 00:00:00") as pp,
(select count(*) from outreach_links where year(outreach_links.start_date) = year and month(outreach_links.start_date) = month and status = "Approved" and start_date>="2016-12-01 00:00:00" and start_date<="2016-12-31 00:00:00") as aa,
(select sum(cost) from outreach_links where year(outreach_links.start_date) = year and month(outreach_links.start_date) = month and status = "Approved" and start_date>="2016-12-01 00:00:00" and start_date<="2016-12-31 00:00:00") as cc
from
(select year(outreach_links.created_at) as year, month(outreach_links.created_at) as month, outreach_links.created_at as date
from outreach_links
inner join outreach on outreach.id = outreach_links.outreach_id
where outreach_links.created_at>="2016-12-01 00:00:00" and outreach_links.created_at<="2016-12-31 00:00:00" and outreach.profile_id=2
union
select year(outreach_links.start_date) as year, month(outreach_links.start_date) as month, outreach_links.start_date as date
from outreach_links
inner join outreach on outreach.id = outreach_id
where start_date>="2016-12-01 00:00:00" and start_date<="2016-12-31 00:00:00" and outreach.profile_id=2 ) t1
group by year, month
order by date
So I am doing a date range from "2016-12-01 00:00:00" to "2016-12-31 00:00:00" these could be any date range inputed by the user , and try to do a count based on outreach.profile_id = 2 , my output is wrong its counting everything for all profile_ids, I am not sure why
Note: this is just a sample of the tables , there might be more records and the user inputed Date range from to could be different , I want to group them by Month / Year
here is my output: ( its counting ALL records)
array:1 [▼
0 => {#394 ▼
+"Month": "December"
+"Year": "2016"
+"Mn": "12"
+"tt": "1480568400.000000"
+"pp": "4"
+"aa": "6"
+"cc": "285.00"
}
]
Which is wrong it should count only for profile_id=2 , here is the DESIRED output I want:
array:1 [▼
0 => {#394 ▼
+"Month": "December"
+"Year": "2016"
+"Mn": "12"
+"tt": "1480568400.000000"
+"pp": "1"
+"aa": "4"
+"cc": "265.00"
}
]
As you can see the 3 counts are wrong they suppose to be:
"pp": "1"
"aa": "4"
"cc": "265.00"
here is what I am looking for:
1). **"pp" is Total Pending** Count when status="Pending" based on created_at
2). **"aa" is Total Approved** Count when status="Approved" based on start_date
3). **"cc" is Total Cost** Sum of All cost when Status="Approved" and based on start_date
4). Group by Month & Year of the user imputed Date Range
here is a SQLFIDDLE >> http://sqlfiddle.com/#!9/87dfa8/1
can you please help me fix it?
Thanks
I think you want something like this:
SELECT MONTHNAME(d.date) AS Month
, YEAR(d.date) AS Year
, MONTH(d.date) AS Mn
, SUM(IF(l.status = 'Pending' AND l.created_at >= d.date AND l.created_at < d.date + INTERVAL 1 MONTH ,1 ,0)) AS pp
, SUM(IF(l.status = 'Approved' AND l.start_date >= d.date AND l.start_date < d.date + INTERVAL 1 MONTH ,1 ,0)) AS aa
, SUM(IF(l.status = 'Approved' AND l.start_date >= d.date AND l.start_date < d.date + INTERVAL 1 MONTH ,l.cost,0)) AS cc
FROM ( SELECT '2016-12-01' + INTERVAL 0 MONTH AS date ) d
JOIN outreach o
ON o.profile_id = 2
LEFT
JOIN outreach_links l
ON l.outreach_id = o.id
AND ( ( l.start_date >= d.date + INTERVAL 0 MONTH
AND l.start_date < d.date + INTERVAL 1 MONTH
)
OR ( l.created_at >= d.date + INTERVAL 0 MONTH
AND l.created_at < d.date + INTERVAL 1 MONTH
)
)
GROUP BY d.date
EDIT
To specify the end date of the range along with the start date, the inline view d can return two date values. And the outer query can reference the second date value, in this example d.end_date, as well as the start of the range d.date.
SELECT MONTHNAME(d.date) AS Month
, YEAR(d.date) AS Year
, MONTH(d.date) AS Mn
, SUM(IF(l.status = 'Pending' AND l.created_at >= d.date AND l.created_at < d.end_date,1 ,0)) AS pp
, SUM(IF(l.status = 'Approved' AND l.start_date >= d.date AND l.start_date < d.end_date,1 ,0)) AS aa
, SUM(IF(l.status = 'Approved' AND l.start_date >= d.date AND l.start_date < d.end_date,l.cost,0)) AS cc
FROM ( SELECT '2016-12-01' + INTERVAL 0 MONTH AS date
, '2016-12-16' + INTERVAL 0 MONTH AS end_date
) d
JOIN outreach o
ON o.profile_id = 2
LEFT
JOIN outreach_links l
ON l.outreach_id = o.id
AND ( ( l.start_date >= d.date
AND l.start_date < d.end_date
)
OR ( l.created_at >= d.date
AND l.created_at < d.end_date
)
)
GROUP BY d.date, d.end_date
I tried many way but didn't get expected result. How can I get expected result.
You can download the dbtable structure from here :-
SELECT
IF(o.source_id = 1, 'online',0) TYPE,
MONTH(date_created) AS monthvalue
,SUM(total_price) AS totalSale
FROM orders o
WHERE o.source_id = 1 AND date_created BETWEEN(CURDATE() - INTERVAL 1 MONTH)
AND CURDATE()
GROUP BY monthvalue
UNION ALL
SELECT
IF(o.source_id = 2, 'visit',0) TYPE,
MONTH(date_created) AS monthvalue
,SUM(total_price) AS totalSale
FROM orders o
WHERE o.source_id =2 AND date_created BETWEEN(CURDATE() - INTERVAL 1 MONTH)
AND CURDATE()
GROUP BY monthvalue
UNION ALL
SELECT
IF(o.source_id = 3, 'phone',0) TYPE,
MONTH(date_created) AS monthvalue
,SUM(total_price) AS totalSale
FROM orders o
WHERE o.source_id = 3 AND date_created BETWEEN(CURDATE() - INTERVAL 1 MONTH)
AND CURDATE()
GROUP BY monthvalue
Got Result :-
TYPE monthvalue totalSale
online 6 38300
visit 6 16800
phone 5 500
phone 6 7150
Expected Result :
Type May June
online 0 38300
Visit 0 16800
Phone 500 7150
According to your database schema, if you just want your expected result, please try following sql;)
select
case source_id when 1 then 'online' when 2 then 'visit' when 3 then 'phone' end as `Type`,
sum(if(month(date_created) = 5, total_price, 0)) as `May`,
sum(if(month(date_created) = 6, total_price, 0)) as `June`
from `orders`
where date_created between (curdate() - interval 1 month) and curdate()
group by source_id
SQLFiddle DEMO HERE.
I have rows like:
id, start_date, end_date
0, 2000-01-01 20:00:00, 2000-01-01 21:00:00
1, 2000-01-01 23:00:00, 2000-01-02 04:00:00
And I need get reporting result like:
date | time_online
2000-01-01 | 02:00:00
2000-01-02 | 04:00:00
My solution was wrong cos i only start_date count.
SELECT DATE_FORMAT(start_date, '%Y-%m-%d') as date,
SUM(CASE WHEN EXTRACT(DAY FROM start_date) <> EXTRACT(DAY FROM end_date)
THEN
TIMESTAMPDIFF(SECOND, start_date, DATE_FORMAT(start_date + INTERVAL 1 DAY, '%Y-%m-%d'))
ELSE
TIMESTAMPDIFF(SECOND, start_date, end_date) END) time_online
FROM online
GROUP BY date
Result:
date | time_online
2000-01-01 | 02:00:00
Can someone help me?
What you need is a (virtual) reference table with a 24 hour timespan for each date in the online table.
You can use the table itself to do that:
SELECT
DATE(start_date) + INTERVAL 0 HOUR ref_start,
DATE(start_date) + INTERVAL 24 HOUR ref_end
FROM
online
WHERE
end_date IS NOT NULL
UNION DISTINCT
SELECT
DATE(end_date) + INTERVAL 0 HOUR ref_start,
DATE(end_date) + INTERVAL 24 HOUR ref_end
FROM
online
WHERE
end_date IS NOT NULL
The + INTERVAL 0 HOUR is not really neccesary, I added that for clarity, the same goes for the DISTINCT keyword.
If you put this in a subquery then you can get with a (kind of) self-join the records with overlaps, and the calculate the difference depending on the the values:
SELECT
DATE(r.ref_start) ref_date,
SEC_TO_TIME(SUM(TIMESTAMPDIFF(SECOND,
CASE WHEN d.start_date >= r.ref_start
THEN d.start_date
ELSE r.ref_start
END,
CASE WHEN d.end_date <= r.ref_end
THEN d.end_date
ELSE r.ref_end
END))) time_online
FROM
(
SELECT
DATE(start_date) + INTERVAL 0 HOUR ref_start,
DATE(start_date) + INTERVAL 24 HOUR ref_end
FROM
online
WHERE
end_date IS NOT NULL
UNION DISTINCT
SELECT
DATE(end_date) + INTERVAL 0 HOUR ref_start,
DATE(end_date) + INTERVAL 24 HOUR ref_end
FROM
online
WHERE
end_date IS NOT NULL
) r
JOIN
online d
ON d.end_date > r.ref_start
AND d.start_date < r.ref_end
GROUP BY ref_date