mysql PHP query to contain count over join - php

I have this query which after checking various tutorials should work - but it doesn't.
$query="SELECT week, year, COUNT(week) AS week_no
FROM archive_agent_booking
LEFT JOIN invoice_additions ON invoice_additions.week = archive_agent_booking.week
WHERE client_id='$account_no' GROUP BY week, year ORDER BY week DESC";
The tables are as follows:
archive_agent_booking
+---------+----------+----------+----------+----------+---------+---------+
| job_id | week | year | desc | price | date | acc_no |
+---------+----------+----------+----------+----------+---------+---------+
invoice_additions
+---------+----------+----------+----------+----------+---------+
| acc_no | week | year | desc | am_price | am_date |
+---------+----------+----------+----------+----------+---------+
I basically want to count each week element from both tables and display them as one total even if one of the week values does not show in one of the tables. Don't know whether this is the best solution so I am open to alternatives.

select
week,
sum(items)
from
(
(select week, count(*) as items from archive_agent_booking group by week)
union
(select week, count(*) from invoice_additions group by week)
)
group by
week
Edit: i've made some huge assumption about what you want to see

Related

How to select all entries of a user from a database?

I am trying to make a "top purchaser" module on my store and I am a bit confused about the MySQL query.
I have a table with all transactions and I need to select the person (which could have one or many transactions) with the highest amount of money spent in the past month.
What I have:
name | money spent
------------------
john | 50
mike | 12
john | 10
jane | 504
carl | 99
jane | 12
jane | 1
What I want to see:
With a query, I need to see:
name | money spent last month
-----------------------------
jane | 517
carl | 99
john | 60
mike | 12
How do I do that?
I do not really seem to find many good solutions since my MySQL query skills are quite basic. I thought of making a table in which money is added to the user when he buys something.
That's a simple aggregated query :
SELECT t.name, SUM(t.moneyspent) money_spent_last_month
FROM mytable t
GROUP BY t.name
ORDER BY t.money_spent_last_month DESC
LIMIT 1
The query sums the total money sped by customer name. The results are ordered by descending total money spent, and only the first row is retained.
If you are looking to filter data over last month, you need a column in the table that keeps track of the transaction date, say transaction_date, and then you can just add a WHERE clause to the query, like :
SELECT t.name, SUM(t.moneyspent) money_spent_last_month
FROM mytable t
WHERE
t.transaction_date >=
DATE_ADD(LAST_DAY(DATE_SUB(NOW(), INTERVAL 2 MONTH)), INTERVAL 1 DAY)
AND t.transaction_date <=
DATE_SUB(NOW(), INTERVAL 1 MONTH)
GROUP BY t.name
ORDER BY t.money_spent_last_month DESC
LIMIT 1
This method is usually more efficient than using DATE_FORMAT to format dates as string and compare the results.

MySql query for cohort analysis

I am working with MySql and Symfony2. I need to build cohort analysis table. I need to compare how many users in each cohort log in to website at least once a week after they register. What I tried to do is to get number of registered users by week, basically these are my cohorts.
SELECT DATE_FORMAT(date_added,'%d %b %y') as reg_date, COUNT(*) AS user_count
FROM user
WHERE date_added>='2016-02-01' AND date_added<=NOW()
GROUP BY WEEK(date_added)
This query gets distinct users logged in to website by week.
SELECT WEEK(login_date) AS week, COUNT(DISTINCT user_id) AS user_count
FROM user_log
WHERE login_date>='2016-02-01' AND login_date<=NOW()
GROUP BY WEEK(login_date)
My problem: I can't figure out how to group logged in users by cohorts and compare cohorts by weeks. I hope I stated problem clearly. English is not my first language. Thanks.
Sample data:
user table
id | date_added (in WEEK() format)
A | 1
B | 1
C | 1
D | 2
E | 2
F | 2
G | 2
------------
user_log table
user_id | login_date (in WEEK() format)
A | 1
B | 1
B | 1
A | 2
D | 2
A | 2
D | 2
E | 2
Expected table. Cohort 1 - users registered in week 1, cohort 2- in week etc. Size - number of registered users. Week 1 - how many users logged back to website in a first week after registration, Week 2 - how many users logged back to website in a second week after registration
Cohort size Week1 Week2
Cohort 1 | 3 | 2 | 1 |
Cohort 2 | 4 | 2 | - |
This is borrowed from my modification of #Andriy M's answer of this question: Cohort analysis in SQL
This query gets unique user logins by week after registering.
SELECT DISTINCT
user_id,
FLOOR(DATEDIFF(user_log.login_date, user.date_added)/7) AS Offset
FROM user_log
LEFT JOIN user ON (user.id = user_log.user_id)
WHERE user_log.login_date >= CURDATE() - INTERVAL 14 DAY
This query gets all the users created in the past 14 days and formats the date to the week they signed up:
SELECT
id,
DATE_FORMAT(date_added, "%Y-%u") AS cohort
FROM user
WHERE date_added >= CURDATE() - INTERVAL 14 DAY
We can put those two queries together to get a table with how many people came back after registering:
SELECT STR_TO_DATE(CONCAT(u.cohort, ' Monday'), '%X-%V %W') as date,
SUM(s.Offset = 0) AS size,
SUM(s.Offset = 1) AS Week1,
SUM(s.Offset = 2) AS Week2
FROM (
SELECT
id,
DATE_FORMAT(date_added, "%Y-%u") AS cohort
FROM user
WHERE date_added >= CURDATE() - INTERVAL 21 DAY
) as u
LEFT JOIN (
SELECT DISTINCT
user_id,
FLOOR(DATEDIFF(user_log.login_date, user.date_added)/7) AS Offset
FROM user_log
LEFT JOIN user ON (user.id = user_log.user_id)
WHERE user_log.login_date >= CURDATE() - INTERVAL 21 DAY
) as s
ON s.user_id = u.id
GROUP BY u.cohort
ORDER BY u.cohort
Since we aren't counting how many people registered in a given week, we are assuming that they logged at lease once in the week they registered to give an accurate result for the size column.
Also you'll have to rework this to get a number for the cohort instead of the date, but I find dates more helpful.
Also you can extend this to more weeks - you'll have to change the number of days after INTERVAL in both subqueries, and you can add more rows on in the main select statement to get more weeks.

