Mysql complex query, group by with limit - mysql

I've the following table
store_visits: (store_id, city_id, date, visits, ...)
I want to select the maximum 5 stores ordered by visits.
SELECT X.*
FROM (
SELECT
store_id, SUM(visits) as sum_visits FROM store_visits
WHERE
(date <= '2014-06-28' AND date >= '2014-06-27')
AND
store_visits.city_id = 2
GROUP BY
store_id
ORDER BY
sum_visits desc
) X
LIMIT 5
I was wondering if there's a way to enhance the query to eleminate the temporary table and filesort.

Try this:
SELECT store_id, SUM(visits) AS sum_visits
FROM store_visits sv
WHERE sv.date <= '2014-06-28' AND sv.date >= '2014-06-27' AND sv.city_id = 2
GROUP BY store_id
ORDER BY sum_visits DESC LIMIT 5

Related

Getting all orders, where the last order ist older than a year in mySql

I have a mySQL table, which holds:
CustomerId and OrderDate
There can me multiple rows for one CustomerId
Now, I try to get the CustomerId's where only the last OrderDate is older than a year.
I try the following:
SELECT *
FROM order
WHERE OrderDate <=DATE_SUB(now(), Interval 1 Year)
GROUP BY CustomerId
ORDER BY OrderDate DESCC;
The problem here is, that I get all the rows, which are older then 1 year.
But as I said above, I try to get only the latest order, which is older than 1 year.
THX for any advise
Order the rows and limit to the last. Also, you had DESCC instead of DESC.
SELECT *
FROM order
WHERE OrderDate <=DATE_SUB(now(), Interval 1 Year)
GROUP BY CustomerId
ORDER BY OrderDate DESC
LIMIT 1;
You might also try this query:
SELECT
`CustomerId`,
`CustomerName`, // Add other fields you want returned.
MAX(`OrderDate`)
FROM `order`
WHERE `OrderDate` <= DATE_SUB(now(), Interval 1 Year)
GROUP BY `CustomerId`
ORDER BY MAX(`OrderDate`) DESC;
Also, this will return all of the related columns in the last order for each customer:
SELECT *
FROM `order` a
JOIN (
SELECT
`CustomerId`,
MAX(`OrderDate`) as `maxdate`
FROM `order`
WHERE `OrderDate` <= DATE_SUB(now(), Interval 1 Year)
GROUP BY `CustomerId`) b
ON a.`CustomerId` = b.`CustomerId` AND
a.`OrderDate` = b.`maxdate`
ORDER BY `maxdate` DESC;
Try this subquery:
select customer_id
from customer table
where order_id in(Select order_id from (select order_id from order_table (year(now())-year(order_date)) = 1 order by order_date desc limit 1))
if it doesn't work please post your table structure.
THX for all your tips.
At the end, I found my working solution:
SELECT
*
FROM order a1
INNER JOIN (SELECT
order.Id
FROM (SELECT
*
FROM (SELECT
*
FROM order
WHERE OrderDate <= DATE_SUB(NOW(), INTERVAL 1 year)
ORDER BY OrderDate DESC) AS Sub
GROUP BY Sub.CustomerId) AS a2) AS a3
ON a1.id = a3.id;

To find the maximum number of order count that occur in any 1 hour of the day from the database?

I have a food selling website in which there is order table which record the order of every user.It column for user id ,user name,orderid ,timestamp of order.I want to know the maximum number of order that has been made in any one hour span through out the day.Give me any formula for this,or any algorithm or any sql queries for these.
SQL server:
with CTE as
(
select cast(t1.timestamp as date) as o_date, datepart(hh, t1.timestamp) as o_hour, count(*) as orders
from MyTable t1
group by cast(t1.timestamp as date), datepart(hh, t1.timestamp)
)
select o_date, o_hour, orders
from CTE
where orders = (select max(orders) from CTE)
Oracle
with CTE as
(
select to_char(t1.timestamp, 'YYYYMMDD') as o_date, to_char(t1.timestamp, 'HH24') as o_hour, count(*)
from MyTable t1
group by to_char(t1.timestamp, 'YYYYMMDD'), to_char(t1.timestamp, 'HH24')
)
select o_date, o_hour, orders
from CTE
where orders = (select max(orders) from CTE)
You can get count by day and hour like this
For SQL
SELECT TOP 1
COUNT(*)
FROM myTable
GROUP BY DATEPART(day, [column_date]), DATEPART(hour, [column_date])
ORDER BY COUNT(*) DESC;
For MySQL
SELECT
COUNT(*)
FROM myTable
GROUP BY HOUR(column_date), DAY(column_date)
ORDER BY COUNT(*) DESC
LIMIT 1;

