SQL group by dates, simple select statement - mysql

INTRO: Given a table with a column 'time' of unique dates(or datetime) and another column with some random integer called 'users'.
I usually do a call as such:
select table.dates, count(table.dates)
from table
group by year(table.dates), month(table.dates)
order by table.dates desc
which will return the number of users per month, albeit in an unformatted way. (I know it's not the standard way, but I check my values and this seems to work)
Here is my problem:
DATA: a table with with non-unique year/month dates, and a corresponding user count on that row.
PROBLEM: I wish to sum the user counts for identical dates, and again show a user count for every month.
EDIT: Perhaps you can ignore the INTRO, and here is an example of the data I need to work with:
| Date |user count |
----------------------.-
|2015-01 | 9 |
|2014-09 | 5 |
|2014-09 | 2 |
|2014-08 | 5 |
|2014-09 | 7 |
|2014-08 | 2 |
|2014-07 | 3 |

Related

Need an aggregate MySQL select that iterates virtually across date ranges and returns bills

I have a MySQL table named rbsess with columns RBSessID (key), ClientID (int), RBUnitID (int), RentAmt (fixed-point int), RBSessStart (DateTime), and PrevID (int, references to RBSessID).
It's not transactional or linked. What it does track when a client was moved into a room and what the rent at the time of move in was. The query to find what the rent was for a particular client on a particular date is:
SET #DT='Desired date/time'
SET #ClientID=Desired client id
SELECT a.RBSessID
, a.ClientID
, a.RBUnitID
, a.RentAmt
, a.RBSessStart
, b.RBSessStart AS RBSessEnd
, a.PrevID
FROM rbsess a
LEFT
JOIN rbsess b
ON b.PrevID=a.RBSessID
WHERE a.ClientID=#ClientID
AND (a.RBSessStart<=#DT OR a.RBSessStart IS NULL)
AND (b.RBSessStart>#DT OR b.RBSessStart IS NULL);
This will output something like:
+----------+----------+----------+---------+---------------------+-----------+--------+
| RBSessID | ClientID | RBUnitID | RentAmt | RBSessStart | RBSessEnd | PrevID |
+----------+----------+----------+---------+---------------------+-----------+--------+
| 2 | 4 | 1 | 57500 | 2020-11-22 00:00:00 | NULL | 1 |
+----------+----------+----------+---------+---------------------+-----------+--------+
I also have
SELECT * FROM rbsess WHERE rbsess.ClientID=#ClientID AND rbsess.PrevID IS NULL; //for finding the first move in date
SELECT TIMESTAMPDIFF(DAY,#DT,LAST_DAY(#DT)) AS CountDays; //for finding the number of days until the end of the month
SELECT DAY(LAST_DAY(#DT)) AS MaxDays; //for finding the number of days in the month
SELECT (TIMESTAMPDIFF(DAY,#DT,LAST_DAY(#DT))+1)/DAY(LAST_DAY(#DT)) AS ProRateRatio; //for finding the ratio to calculate the pro-rated rent for the move-in month
SELECT ROUND(40000*(SELECT (TIMESTAMPDIFF(DAY,#DT,LAST_DAY(#DT))+1)/DAY(LAST_DAY(#DT)) AS ProRateRatio)) AS ProRatedRent; //for finding a pro-rated rent amount based on a rent amount.
I'm having trouble putting all of these together to form a single query that can output pro-rated and full rent amounts based on a start date and an optional end date all rent owed amounts in a single statement for each month in the period. I can add a payments table received and integrate it afterwards, just having a hard time with this seemingly simple real-world concept in a MySQL query. I'm using php with a MySQL back end. Temporary tables as intermediary queries are more than acceptable.
Even a nudge would be helpful. I'm not super-experienced with MySQL queries, just your basic CREATE, SELECT, INSERT, DROP, and UPDATE.
Examples as requested by GMB:
//Example data in rbsess table:
+----------+----------+----------+---------+---------------------+--------+
| RBSessID | ClientID | RBUnitID | RentAmt | RBSessStart | PrevID |
+----------+----------+----------+---------+---------------------+--------+
| 1 | 4 | 1 | 40000 | 2020-10-22 00:00:00 | NULL |
| 2 | 4 | 1 | 57500 | 2020-11-22 00:00:00 | 1 |
| 3 | 2 | 5 | 40000 | 2020-11-29 00:00:00 | NULL |
+----------+----------+----------+---------+---------------------+--------+
Expected results would be a list of the rent amounts owed for every month, including pro-rated amounts for partial occupancy in a month, from a date range of months. For example for the example data above for a date range spanning all of the year of 2020 from client with ClientID=4 the query would produce an amount for each month within the range similar to:
Month | Amt
2020-10-1 | 12903
2020-11-1 | 45834
2020-12-1 | 57500

count groupings of multiple columns

I have a table of tickets to multiple dates of shows shows. basically, it looks like this...
+----+---------------+--------------+-----------+
| ID | ticket_holder | ticket_buyer | show_date |
+----+---------------+--------------+-----------+
ticket_holder and ticket_buyer are both user ids
If I wanted to count the total number of tickets that one ticket holder has, I could group by that holder and count the rows, but I want more stats than that.
I want to know a user's total bought tickets, how many they hold and how many shows they've bought tickets for.
+------+---------+--------+-------+
| USER | HOLDING | BOUGHT | DATES |
+------+---------+--------+-------+
| 1 | 12 | 24 | 7 |
+------+---------+--------+-------+
| 2 | 3 | 4 | 2 |
+------+---------+--------+-------+
| 3 | 1 | 2 | 1 |
+------+---------+--------+-------+
is it possible to put all this in a query, or do i need to do php stuff to make it happen?
I would do it in multiple queries. You can't group by either ticket_holder or ticket_buyer like you want, in a single query. If you try GROUP BY ticket_holder, ticket_buyer then it will group by both columns, which is not what you want.
SELECT ticket_holder, COUNT(*) AS tickets_held
FROM `a table of tickets` GROUP BY ticket_holder;
SELECT ticket_buyer, COUNT(*) as tickets_bought
FROM `a table of tickets` GROUP BY ticket_buyer;
SELECT ticket_buyer, COUNT(DISTINCT show_date) AS shows_bought
FROM `a table of tickets` GROUP BY ticket_buyer;
Not every task has to be accomplished in a single query! It's part of the design of SQL that it should be used by some application language, and you're expected to handle formatting and display in the application.

MySQL query with list of values

I have a table with over then 50kk rows.
trackpoint:
+----+------------+-------------------+
| id | created_at | tag |
+----+------------+-------------------+
| 1 | 1484407910 | visitorDevice643 |
| 2 | 1484407913 | visitorDevice643 |
| 3 | 1484407916 | visitorDevice643 |
| 4 | 1484393575 | anonymousDevice16 |
| 5 | 1484393578 | anonymousDevice16 |
+----+------------+-------------------+
where 'created_at' is a timestamp of row added.
and i have a list of timestamps, for example like this one:
timestamps = [1502744400, 1502830800, 1502917200]
I need to select all timestamp in every interval between i and i+1 of timestamp.
Using Django ORM it's look like:
step = 86400
for ts in timestamps[:-1]:
trackpoint_set.filter(created_at__gte=ts,created_at__lt=ts + step).values('tag').distinct().count()
Because of actually timestamps list is very very longer and table has many of rows, finally i getting 500 time-out
So, my question is, how to for it in ONE raw SQL query join rows and list of values, so it looks like [(1502744400, 650), (1502830800, 1550)...]
Where second first value is timestamp, and the second is count of unique tags in each interval.
First index created_at. Next build query like created_at in (timestamp, timestamp+1). For each timestamp, run the query one by one rather than all at once.

Select a row for every date in the table, no matter the data

I have the following 3 tables in my database:
noobs
id
name
img_url
associations_id
noobs_has_points
noobs_id
points_id
points
id
amount
create_time (as UNIX timestamp)
I want to get a result for every day (such as FROM_UNIXTIME(points.create_time,'%Y-%m-%d')). And in that result I want the noobs.id and his amount of points so SUM(points.amount). So whether a noob has actually scored points on that day doesn't matter, if he did not I would want a row with 0 in there as the amount, so that for every day I get to see how many points each noob scored.
However, I have no idea how to get this result. I have tried some things with left/right (or unioned) joins but I don't get the result I want. Can anyone help me with this?
Example results:
day | points.amount | noobs.id
2015-04-11 | 3 | 1
2015-04-11 | 0 | 2 (no points scored, no entry in database)
2015-04-12 | 0 | 1 (no points scored, no entry in database)
2015-04-12 | 1 | 2
Some sample data from the three tables:
Noobs
id | name | img_url | associations_id
1 | Rien | NULL | 1
2 | Peter| NULL | 1
noobs_has_points
noobs_id | points_id
1 | 1
2 | 3
points
id | amount | create_time
1 | 3 | 1428779292
2 | 1 | 1428805351
Because there may be no dara for a given day for a given noob, you need a way to generate date values. Unfortunately, mysql doesn't have a built-in way to do this. You can code a range into the query with a series if unions as a subquery, but it's ugly and not scalable.
I recommend creating a table to hold date values:
create table dates(_date date not null primary key);
And populating it with lots of dates (say everything from 1970-2020).
Then you can code:
select _date day, sum(p.amount) total, n.id
from dates d
cross join noobs n
left join noobs_has_points np on np.noob_id = n.id
left join points p on p.id = np.points_id
and date(p.create_time) = _date
where _date between ? and ?
group by 1, 3
The cross join gives every noob a result for every date in the specified range, while to left joins ensure a zero for days without points for the noob.

Getting Distinct Value Counts Across Multiple Fields/Tables in One MySQL Query

I have a table called visits which contains the following
link_id, id, browser, country, referer
Now, this basically records visits of a certain link and inserts the browser, country and referer of whomever visted that link in a database
Now I need to show statistics for each link
I used the following query to get me all the browsers
SELECT browser, COUNT(browser) FROM visits GROUP BY browser
Which produced something like
Browser Count(Browser)
Internet Explorer | 5
Chrome | 3
Now this worked as expected for browsers only but I'm looking for a way to count all occurrences of referers, browsers and countries in one single query.
Is there a way to do this?
To count multiple, different occurence counts of values in the DB can very easily be done in just one query.
Keep in mind, the column header in SELECT COUNT(tablename) returns only one column, with only one numeric value. For every distinct value (from the GROUP BY clause), you have two columns: Value, Count. To count for different fields, you'll need three: Field, Value, Count, and if you want to count different fields in different tables, you'll need four: Table, Field, Value, Count.
Observe how I am using UNION below for two different tables:
SELECT
"Table1" AS TableName,
"Field1" AS Field,
Field1 AS Value,
COUNT(Field1) AS COUNT
FROM Table1
GROUP BY Value
UNION
SELECT
"Table2" as TableName,
"Field2" as Field,
Field2 as Value,
COUNT(Field2) AS COUNT
FROM Table2
GROUP BY Value
You'll notice I need to use aliases: "Table2" as TableName, this is because the UNION'd columns ought to have matching column headers.
So you can visualize what this returns, take a look:
+-------------------+----------------+----------+--------+
| TableName | Field | Value | COUNT |
+-------------------+----------------+----------+--------+
| ItemFee | PaymentType | | 228 |
| ItemFee | PaymentType | All | 1 |
| ItemFee | PaymentType | PaidOnly | 1 |
| Person | Presenter | | 692258 |
| Person | Presenter | N | 590 |
| Person | Presenter | Y | 8103 |
+-------------------+----------------+----------+--------+