Grouping MySQL query by date range and productId - mysql

So I am trying to alter my sql code (see below for screenshot of current results + sql) to group the data by the month AND sum up all the paymentSplitAmounts. Each row should be a unique productId
So the end result would be something like
productID total month
1 500 11-2011
2 650 11-2011
3 250 11-2011
1 100 10-2011
2 150 10-2011
3 750 10-2011
I can't seem to get the syntax right. Where am I going wrong?
http://imgur.com/UC5Si
select
cpd.paymentId, cpd.paymentId, cpd.productId, cpd.paymentSplitAmount, cp.campaignId, cp.paymentDate
from campaign_payment_detail cpd
inner join
campaign_payment cp on cp.paymentId = cpd.paymentId
inner join product on cpd.productId = product.productId
where
1=1
and cp.campaignId = 2413

Looks like you want to group then sort your results:
SELECT cpd.productId, SUM(cpd.paymentSplitAmount), DATE_FORMAT(cp.paymentDate, '%b-%Y')
FROM campaign_payment_detail cpd
JOIN campaign_payment cp ON cp.paymentId = cpd.paymentId
JOIN product ON cpd.productId = product.productId
WHERE cp.campaignId = 2413
GROUP BY cpd.productId, DATE_FORMAT(cp.paymentDate, '%b-%Y')
ORDER BY cp.paymentDate DESC, cpd.productId ASC
edit: Using DATE_FORMAT to format the date like you want.

First, based on the query you provided and without other information, the table product is useless..
I will do that:
select
cpd.paymentId,
SUM(cpd.paymentSplitAmount) as total,
cp.campaignId,
cp.paymentDate
from campaign_payment_detail cpd
inner join
campaign_payment cp on cp.paymentId = cpd.paymentId
where
cp.campaignId = 2413
GROUP BY cpd.productId, cp.paymentDate
ORDER BY cpd.paymentId ASC, cp.paymentDate DESC

You already mentioned 'grouping'. For that you need to add group by to your query, to group the data by productid and month, then you can add sum to sum the paymentSplitAmount.
The grouping syntax isn't wrong, it is missing completely. :)
select
cpd.productId, sum(cpd.paymentSplitAmount) as total, date_format(cp.paymentDate, '%m-%Y')
from campaign_payment_detail cpd
inner join campaign_payment cp on cp.paymentId = cpd.paymentId
inner join product on cpd.productId = product.productId
where
cp.campaignId = 2413
group by cp.productId, date_format(cp.paymentDate, '%m-%Y')
order by date_format(cp.paymentDate, '%m-%Y') desc, cp.productId
This assumes cp.paymentDate already contains the months. If not, you will have to round each date to the first of the month and group by that.
Now groups by month.

Related

MySql sum DISTINCT after join