how to select with group by order by and desc?

i want to select the data in a table such that it should group it by userid except one value in that column and order by date time and desc.
The problem i am getting is the grouped items are not ordering by date and time and in desc manner.
I mean the grouped item is showing earlier row.
How can i do that.
This is what i have done.
SELECT * FROM `tbljobs`
GROUP BY user_id
UNION ALL
SELECT * FROM tbljobs
WHERE user_id = '1'
ORDER BY date_time DESC
LIMIT 20"
where '1' is should not be grouped.
Your ORDER BY is only executed on the second statement. You have to use braces to order the whole results:
(SELECT *
FROM `tbljobs`
GROUP BY user_id)
UNION ALL
(SELECT *
FROM tbljobs
WHERE user_id = '1')
ORDER BY date_time DESC
Thank you friends for your suggestions. Finally I created the solution by myself after a lot of effort.
(
SELECT *
FROM (
SELECT *
FROM tbljobs
ORDER BY date_time desc
) AS A
WHERE user_id <> '1' group by user_id
)
UNION ALL
(
SELECT *
FROM tbljobs
WHERE user_id=1
)
ORDER BY date_time DESC

Sum results of a few queries and then find top 5 in SQL

I have 3 queries:
table: pageview
SELECT event_id, count(*) AS pageviews
FROM pageview
GROUP BY event_id
ORDER BY pageviews DESC, rand()
LIMIT 1000
table: upvote
SELECT event_id, count(*) AS upvotes
FROM upvote
GROUP BY event_id
ORDER BY upvotes DESC, rand()
LIMIT 1000
table: attending
SELECT event_id, count(*) AS attendants
FROM attending
GROUP BY event_id
ORDER BY attendants DESC, rand()
LIMIT 1000
I'd like to combine the event_ids of all 3 queries ordered by amount and then choose the top 5. How do I do that?
EDIT: HERE IS WHAT I DID TO MAKE IT HAPPEN:
SELECT event_id, sum(amount) AS total
FROM (
(SELECT event_id, count(*) AS amount
FROM pageview
GROUP BY event_id
ORDER BY amount DESC, rand()
LIMIT 1000)
UNION ALL
(SELECT event_id, count(*) as amount
FROM upvote
GROUP BY event_id
ORDER BY amount DESC, rand()
LIMIT 1000)
UNION ALL
(SELECT event_id, count(*) as amount
FROM attending
GROUP BY event_id
ORDER BY amount DESC, rand()
LIMIT 1000)
) x
GROUP BY 1
ORDER BY sum(amount) DESC
LIMIT 5;
To UNION the resulting rows of all three queries and then pick the 5 rows with the highest amount:
(SELECT event_id, count(*) AS amount
FROM pageview
GROUP BY event_id
ORDER BY pageviews DESC, rand()
LIMIT 1000)
UNION ALL
(SELECT event_id, count(*)
FROM upvote
GROUP BY event_id
ORDER BY upvotes DESC, rand()
LIMIT 1000)
UNION ALL
(SELECT event_id, count(*)
FROM attending
GROUP BY event_id
ORDER BY attendants DESC, rand()
LIMIT 1000)
ORDER BY 2 DESC
LIMIT 5;
The manual:
To apply ORDER BY or LIMIT to an individual SELECT, place the
clause inside the parentheses that enclose the SELECT.
UNION ALL to keep duplicates.
To add the counts for every event_id:
SELECT event_id, sum(amount) AS total
FROM (
(SELECT event_id, count(*) AS amount
FROM pageview
GROUP BY event_id
ORDER BY pageviews DESC, rand()
LIMIT 1000)
UNION ALL
(SELECT event_id, count(*)
FROM upvote
GROUP BY event_id
ORDER BY upvotes DESC, rand()
LIMIT 1000)
UNION ALL
(SELECT event_id, count(*)
FROM attending
GROUP BY event_id
ORDER BY attendants DESC, rand()
LIMIT 1000)
) x
GROUP BY 1
ORDER BY sum(amount) DESC
LIMIT 5;
The tricky part here is that not every event_id will be present in all three base queries. So take care that a JOIN does not lose rows completely and additions don't turn out NULL.
Use UNION ALL, not UNION. You don't want to remove identical rows, you want to add them up.
x is a table alias and shorthand for AS x. It is required for for a subquery to have a name. Can be any other name here.
The SOL feature FULL OUTER JOIN is not implemented in MySQL (last time I checked), so you have to make do with UNION. FULL OUTER JOIN would join all three base queries without losing rows.
Answer to follow-up question
SELECT event_id, sum(amount) AS total
FROM (
(SELECT event_id, count(*) / 100 AS amount
FROM pageview ... )
UNION ALL
(SELECT event_id, count(*) * 5
FROM upvote ... )
UNION ALL
(SELECT event_id, count(*) * 10
FROM attending ... )
) x
GROUP BY 1
ORDER BY sum(amount) DESC
LIMIT 5;
Or, to use the base counts in multiple ways:
SELECT event_id
,sum(CASE source
WHEN 'p' THEN amount / 100
WHEN 'u' THEN amount * 5
WHEN 'a' THEN amount * 10
ELSE 0
END) AS total
FROM (
(SELECT event_id, 'p'::text AS source, count(*) AS amount
FROM pageview ... )
UNION ALL
(SELECT event_id, 'u'::text, count(*)
FROM upvote ... )
UNION ALL
(SELECT event_id, 'a'::text, count(*)
FROM attending ... )
) x
GROUP BY 1
ORDER BY 2 DESC
LIMIT 5;

