I have table structure as follows
id productid ip hittime
---------------------------------------------------------------------------
1 5 1.1.1.1 2011-05-03 06:55:11
2 5 1.1.1.1 2011-05-03 06:57:11
3 6 2.2.2.2 2011-05-03 07:30:00
4 4 1.1.1.1 2011-05-03 07:32:54
5 5 2.2.2.2 2011-05-03 07:55:00
Now I need query such that, it output me total and unique hits for each product
productid totalhits uniquehits
------------------------------------------------------------------
4 1 1
5 3 2
6 1 1
Criteria for
Total Hits = all the records that belong to particular product
Unique Hits = 2 hits are identified as unique hits if (1) IP is different or (2) for same ip, there is difference of 5 mins in hittime
How can I achieve this?
rMX was extremely close with his solution, it's quite clever. He should really get the credit, I just tweaked it slightly to add in a couple missing pieces:
select productid, count(*) totalhits,
count(distinct
concat(ip,
date_format(hittime, '%Y%m%d%H'),
round(date_format(hittime, '%i') / 5) * 5)
) uniquehits
from table
group by productid
Changes I made to rMX's idea:
Changed ceil() to round() because
ceil/floor will cause edge cases to
be treated improperly
Multiply the results of the round()
by 5. I think rMX meant to do this
and just forgot to type it.
EDIT: The multiplying by 5 really isn't necessary. My brain was just muddled. Changing ceil() to round() still matters though.
UPD>
select productid, count(*) totalhits,
count(distinct
concat(ip,
date_format(hittime, '%Y%m%d%H'),
ceil(date_format(hittime, '%i') / 5))
) uniquehits
from table
group by productid
I think, this should work. Sorry, had no time to test it.
Related
I have been at this for a few days without much luck and I am looking for some guidance on how to get the lowest estimate from a particular group of sullpiers and then place it into another table.
I have 4 supplier estimate on every piece of work and all new estimates go into a single table, i am trying to find the lowest 'mid' price from the 4 newsest entries in the 'RECENT QUOTE TABLE' with a group id of '1' and then place that into the 'LOWEST QUOTE TABLE' as seen below.
RECENT QUOTE TABLE:
suppid group min mid high
1 1 200 400 600
2 1 300 500 700
3 1 100 300 500
[4] [1] 50 [150] 300
5 2 1000 3000 5000
6 2 3000 5000 8000
7 2 2000 4000 6000
8 2 1250 3125 5578
LOWEST QUOTE TABLE:
suppid group min mid high
4 1 50 150 300
Any help on how to structure this would be great as i have been loking for a few days and have not been able to find anything to get me moving again, im using MYSQL and the app is made in Python im open to all suggestions.
Thanks in advance.
If you really want to select only row with group 1, you can do something like
INSERT INTO lowest_quote_table
SELECT * FROM recent_quote_table
WHERE `group` = 1
ORDER BY `mid` ASC
LIMIT 1.
If you want a row with the lowest mid from every group, you can do something like
INSERT INTO lowest_quote_table
SELECT rq.* FROM recent_quote_table AS rq
JOIN (
SELECT `group`, MIN(`mid`) AS min_mid FROM recent_quote_table
GROUP BY `group`
) MQ ON rq.`group` = MQ.`group` AND rq.`mid` = MQ.min_mid
I have a table with the following information:
Table: bar
minute | beer
1 | 48
2 | 24
3 | 92
4 | 17
5 | 38
6 | 64
I want to know what or where the biggest difference is in the column beer. By manually seeing it with my own eyes, it's between minute 3 and 4, but how can I do this in SQL?
I had something in mind:
Select minute, count(beer) as spike
from bar
where ???
You need nested aggregation:
select max(spike) - min(spike)
from
( -- count per minute
Select minute, count(beer) as spike
from bar
group by minute
) as dt
The simplest method would be:
select max(beer) - min(beer)
from bar;
You can use mysql MAX() and MIN() functions to get highest and lowest values.
SELECT MIN(beer) AS lowestBeer, MAX(beer) as highestBeer
FROM bar;
Since the order does not matter, you can do it with a self-join:
SELECT a.minute AS from_minute, b.minute AS to_minute, a.beer, b.beer
FROM bar a
CROSS JOIN bar b
ORDER BY a.beer-b.beer DESC
LIMIT 1
This would yield a row describing from what minute to what minute you have the biggest difference, along with the corresponding values of beer.
I normally work in Access but cannot figure this logic within it. I'm now branching to MySQL in hopes i can do this.
Have table Visits with CUSTOMERID, VISITDATE
CUSTOMERID VISITDATE
1001 7/6/2015
2315 9/1/2015
2315 12/30/2014
9851 5/5/2013
9851 1/7/2014
9851 3/21/2014
I'd like to add a column called 'Visit Number' so I can label in ascending order each Customer's visitdate as his first, second, etc...
It would look like:
CUSTOMERID VISITDATE VISITNUMBER
1001 7/6/2015 1
2315 9/1/2015 1
2315 12/30/2014 2
9851 5/5/2013 1
9851 1/7/2014 2
9851 3/21/2014 3
It's an incrementation based on the ascending dates, but also grouped by CUSTOMERID.
Would seriously appreciate any tips on this. Thanks.
OK. So you have a query that you use to update your date whenever someone visits.
You want to cause an additional action at this point because this equates to an increment of visits.
if I'm not incorrect, a simple bundle of:
YOUR UPDATE SQL;
UPDATE mytable
SET visitnumber = visitnumber + 1
WHERE customerid = (the id of the user you are updating);
I found it hard to find a fitting title. For simplicity let's say I have the following table:
cook_id cook_rating
1 2
1 1
1 3
1 4
1 2
1 2
1 1
1 3
1 5
1 4
2 5
2 2
Now I would like to get an output of 'good' cooks. A good cook is someone who has a rating of at least 70% of 1, 2 or 3, but not 4 or 5.
So in my example table, the cook with id 1 has a total of 10 ratings, 7 of which have type 1, 2 and 3. Only three have type 4 or 5. Therefore the cook with id 1 would be a 'good' cook, and the output should be the cook's id with the number of good ratings.
cook_id cook_rating
1 7
The cook with id 2, however, doesn't satisfy my condition, therefore should not be listed at all.
select cook_id, count(cook_rating) - sum(case when cook_rating = 4 OR cook_rating = 5 then 1 else 0 end) as numberOfGoodRatings from cook
where cook_rating in (1,2,3,4,5)
group by cook_id
order by numberOfGoodRatings desc
However, this doesn't take into account the fact that there might be more 4 or 5 than good ratings, resulting in negative outputs. Plus, the requirement of at least 70% is not included.
You can get this with a comparison in your HAVING clause. If you must have just the two columns in the result set, this can be wrapped as a sub-select select cook_id, positive_ratings FROM (...)
SELECT
cook_id,
count(cook_rating < 4 OR cook_rating IS NULL) as positive_ratings,
count(*) as total_ratings
FROM cook
GROUP BY cook_id
HAVING (positive_ratings / total_ratings) >= 0.70
ORDER BY positive_ratings DESC
Edit Note that count(cook_rating < 4) is intended to only count rows where the rating is less than 4. The MySQL documentation says that count will only count non-null rows. I haven't tested this to see if it equates FALSE with NULL but I would be surprised it it doesn't. Worst case scenario we would need to wrap that in an IF(cook_rating < 4, 1,NULL).
I suggest you change a little your schema to make this kind of queries trivial.
Suppose you add 5 columns to your cook table, to simply count the number of each ratings :
nb_ratings_1 nb_ratings_2 nb_ratings_3 nb_ratings_4 nb_ratings_5
Updating such a table when a new rating is entered in DB is trivial, just as would be recomputing those numbers if having redundancy makes you nervous. And it makes all filterings and sortings fast and easy.
I need help with a MySQL query. We have a database (~10K rows) which I have simplified down to this problem.
We have 7 truck drivers who visit 3 out of a possible 9 locations, daily. Each day they visit exactly 3 different locations and each day they can visit different locations than the previous day. Here are representative tables:
Table: Drivers
id name
10 Abe
11 Bob
12 Cal
13 Deb
14 Eve
15 Fab
16 Guy
Table: Locations
id day address driver.id
1 1 Oak 10
2 1 Elm 10
3 1 4th 10
4 1 Oak 16
5 1 4th 16
6 1 Toy 16
7 1 Toy 11
8 1 5th 11
9 1 Law 11
10 2 Oak 11
11 2 4th 11
12 2 Toy 11
.........
We have data for a full year and we need to find out how many times each "route" is visited over a year, sorted from most to least.
From my high school math, I believe there are 9!/(6!3!) route combinations, or 84 in total. I want do something like:
Get count of routes where route addresses = 'Oak' and 'Elm' and '4th'
then run again
where route addresses = 'Oak' and 'Elm' and '5th'
then again and again, etc.Then sort the route counts, descending. But I don't want to do it 84 times. Is there a way to do this?
I'd be looking at GROUP_CONCAT
SELECT t.day
, t.driver
, GROUP_CONCAT(t.address ORDER BY t.address)
FROM mytable t
GROUP
BY t.day
, t.driver
What's not clear here, if there's an order to the stops on the route. Does the sequence make a difference, and how to we tell what the sequence is? To ask that a different way, consider these two routes:
('Oak','Elm','4th') and ('Elm','4th','Oak')
Are these equivalent (because it's the same set of stops) or are they different (because they are in a different sequence)?
If sequence of stops on the route distinguishes it from other routes with the same stops (in a different order), then replace the ORDER BY t.address with ORDER BY t.id or whatever expression gives the sequence of the stops.
Some caveats with GROUP_CONCAT: the maximum length is limited by the setting of group_concat_max_len and max_allowed_packet variables. Also, the comma used as the separator... if we combine strings that contain commas, then in our result, we can't reliably distinguish between 'a,b'+'c' and 'a'+'b,c'
We can use that query as an inline view, and get a count of the the number of rows with identical routes:
SELECT c.route
, COUNT(*) AS cnt
FROM ( SELECT t.day
, t.driver
, GROUP_CONCAT(t.address ORDER BY t.address) AS route
FROM mytable t
GROUP
BY t.day
, t.driver
) c
GROUP
BY c.route
ORDER
BY cnt DESC