I have 2 table that join together ( Orders and Order_item)
When I use join I get duplicates records then I eliminate them with DISTINCT, but when I want to get sum the the shipping_price DISTINCT not works because it just eliminate the same price value and I all my prices are same I get 1 not sum !
If I don't use DISTINCT , I get rows per each items in order
SELECT sum(DISTINCT shipping_price) FROM `product_order`
INNER JOIN `product_address`
ON `product_order`.`address_id` = `product_address`.`id`
INNER JOIN `product_item`
ON `product_order`.`id` = `product_item`.`order_id`
WHERE (`status`<>2)
AND (`company_id`=1968)
AND DATE(date)='2021-08-31'
ORDER BY `product_order`.`id` DESC
how to get sum of shipping price correctly ..
data in order_table is
id shipping_price status
100
200
200
100
sum = 600 , but how to get it, if I did't DISTINCT, I get more than one row per order_items row counts that join tho order..
Use a subquery to get your shipping prices. Something like this:
SELECT product_order.id,
SUM(product_item.price * product_item.quantity) shipping_price
FROM product_order
JOIN product_item ON product_order.id = product_item.order_id
GROUP BY product_order.id
The trick here is to get a subquery that delivers exactly one row per order, with the summed-up shipping priced in it. Do your SUM() ... GROUP BY ...` in the subquery. That way you'll avoid any duplication of items.
TEST THIS before you proceed to make sure it works: giving each order id and its shipping price.
Then use it as if it were a table, JOINing it to the rest.
SELECT total.shipping_price,
product_order.id,
product_address.*
FROM product_order
JOIN product_address
ON product_order.id = product_address.order_id
JOIN (
SELECT product_order.id,
SUM(product_item.price * product_item.quantity) shipping_price
FROM product_order
JOIN product_item ON product_order.id = product_item.order_id
GROUP BY product_order.id
) total ON product_order.id = total.id
ORDER BY product_order.id = total.id
Use a subquery instead of a join.
SELECT (
select sum(shipping_price)
FROM product_item
WHERE po.`id` = `product_item`.`order_id`
) as shipping_price
FROM `product_order` po
INNER JOIN `product_address`
ON `product_order`.`address_id` = `product_address`.`id`
WHERE (`status`<>2)
AND (`company_id`=1968)
AND DATE(date)='2021-08-31'
ORDER BY `product_order`.`id` DESC

Calculating Checkout Conversion using MySQL

I am trying to calculate the checkout conversion by using the following query but I keep getting error:
SELECT
(SELECT seller.name, count(checkout.id) AS 'Completed_checkout'
FROM checkout
JOIN seller
ON seller.id = checkout.seller_id
WHERE checkout.completed = 1
GROUP BY seller.name)
/
(SELECT seller.name, count(checkout.id) AS 'Total_Checkouts'
FROM checkout
JOIN seller
ON seller.id = checkout.seller_id
GROUP BY seller.name) * 100
AS 'Checkout_Converstion';
The end goal after being able to calculate it is:
filter by seller with more than 15 checkouts total
order it by DESC
limit it by then 5 first records
Any ideas on how to make this work?
How about simplifying this?
SELECT s.name, AVG(co.completed) as completed_ratio
FROM checkout co JOIN
seller s
ON s.id = co.seller_id
GROUP BY s.name;
If you want the counts:
SELECT s.name, AVG(co.completed = 1) as completed_ratio,
SUM(c.completed = 1) as num_completed,
COUNT(*) as total
FROM checkout co JOIN
seller s
ON s.id = co.seller_id
GROUP BY s.name;
These make use of the fact that MySQL treats boolean expressions as numbers in a numeric context -- with "1" for true and "0" for false.
You can do it with 1 query:
SELECT s.name,
100 * AVG(c.completed) AS Checkout_Conversion
FROM checkout c JOIN seller s
ON s.id = c.seller_id
GROUP BY s.id, s.name
HAVING SUM(c.completed) > 15
ORDER BY Checkout_Conversion DESC
LIMIT 5

MySQL GROUP BY grouping by lowest field value

I'm trying to fetch the lowest price per day per hotel, I get multiple results.
I first try to fetch the lowest amount with the MIN() function, then inner join.
When i later try to group by outside the subquery, it just groups by the lowest id.
The SQL itself:
SELECT mt.id, mt.amount, mt.fk_hotel, mt.start_date
FROM price mt
INNER JOIN
(
SELECT price.id, MIN(price.amount) minAmount
FROM price
WHERE 1=1 AND price.start_date >= '2014-10-08' AND price.start_date <= '2014-10-10' AND price.active = 1 AND price.max_people = 2
GROUP BY id
) t
ON mt.id = t.id AND mt.amount = t.minAmount
ORDER BY mt.fk_hotel, mt.amount;
And the results looks like this:
http://jsfiddle.net/63mg3b2j/
I want to group by the start date and fk_hotel so that it groups by the lowest amount value, can anybody help me? Am I being clear?
Edit: I also need a field fk_room from the corresponding row, so i can inner join
Try this:
SELECT MIN(mt.amount) AS min_amount, mt.fk_hotel, mt.start_date
FROM price mt
WHERE
mt.active = 1 AND
mt.max_people = 2 AND
mt.start_date >= '2014-10-08' AND mt.start_date <= '2014-10-10'
GROUP BY mt.fk_hotel, mt.start_date
ORDER BY mt.fk_hotel, min_amount;
Well first of all get a table with minimum value in top row using ORDER BY and then GROUP BY for your required result
SELECT mt.id, mt.amount, mt.fk_hotel, mt.start_date
FROM
(SELECT id, amount, fk_hotel, start_date
FROM price
WHERE start_date >= '2014-10-08' AND start_date <= '2014-10-10'
AND active = 1 AND max_people = 2
ORDER BY amount DESC) AS mt
GROUP BY mt.id
Well I had to still go with a subquery, cause i needed some additional foreign key fields from the corresponding row to inner join some other stuff. It isn't a great solution, cause it fetches too much stuff, the rest is filtered out programmatically.
The most annoying thing here, when I try to use MIN() or MAX() function and get the appropriate fields to that row, it fetches the first results from the DB, which are incorrect and so i have to use a subquery to inner join to get the other fields, I can use grouping, but I had too many fields to group. Maybe I'm missing something. The amount of data doesn't grow in time, so I guess it works for me. So this is the final SQL i came up with, for future reference..
SELECT mt.*, roomtype.name roomname, hotel.name hotelname
FROM booking.price mt
INNER JOIN roomtype ON roomtype.id = mt.fk_roomtype
INNER JOIN hotel ON hotel.id = mt.fk_hotel
INNER JOIN(
SELECT price.id, MIN(price.amount) minAmount
FROM booking.price WHERE 1=1 AND price.start_date >= '2014-10-22' AND price.start_date <= '2014-10-31' AND price.max_people = 2 AND price.active = 1
GROUP BY id
) t
ON mt.id = t.id AND mt.amount = t.minAmount
ORDER BY mt.start_date, mt.amount

Need Help Combining Two MySQL Queries

I'm not amazing at SQL and can't figure out how to do this. Here are the two queries I have at the moment.
SELECT TicketID_PK, SubProjectID_FK, ProjectID_FK, CustomerID_FK, TicketDate, TicketNumber,
SignOff, WorkOrder, ClientPO, TicketType, Description, Processed
FROM Tickets
INNER JOIN CustomersSubProjects ON Tickets.SubProjectID_FK = CustomersSubProjects.SubProjectID_PK
INNER JOIN CustomersProjects ON CustomersSubProjects.ProjectID_FK = CustomersProjects.ProjectID_PK
WHERE TicketID_PK = 1
SELECT ROUND(WCB+Vacation+Stat+UIC+CPP+Overhead,2) AS Total
FROM EmployeeFormula
WHERE EffectiveDate <= $TicketDate
ORDER BY EffectiveDate DESC LIMIT 1
I'm saving TicketDate as $TicketDate and using it in the second query, but I'm sure there is a way to combine the two queries to avoid this. Any help would be appreciated.
Edit: I need to select the EmployeeFormula Total (as shown in second query) by comparing the TicketDate column (in the Tickets table) to the EffectiveDate column. So the results should look like this:
TicketID_PK SubProjectID_FK ProjectID_FK CustomerID_FK TicketDate TicketNumber Total
1 1 1 1 2014-01-05 1-0501-00 30.78
Use like a subquery.
SELECT TicketID_PK, SubProjectID_FK, ProjectID_FK, CustomerID_FK, TicketDate, TicketNumber,
SignOff, WorkOrder, ClientPO, TicketType, Description, Processed, (SELECT ROUND(WCB+Vacation+Stat+UIC+CPP+Overhead,2) FROM EmployeeFormula WHERE EffectiveDate <= TicketDate ORDER BY EffectiveDate DESC LIMIT 1) AS Total
FROM Tickets
INNER JOIN CustomersSubProjects ON Tickets.SubProjectID_FK = CustomersSubProjects.SubProjectID_PK
INNER JOIN CustomersProjects ON CustomersSubProjects.ProjectID_FK = CustomersProjects.ProjectID_PK
WHERE TicketID_PK = 1

Mysql count() fetches wrong result

I am trying to find the number of records for current week.
My current query is:
SELECT Week(Str_to_date(products_options_values, '%m-%d-%Y'), 1) AS order_week,
Year(Str_to_date(products_options_values, '%m-%d-%Y')) AS order_year,
order_active,
Count(op.sub_order_id) AS deliveries
FROM orders_products_attributes opa
LEFT JOIN orders_products op
ON ( opa.orders_products_id = op.orders_products_id )
GROUP BY order_week,
order_year
HAVING order_week = '31'
AND order_year >= '2013'
AND order_active = 0
ORDER BY order_week
It fetches deliveries AS 2 where as there are actually 4 records, and if I run the same query after removing COUNT and GROUP BY, it correctly shows all 4 rows. The same problem happens on other weeks too, for example week 34 has 3 records, but the above query fetches it as 4 instead. Moreover, another weird thing is, in the GROUP BY clause, if I remove either one of order_week or order_year the query returns an empty result set.
Any idea what I am doing wrong?
Try to move all HAVING conditions into WHERE. Also Count(id) - counts UNIQUE values of ID not all. If you need all records count just use COUNT(*)
SELECT Week(Str_to_date(products_options_values, '%m-%d-%Y'), 1) AS order_week,
Year(Str_to_date(products_options_values, '%m-%d-%Y')) AS order_year,
order_active,
Count(op.sub_order_id) AS deliveries
FROM orders_products_attributes opa
LEFT JOIN orders_products op
ON ( opa.orders_products_id = op.orders_products_id )
WHERE order_week = '31'
AND order_year >= '2013'
AND order_active = 0
GROUP BY order_week,
order_year
ORDER BY order_week