SQL: Changing structure of query - mysql

I have a query which successfully returns a single value where "day" is hardcoded in the query, as below:
SELECT MAX(theCount) FROM
(SELECT FK_Hour, Count(FK_Hour) As theCount FROM
(Select FK_Hour
From slottime
INNER JOIN time ON slottime.FK_Hour = time.Hour
WHERE FK_Hour IN
(SELECT time.Hour FROM time WHERE time.day=0 )
) As C
GROUP By FK_Hour
) AS counts;
I'm trying to remove this hardcoding such that two columns; namely
day:theCount are returned.
I have tried
SELECT MAX(theCount), day FROM
(SELECT FK_Hour, day As day, Count(FK_Hour) As theCount FROM
(Select slottime.FK_Hour, time.day
From slottime
INNER JOIN time ON slottime.FK_Hour = time.Hour
) As C
GROUP By FK_Hour
) AS counts
GROUP By day;
and it executes. However the values it returns are obviously incorrect (no obvious correlation to the data in the tables being queried)

In the first example, if I am reading this right, you are getting the count of records for day = 0 for each fk_hour value, and selecting the max count from that.
To do this for all days, start by writing an aggregation query to get the count of each day and hour pair like this:
SELECT t.day, t.hour, COUNT(*) AS numRecords
FROM time t
GROUP BY t.day, t.hour;
Once you have that, you can get the maximum value by using limit 1:
SELECT t.day, t.hour, COUNT(*) AS numRecords
FROM time t
GROUP BY t.day, t.hour
ORDER BY COUNT(*) DESC
LIMIT 1;
This query will return one row, and tell you at which day and which hour the highest number of records occurred.

Related

Getting the last and oldest price of a grouped row

I have this query and I want to select the currentprice(the most current price sorted by time) and the oldprice(the last row sorted by time) in the same columns per row. I figured out how to select the currentprice but how can I select both in the same query?
In the end I want to make a calculation for the percentage of gain or drop with ROUND((latestprice - oldprice) / oldprice * 100, 2) as gain_ratio
WITH tmp AS (
SELECT TrackID, ID, price, MAX(Time) as maxtime, MIN(Time) as mintime
FROM track
WHERE Time > NOW() - INTERVAL 1 HOUR
GROUP BY ID
)
SELECT T.TrackID, T.ID, tmp.Price as currentprice, T.Time
FROM track AS T
JOIN tmp ON T.ID = tmp.ID
WHERE T.Time = tmp.maxtime;
I'm really struggeling to grasp how to make a CTE query, I have read the documentation several times
Have you tried to change your where clause to...?:
WHERE T.Time = tmp.maxtime or T.Time = tmp.mintime

How to find which year do values tend to increase in ? in SQL

Basically I have a table like this:
Table Time:
ID.......Date
1......08/26/2016
1......08/26/2016
2......05/29/2016
3......06/22/2016
4......08/26/2015
5......05/23/2015
5......05/23/2015
6......08/26/2014
7......04/26/2014
8......08/26/2013
9......03/26/2013
The query should return like this
Year........CountNum
2016........4
2015........3
To find out which year does its value tend to increase in. I notice that I want to display the years that have more values (number of row in this case) than the previous year.
What I've done so far
SELECT Year, count(*) as CountNum
FROM Time
GROUP BY Year
ORDER BY CountNum DESC;
I don't know how to get the year from date format. I tried year(Date) function, but I got Null data.
Please help!
It should works fine.
select year(date), count(*) as countNum
from time
group by year(date)
order by countNum
Join the grouped data to itself with 1 year offset:
select
a.*
from
(
select year(`Date`) as _year, count(*) as _n
from time group by 1
) a
left join
(
select year(`Date`) as _year, count(*) as _n
from time group by 1
) b
on a._year = b._year-1
where a._n > b._n
order by 1

How to Group a table and get results for a row based on the previous rows' data

I have a lookup table that relates dates and people associated with those dates:
id, user_id,date
1,1,2014-11-01
2,2,2014-11-01
3,1,2014-11-02
4,3,2014-11-02
5,1,2014-11-03
I can group these by date(day):
SELECT DATE_FORMAT(
MIN(date),
'%Y/%m/%d 00:00:00 GMT-0'
) AS date,
COUNT(*) as count
FROM user_x_date
GROUP BY ROUND(UNIX_TIMESTAMP(created_at) / 43200)
But, how can get the number of unique users, that have now shown up previously? For instance this would be a valid result:
unique, non-unique, date
2,0,2014-11-01
1,1,2014-11-02
0,1,2014-11-03
Is this possibly without having to rely on a scripting language to keep track of this data?
I think this query will do what you want, at least it seems to work for your limited sample data.
The idea is to use a correlated sub-query to check if the user_id has occurred on a date before the date of the current row and then do some basic arithmetic to determine number of unique/non-unique users for each date.
Please give it a try.
select
sum(u) - sum(n) as "unique",
sum(n) as "non-unique",
date
from (
select
date,
count(user_id) u,
case when exists (
select 1
from Table1 i
where i.user_id = o.user_id
and i.date < o.date
) then 1 else 0
end n
from Table1 o
group by date, user_id
) q
group by date
order by date;
Sample SQL Fiddle
I didn't include the id column in the sample fiddle as it's not needed (or used) to produce the result and won't change anything.
This is the relevant question: "But, how can get the number of unique users, that have now shown up previously?"
Calculate the first time a person shows up, and then use that for the aggregation:
SELECT date, count(*) as FirstVisit
FROM (SELECT user_id, MIN(date) as date
FROM user_x_date
GROUP BY user_id
) x
GROUP BY date;
I would then use this as a subquery for another aggregation:
SELECT v.date, v.NumVisits, COALESCE(fv.FirstVisit, 0) as NumFirstVisit
FROM (SELECT date, count(*) as NumVisits
FROM user_x_date
GROUP BY date
) v LEFT JOIN
(SELECT date, count(*) as FirstVisit
FROM (SELECT user_id, MIN(date) as date
FROM user_x_date
GROUP BY user_id
) x
GROUP BY date
) fv
ON v.date = fv.date;

