I've got pretty tricky problem with MySQL.
I have two tables with one to many relation (below colums that are relevant)
Table A (campaigns):
id | channel_type | date
Table B (budgets):
id | campaign_id | budget
I need single query to fetch following result:
Campaign count by channel_type
Sum of all budgets that are related to found campaigns.
I need to filter results by columns in campaigns table (e.g. WHERE campaigns.date > '2014-05-01')
I have tried following approach:
SELECT channel_type, COUNT(*) cnt,
(SELECT SUM(budget) FROM budgets WHERE budgets.campaign_id = campaigns.id))
as budget
FROM campaigns
WHERE campaigns.date >= 'some-value'
AND [more conditions]
GROUP BY campaigns.channel_type
But this of course fails miserably because of GROUP i am getting only first campaigns.id result for channel_type.
Any tips (and solution) would be really appreciated!
TIA
Get the total budget from budgets table using GROUP BY campain_id. It will be subquery. Name it. For example, A.
Now get the total id counts from campains using GROUP BY channel_type and WHERE date>='some-value'.
Use step 2 and 1(the subquery will act as table) in the final query and you will get the results.
You can post schema and then I can check.
I think this should work :
SELECT channel_type, COUNT(*) cnt,
(SELECT SUM(t2.budget) FROM budgets t2 WHERE t2.campaign_id IN (
SELECT t3.id FROM campaigns t3 WHERE t3.channel_type = t1.channel_type))
AS budget
FROM campaigns t1
WHERE t1.date >= 'some-value'
AND [more conditions]
GROUP BY t1.channel_type
see this fiddle
I've found working solution.
Here's working query:
SELECT SUM(budget) as budget, COUNT(*) as count FROM
(SELECT * FROM campaigns WHERE [conditions]) AS found_campaigns
LEFT JOIN budgets ON budgets.campaign_id = found_campaigns.id
GROUP BY channel_type
Related
SELECT *
FROM table
INNER JOIN
(SELECT itemno, MAX(last_updated) as TopDate
FROM table
WHERE userID = 'user'
GROUP BY itemno) AS EachItem ON
EachItem.TopDate = table.last_updated
AND EachItem.itemno = table.itemno
I have taken the solution above from a previous post and modified it to work with one of the functions that I have created but I now want to use this same query but adapt it to order the result by max(last_updated) (which is a timestamp in my table) and also max(qty_sold).
Basically I have multiple duplicates of itemnos in the table but only want to return the rows with the latest date and highest qty_sold for every row where a certain user ID is specified.
Many thanks in advance, I have spent hours searching and can't figure this out as I am fairly new to mysql.
Solved my own question after more trying by adding ORDER BY qty_sold DESC to the end.
SELECT *
FROM table
INNER JOIN
(SELECT itemno, MAX(last_updated) as TopDate
FROM table
WHERE userID = 'user'
GROUP BY itemno) AS EachItem ON
EachItem.TopDate = table.last_updated
AND EachItem.itemno = table.itemno
ORDER BY qty_sold DESC
I tried to write a query, but unfortunately I didn't succeed.
I want to know how many packages delivered over a given period by a person.
So I want to know how many packages were delivered by John (user_id = 1) between 01-02-18 and 28-02-18. John drives another car (another plate_id) every day.
(orders_drivers.user_id, plates.plate_name, orders.delivery_date, orders.package_amount)
I have 3 table:
orders with plate_id delivery_date package_amount
plates with plate_id plate_name
orders_drivers with plate_id plate_date user_id
I tried some solutions but didn't get the expected result. Thanks!
Try using JOINS as shown below:
SELECT SUM(o.package_amount)
FROM orders o INNER JOIN orders_drivers od
ON o.plate_id=od.plate_id
WHERE od.user_id=<the_user_id>;
See MySQL Join Made Easy for insight.
You can also use a subquery:
SELECT SUM(o.package_amount)
FROM orders o
WHERE EXISTS (SELECT 1
FROM orders_drivers od
WHERE user_id=<user_id> AND o.plate_id=od.plate_id);
SELECT sum(orders.package_amount) AS amount
FROM orders
LEFT JOIN plates ON orders.plate_id = orders_drivers.plate_id
LEFT JOIN orders_driver ON orders.plate_id = orders_drivers.plate_id
WHERE orders.delivery_date > date1 AND orders.delivery_date < date2 AND orders_driver.user_id = userid
GROUP BY orders_drivers.user_id
But seriously, you need to ask questions that makes more sense.
sum is a function to add all values that has been grouped by GROUP BY.
LEFT JOIN connects all tables by id = id. Any other join can do this in this case, as all ids are unique (at least I hope).
WHERE, where you give the dates and user.
And GROUP BY userid, so if there are more records of the same id, they are returned as one (and summed by their pack amount.)
With the AS, your result is returned under the name 'amount',
If you want the total of packageamount by user in a period, you can use this query:
UPDATE: add a where clause on user_id, to retrieve John related data
SELECT od.user_id
, p.plate_name
, SUM(o.package_amount) AS TotalPackageAmount
FROM orders_drivers od
JOIN plates p
ON o.plate_id = od.plate_id
JOIN orders o
ON o.plate_id = od.plate_id
WHERE o.delivery_date BETWEEN convert(datetime,01/02/2018,103) AND convert(datetime,28/02/2018,103)
AND od.user_id = 1
GROUP BY od.user_id
, p.plate_name
It groups rows on user_id and plate_name, filter a period of delivery_date(s) and then calculate the sum of packageamount for the group
I use this query to summarize the contents of the table export_blocks, aggregated by user and date, and save it as a new table:
CREATE TABLE export_days
SELECT user_id DATE(submitted) AS date_str,
FROM export_blocks
GROUP BY user_id, DATE(submitted)
ORDER BY user_id, submitted
How can I, for each user_id get an incremental index for the date of records for that user? The indicies should start at 1 for each user, following the ORDER BY. I.e. I'd like to generate the date_index of the output below using SQL:
user_id date_str date_index
brian 2014-06-10 1
brian 2014-06-12 2
brian 2014-06-15 3
louis 2014-06-08 1
louis 2014-06-16 2
lucy 2013-11-15 1
(etc...)
I've been trying https://stackoverflow.com/a/5493480/1297830 but I cannot get it to work. It stops the counters prematurely, giving too low numbers for id_no and date_no.
Basing it on your sample query, you can do simple (dependent) subqueries to get the result;
SELECT id, date_str,
(SELECT COUNT(DISTINCT id)+1 FROM mytable WHERE id < a.id) id_no,
(SELECT COUNT(id)+1 FROM mytable WHERE id = a.id AND date_str < a.date_str) date_no
FROM mytable a
ORDER BY id;
...or you could do a couple of self joins;
SELECT a.id, a.date_str,
COUNT(DISTINCT b.id)+1 id_no,
COUNT(DISTINCT c.date_str)+1 date_no
FROM mytable a
LEFT JOIN mytable b ON a.id > b.id
LEFT JOIN mytable c ON a.id = c.id AND a.date_str > c.date_str
GROUP BY a.id, a.date_str
ORDER BY a.id, a.date_str;
An SQLfiddle showing both in action.
Sadly neither is really a very performant solution, but since MySQL lacks analytical (ie ranking) functions, the options are limited. Using user variables to do the ranking is also an option, however they're notoriously tricky to use and aren't portable so I'd go there only if performance demands it.
Based on Joachim's excellent answer I worked out the solution. It also works when there's multiple rows per day for each user.
CREATE TABLE export_days
SELECT
user_id, DATE(submitted) AS date_str,
(SELECT COUNT(DISTINCT DATE(submitted))+1 FROM export_blocks WHERE user_id = a.user_id AND submitted < a.submitted) date_no
FROM export_blocks a
GROUP BY user_id, DATE(submitted)
ORDER BY user_id, submitted
I have 2 tables: users_item that has 2 columns user_id, item_id and item_rates that has 2 columns rate_item_id, rate.
They are connected with Foreign_Key on users_item.item_id = item_rates.rate_item_id. I need to
select item_id's with max rate for a given range of users. One user can have a lot of items.
My select is:
SELECT MAX(rate), rate_item_id, user_id
FROM users_item JOIN item_rates ON item_id = rate_item_id
AND user_id in (2706,2979) GROUP BY user_id;
but it returns not correspondent item_id's with max rate. In given example select has to return just 2 rows. Can someone help on this. Thanks in advance.
Ok, I found what you want.. Try this:
SELECT users_item.user_id, item_id, maxrate
FROM user_items
JOIN item_rates ON users_item.item_id = item_rates.rate_item_id
JOIN (SELECT MAX(rate) AS maxrate, user_id
FROM users_item JOIN item_rates ON item_id = rate_item_id
WHERE user_id in (1,2)
GROUP BY user_id) AS maxis
ON users_item.USER_ID = maxis.USER_ID
WHERE item_rates.rate = maxrate
The reason you need a subquery is that multiple different items own by the same user could have the same rate and this could be the maximum rate of user's owned items.
Try grouping by user_id, rate_item_id
I'm surprised that MySql doesn't give you an error, Oracle would...
From joining the tables below on the entry.id, I want to extract the rows from the food_brands table which have the highest type_id - so I should be getting the top 3 rows below, with type_id 11940
food_brands
id brand type_id
15375 cesar 11940
15374 brunos 11940
15373 butchers 11940
15372 bakers 11939
15371 asda 11939
15370 aldi 11939
types
id type quantity food_id
11940 comm 53453 10497
11939 comm 999 10496
foods
id frequency entry_id
10497 twice 12230
10496 twice 12230
10495 once 12230
entries
id number
12230 26
My attempt at the query isn't filtering out the lower type.id records - so from the table records below in food_brands, i'm getting those with type_id 11940 and 11939. Grateful for any help fix this!
SELECT fb.*
FROM food_brands fb
INNER JOIN types t ON fb.type_id = t.id
INNER JOIN
(
SELECT MAX(id) AS MaxID
FROM types
GROUP BY id
) t2 ON t.food_id = t2.food_id AND t.id = t2.MaxID
INNER JOIN foods f ON t.food_id = f.id
INNER JOIN entries e ON f.entry_id = e.id
WHERE entries.id = 12230
A simple subquery should do it just fine;
SELECT * FROM food_brands WHERE type_id=
(SELECT MAX(t.id) tid FROM types t
JOIN foods f ON f.id=t.food_id AND f.entry_id=12230)
An SQLfiddle to test with.
If you just want to return the rows from food_brands with the max type id, you should be able to use:
SELECT fb.*
FROM food_brands fb
INNER JOIN
(
select max(id) id
from types
) t
on fb.type_id = t.id
See SQL Fiddle with Demo
I don't know why you are doing all these inner joins after the one on the t2 subquery, since you are only retrieving the columns of fb, but I suppose that you are not showing the whole query, and you just want to get that one fixed.
The issue is actually in the subquery t2: there, for some untold reason, you choose to do a GROUP BY id which changes the MAX function semantic to generate a maximum value per id, and since you are asking the maximum on that very column, MAX and GROUP BY cancel out each other. Just removing the GROUP BY clause fixes the query.
If for some untold reason you cannot remove that clause, perhaps replacing MAX(id) by id and adding ORDER BY id DESC LIMIT 1 would do.
Also, your subquery should probably select also food_id since it is used in the subsequent INNER JOIN clause.