Taking a specific data with MySQL, Group by

I want to take most frequently entered datas in last 1 day.
Here is my code:
SELECT tag_id, time,
COUNT(tag_id) AS value_occurrence
FROM tag_rel
GROUP BY tag_id
HAVING time > '$yesterday'
ORDER BY value_occurrence DESC LIMIT 10
Code is working but it has a problem:
I wanna take between july 22 and 23.
id| tag_id | time |
1 | football | 22,5 july |
2 | basketball | 22,5 july |
3 | football | 22,5 july |
4 | football | 21 july |
I want to take first three rows and order them by their frequency.
ex:
1- football
2- basketball
But my code is not taking "football". It just shows "basketball". Because additionally "football" has a time value which is smaller than 22 july.
How can solve it?
The correct query for what you want would use where, not having:
SELECT tag_id, MAX(time) as maxtime,
COUNT(tag_id) AS value_occurrence
FROM tag_rel
WHERE time > '$yesterday'
GROUP BY tag_id
ORDER BY value_occurrence DESC
LIMIT 10;
Otherwise, there is an arbitrary value used for time, both in the select and the having clause.

Effectively Firing a multiple query

I was practicing drawing graphs on various statistics for the purpose of data analysis. But I am not able to figure out an efficient way to fire multiple mysql query at the back-end.
I am trying to draw Period Vs No of Visitors graph.
Please Note: Period here refers to week,month,3 months,6 months,1 year,2 years.
Period will be selected by the user from the select box.
For example: When User selects 3 week, I need to construct No of Visitors per 3 week graph.
My DataBase Contains Two Column: For each of the site hit, it records:
(1) timestamp and
(2)user ID.
If I fire query multiple times for each select option, then performance would be quite poor.So, How to do it efficiently?
UPD:
When User Select stats per 3 month:
Then I am firing mysql query as:
Select count(*) From stats_tab WHERE timestamp BETWEEN JAN AND MAR;
Select count(*) From stats_tab WHERE timestamp BETWEEN APR AND JUN;
Select count(*) From stats_tab WHERE timestamp BETWEEN JUL AND SEP;
............
Each count returned from each of the query will be the y-axis value for my graph
When User Select stats per year:
Then I am firing mysql query as:
Select count(*) From stats_tab WHERE timestamp BETWEEN 2009 AND 2010;
Select count(*) From stats_tab WHERE timestamp BETWEEN 2010 AND 2011;
Select count(*) From stats_tab WHERE timestamp BETWEEN 2011 AND 2012;
............
Don't hit database with multiple queries. Get all your values with one query appropriately applying GROUP BY and WHERE
SELECT YEAR(timestamp) year, COUNT(*) total
FROM stats_tab
WHERE timestamp BETWEEN NOW() - INTERVAL 3 YEAR AND NOW()
GROUP BY YEAR(timestamp);
SELECT MONTH(timestamp) month, COUNT(*) total
FROM stats_tab
WHERE timestamp BETWEEN NOW() - INTERVAL 6 MONTH AND NOW()
GROUP BY MONTH(timestamp);
SELECT DAY(timestamp) day, COUNT(*) total
FROM stats_tab
WHERE timestamp BETWEEN NOW() - INTERVAL 7 DAY AND NOW()
GROUP BY DAY(timestamp);
Sample output:
| YEAR | TOTAL |
----------------
| 2011 | 2 |
| 2012 | 1 |
| 2013 | 9 |
| MONTH | TOTAL |
-----------------
| 2 | 1 |
| 3 | 2 |
| 5 | 1 |
| DAY | TOTAL |
---------------
| 20 | 1 |
| 21 | 1 |
| 22 | 1 |
Here is SQLFiddle demo

compare between two dates

i have a course table and a course due dates table like this
course_id | course_name
1 A
2 B
due_id | start_date | end_date course_id
1 2011-02-01 2011-02-28 1
2 2011-03-01 2011-03-15 1
now what i am trying to do from last tow day that write a query or code that will show a course name with current date session.for example if current date is betwen start and end date course should come like this and if its in next date session it should come with next due_id
course_id | course_name | due_id
1 A | 1
if this database structure is wrong for this please let me know
thanks for help
SELECT course.course_name, due_dates.course_id, due_id
FROM course
INNER JOIN due_dates ON course.course_id = due_dates.course_id
WHERE now() BETWEEN start_date and end_date;

Categories