MySQL count all outside limit

I have a MySQL query which counts hours we have worked from the top five of our clients. This works fine, and I am plotting the data on a graph. What I am trying to achieve is a calculation within the query that returns a sixth result set which is the sum of all the hours which are not in the top five. i.e. An 'Other' result, so that the sum of all 6 results would equal the total of sum of projects.hours.
My query:
SELECT
SUM(projects.hours) AS total_hours
FROM projects
GROUP BY projects.companyID
ORDER BY total_hours DESC
LIMIT 5
SELECT
SUM(projects.hours) AS total_hours,
(SELECT SUM(projects.hours) FROM projects) AS all_hours
FROM
projects
GROUP BY
projects.companyID
ORDER BY total_hours DESC
LIMIT 5
Subtract total_hours from all_hours in your application.
SELECT
1 no,
projects.company,
SUM(projects.hours) AS total_hours
FROM
projects
GROUP BY
projects.companyID
ORDER BY
total_hours DESC
LIMIT 5
UNION ALL
SELECT
2 no,
'Others',
SUM(projects.hours) AS total_hours
FROM
projects
WHERE projects.companyID NOT IN
( SELECT companyID
FROM
( SELECT
projects.companyID
FROM
projects
GROUP BY
projects.companyID
ORDER BY
SUM(total_hours) DESC
LIMIT 5
) AS tmp
)
How about a combination of both approaches, with the addition of a rollup we can remove the need for the IN
(I'm not sure if you can rollup with a limit though, I don't have MYSQL here so can't test, sorry)
NOTE: I would expect this to return a company id of NULL that contains the total number of other rows,
SELECT companyID,
CASE WHEN companyID IS NULL THEN
sum(Total_hours)
ELSE
sum(Total_hours) * -1
END
FROM
(
SELECT companyID,SUM(projects.hours) AS total_hours,
FROM projects
GROUP BY projects.companyID
ORDER BY total_hours DESC WITH ROLLUP LIMIT 5
UNION ALL
SELECT null,SUM(projects.hours)*-1 total_hours FROM projects
)
GROUP BY companyID