MYSQL return 0 on hourly count

I am at a loss of how to accomplish this but have seen online ISNULL() and COALESCE() used to return a zero if the query is null. I am unsure though how to use it properly though I am intuitively thinking i need to have in a subquery then have ISNULL or COALESCE around that subquery?
The query goes:
SELECT HOUR( dateAdded ) AS HOUR , COUNT( DISTINCT remoteAddr, xForwardedFor) AS cnt
FROM Track
WHERE accessMask = '1iczo'
AND destination = 'lp_include.php'
AND dateAdded
BETWEEN '2014-05-01'
AND '2014-05-02'
GROUP BY HOUR
ORDER BY HOUR
Some help in the right direction would be greatly appreciated!
UPDATE
I used what #Barmar had suggested but it wasn't returning accurate results. I used what he provided and also another topic with a similar situation, Group by should return 0 when grouping by hours. How to do this? . I actually didn't find this topic till after posting this one, :( unfortunately. Here is the final code that appears to return accurate results, distinct across two columns with empty data being returned as 0.
SELECT a.hour, COALESCE(cnt, 0) AS cnt
FROM (SELECT 0 AS hour
UNION ALL
SELECT 1
UNION ALL
SELECT 2 .....
UNION ALL
SELECT 23) a
LEFT JOIN
(SELECT COUNT(DISTINCT remoteAddr, xForwardedFor) AS cnt, HOUR(dateAdded) AS hour
FROM Track
WHERE accessMask = '1iczo'
AND destination = 'lp_include.php'
AND dateAdded
BETWEEN '2014-05-01 00:00:00' AND '2014-05-01 23:59:59') AS totals
ON a.hour = totals.hour
Fiddle for better reference: http://sqlfiddle.com/#!2/9ab660/7
Thanks again to #Barmar, he really put me in the right direction to get to the solution!
You have to join with a table that contains all the hours. This must be a LEFT JOIN so that the results will include hours that have no matches in Track table.
SELECT allHours.hour, IFNULL(cnt, 0) AS cnt
FROM (SELECT 0 AS hour
UNION
SELECT 1
UNION
SELECT 2
UNION
SELECT 3
...
UNION
SELECT 23) AS allHours
LEFT JOIN
(SELECT HOUR(dateAdded) AS hour, COUNT(DISTINCT remoteAddr, xForwardedFor) AS cnt
FROM Track
WHERE accessMask = '1iczo'
AND destination = 'lp_include.php'
AND dateAdded
BETWEEN '2014-05-01' AND '2014-05-02') AS totals
ON allHours.hour = totals.hour
If you assume that you have some data for every hour, you can move the conditional part into the select:
SELECT HOUR(dateAdded) AS HOUR ,
COUNT(DISTINCT CASE WHEN accessMask = '1iczo' AND destination = 'lp_include.php'
THEN CONCAT(remoteAddr, ',', xForwardedFor)
END) AS cnt
FROM Track
WHERE dateAdded BETWEEN '2014-05-01' AND '2014-05-02'
GROUP BY HOUR
ORDER BY HOUR;

How to get zero values on query result grouped by month, if it doesn't contain any records

I've got IP address, email address and date in table. I need to find out how many mails was sent (grouped by IP and email together) during each month of each year (so group by month and year to). Tricky part is, that if no mail was sent, I need to get zero value on results (now I don't get empty rows). How can I do that?
Select distinct X.Sender, X.IP, MONTH(s.date) as Month, YEAR (s.date) as Year, Count(s.ID)
From
(
Select TOP 10 a.Sender, a.SenderIP as IP, COUNT(a.ID) as C
From AMA a Where a.Summary = 'SPAM'
Group by a.Sender, a.SenderIP
Order by C desc
)As X left outer join AMAs
on X.Sender = s.Sender and X.IP = s.SenderIP
Where s.Summary = 'SPAM'
Group by X.Sender, X.IP, YEAR(s.date), MONTH(s.date)
Order by X.Sender,X.IP,YEAR(s.date) asc, Month(s.date) asc`
The way to do this is to OUTER JOIN from a set of months onto your existing resultset. This way, all months with data will be present, and any months without data will have empty values.
You could create a table with that information, or you could use a CTE.
DECLARE #firstDate DATE = '2010-01-01';
WITH Months (fulldate) AS
(
SELECT #firstdate
UNION ALL
SELECT DATEADD(MONTH, 1, fulldate)
FROM Months
WHERE fulldate < GETDATE()
)
SELECT
m.*, q.*
FROM Months m
LEFT OUTER JOIN
(
-- your existing query
) q
ON q.[Year] = DATEPART(YEAR, fulldate)
AND q.[Month] = DATEPART(MONTH, fulldate)
-- you may need to increase the max recursion, if you want more than 100 months...
-- OPTION (MAXRECURSION 1000)