I have spent a week trying to figure this out, it is somewhat working by combining things from various sources but not fully working yet.
Basically I have an orders table which I'm trying to group customers by their first order date, then show the total spent by this group up to now.
This is my SQL query:
SELECT DISTINCT email, billing_name,
FORMAT(SUM(total),2) AS total,
DATE_FORMAT(MIN(orderdate), '%Y-%m') AS firstorder,
DATE_FORMAT(MAX(orderdate), '%Y-%m') AS lastorder
FROM orders
GROUP BY email
ORDER BY firstorder ASC
and with PHP I am doing:
$rows = array();
while($row = mysql_fetch_array($query))
$rows[] = $row;
foreach($rows as $row) {
$currMonth = $row['firstorder'];
$total += $row['total'];
if ($currMonth != $prevMonth) {
echo $currMonth.' = $'.$total';
$prevMonth = $currMonth;
$total = 0;
}
}
this gives me a list like:
2010-05 = $230.49
2010-06 = $557.32
2010-08 = $223.38
but the numbers don't add up, what am i doing wrong? and how can I display how much a group have spent in other months? this is how I eventually want to show the data, http://www.quickcohort.com/
Please help! thanks!!
Depends on what you're really after and what your data looks like.
If data looks like:
email |BILLING NAME|Total |OrderDate
----------------------------------------------
john#gmail.com |John Smith |200.00 |15/05/2010
john#gmail.com |John Smith | 15.49 |19/10/2010
john#gmail.com |Rico Swavez | 15.00 |10/08/2010
jane#gmail.com |Jane Doe |250.00 |23/06/2010
jane#gmail.com |Jane Doe |307.32 |27/10/2010
juan#gmail.com |Juan Valdez |223.38 |30/08/2010
Then...
SELECT email, billing_name,
FORMAT(SUM(total),2) AS total,
DATE_FORMAT(MIN(orderdate), '%Y-%m') AS firstorder,
DATE_FORMAT(MAX(orderdate), '%Y-%m') AS lastorder
FROM orders
GROUP BY email, billing_name
ORDER BY firstorder ASC
Will return
EMAIL | BILLING NAME |TOTAL |FIRSTORDER | LASTORDER
------------------------------------------------------------
john#gmail.com | John Smith |215.49|2010-05 | 2010-10
jane#gmail.com | Jane Doe |557.32|2010-06 | 2010-10
john#gmail.com | Rico Swavez | 15.00|2010-08 | 2010-08
Juan#gmail.com | Juan Valdez |223.38|2010-08 | 2010-08
Run your query first in mysql are you getting the results you want? if not, then the problem is in the SQL, not the PHP. If the SQL is returning what you want, then the problem is in the PHP
The following query should do the trick:
SELECT
FORMAT(SUM(z.`totalSpent`),2) AS cohortRevenueToDate,
z.`firstOrderMonth`,
GROUP_CONCAT(`email`)
FROM
(
SELECT
`email`,
SUM(`total`) AS totalSpent,
DATE_FORMAT(MIN(`orderdate`), '%Y-%m') AS firstOrderMonth
FROM `orders`
GROUP BY `email`
) AS z
GROUP BY z.`firstOrderMonth`
ORDER BY z.`firstOrderMonth` ASC
I have included a GROUP_CONCAT in case you are interested on each cohort composition.
Related
So I've been following this tutorial: https://www.plus2net.com/php_tutorial/chart-line-database.php
I am trying to add a line chart to my website to display number of sales for each month.
This is an example on how my SQL table looks like:
| ID | user | sale_id | date |
| 1 | RVN4372 | 1341234 | 2020-09-22 17:31:32 |
| 2 | OVI6517 | 5452351 | 2020-09-22 15:14:43 |
| 3 | RVN4372 | 8452176 | 2020-09-17 16:23:54 |
| 4 | FOK8905 | 7421312 | 2020-09-17 11:23:11 |
| 5 | DIF9127 | 4236123 | 2020-09-15 15:32:26 |
This is how my current query looks like:
<?php
if($stmt = $link->query("SELECT user,COUNT(*) FROM sales WHERE yearweek(DATE(date), 1) = yearweek(curdate(), 1) GROUP BY user order by COUNT(*) DESC")){
$php_data_array = Array(); // create PHP array
while ($row = $stmt->fetch_row()) {
$php_data_array[] = $row; // Adding to array
}
}else{
echo $link->error;
}
//print_r( $php_data_array);
// You can display the json_encode output here.
echo json_encode($php_data_array);
// Transfor PHP array to JavaScript two dimensional array
echo "<script>
var my_2d = ".json_encode($php_data_array)."
</script>";
?>
<div id="curve_chart"></div>
This is how it looks like on my website:
So this basically groups the users, and count how many sales each user has. On the X axis is display the user's name, and Y axis total number of sales.
I want to change this, so in the X asix is display the month, and Y asis total number of sales. How can I accomplish this?
EDIT: Hava been trying out some, but can't make it work. This is what I've got so far:
if($stmt = $link->query("
SELECT YEAR(date)
as SalesYear,
MONTH(date) as SalesMonth,
COUNT(*) AS TotalSales
FROM sales
GROUP BY YEAR(date), MONTH(date)
ORDER BY YEAR(date), MONTH(date)
AND COUNT(*) DESC
")){
If you have more than one year then you need to group in Year-month combination. Then change this query to this.
SELECT CONCAT(YEAR(date),'-' MONTHNAME(date)) as ym, COUNT(*) FROM sales GROUP BY ym ORDER BY count(*) DESC
I was able to fix my previous query, however the results retrieve contains duplicates. I want to retrieve the latest record.
For example:
id | firstname | lastname | email | date
1 | steven | smith | steven#gmail.com 2013-06-10 04:01:25
2 | Bill | Johnson | bill#gmail.com | 2014-06-10 04:01:25
3 | steven | smith | steven#gmail.com | 2014-10-10 12:01:25
The return result should be the row with IDs 2 and 3
THe ID 1 should be not returned as the date is older than the ID 3 date
How can I add this to the query below ?
SELECT
users.firstname,
users.lastname,
DISTINCT(users.email),
users.pref
FROM (
SELECT
users.firstname,
users.lastname,
users.email,
users.status,
users.active,
CONCAT(
users.preference_1, ',',
users.preference_2, ',',
users.preference_3
) AS pref
FROM users
) AS users
WHERE users.status = 1
AND users.active = 1
AND users.date = (
SELECT MAX(u.date) FROM users AS u WHERE u.email = users.email
)
LIMIT 10000
no need for subselect
add: ORDER BY users.date DESC LIMIT 1 this way you sort the list by date and return only the "1st elemet" which is the one with the "biggest/latest" date
Well, looks like you want to fetch the latest row for each user.
Here's a query that can do it. (It also uses subquery. I don't understand the necessity for using subquery to concat though)
SELECT DISTINCT us.email, us.preference FROM users AS us WHERE us.date = (
SELECT MAX(u.date) FROM users AS u WHERE u.email = us.email
)
This does not fetch all the details you want. But gives you the basic idea about the query you might have to run.
This is a bit of a weird one I didn't know how to word the title please bear with me.
So I have a table like this which stores data on different jobs:
id | company | contact
----------------------
0 | name1 | Bob
1 | name1 | Mark
2 | name3 | Sam
3 | name1 | Bob
4 | name2 | Nigel
5 | name1 | Bob
6 | name3 | Donald
7 | name1 | Sandy
8 | name3 | Nigel
Is there a query with SQL I can use to query the table to find out the most commonly used contact for a particular company.
So the theoretical code I would be looking for would be something like:
SELECT "Most Commonly used Contact" FROM table WHERE company = "$company";
Is it possible in a single query or is this a multi query job?
try this sql query...
SELECT *, COUNT(*) AS total
FROM table
WHERE company = '$company'
GROUP BY contact
ORDER BY total DESC
LIMIT 1
Basically you want to find the number of contacts grouped by each company, and then grouped by the actual contact. So in other words:
SELECT COUNT(`id`) as num_contacts, `contact`, `company` FROM `jobtable` GROUP BY `company`, `contact` ORDER BY `company`, num_contacts DESC
Or for a single company:
SELECT COUNT(`id`) as num_contacts, `contact` FROM `jobtable` WHERE `company`='$company' GROUP BY `contact` ORDER BY num_contacts DESC
Gives you the single most used contact for $company, if you can't use LIMIT (e.g. if you are utilizing an Oracle Database):
SELECT contact, used_by
FROM (
SELECT contact, COUNT(*) AS used_by
FROM table
WHERE company = $company
GROUP BY contact
) t
HAVING used_by = MAX(used_by)
I have this mysql Table:
+--------------------+---------+-------+
| date | query | count |
|--------------------+---------+-------|
|2012-11-18 09:52:00 | Michael | 1 |
|2012-11-18 10:47:10 | Tom | 2 |
|2012-11-17 15:02:12 | John | 1 |
|2012-11-17 22:52:10 | Erik | 3 |
|2012-11-16 09:42:01 | Larry | 1 |
|2012-11-16 07:41:33 | Kate | 1 |
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
and so on. I can simply take results and order them by date in one row via this code:
$queries = mysql_query("SELECT * FROM my_tables ORDER BY date DESC LIMIT 20");
while($row = mysql_fetch_array($queries)){
echo "Name ".$row['query']."";
}
But how to display elements from table ordered by specific date like this:
In 2012-11-18:
Michael
Tom
In 2012-11-17:
John
Erik
In 2012-11-16:
Larry
Kate
and so on. Thanks!
Here is teh PHP code:
$query = mysql_query("SELECT date, query FROM table6 ORDER BY date DESC LIMIT 20");
$group_date = null;
while ($row = mysql_fetch_assoc($query)) {
if ($group_date !== substr($row["date"], 0, 10)) {
$group_date = substr($row["date"], 0, 10);
echo "<h1>$group_date</h1>\n";
}
echo "${row['query']}<br>\n";
}
Output:
2012-11-18
Tom
Michael
2012-11-17
Erik
John
2012-11-16
Larry
Kate
Note that while this code "groups" rows by one column, it can easily be extended to group rows by multiple columns. Left as an exercise.
+1 good question, THIS QUESTION IS NOT SIMPLY HOW TO ORDER A QUERY!!
I think this can be done using GROUP_CONCAT function. this will combine the matching results when you group them and seperate them by commas. ONce you have the results you can explode or do whatever you want
http://www.w3resource.com/mysql/aggregate-functions-and-grouping/aggregate-functions-and-grouping-group_concat.php
Your going to have to convert and group by date, and group_concat the names. then (in php or whathaveyou) explode the names by commas, and echo the date followed by the names for each result.
edit Looks like you wanted a PHP way to solve this? oops
Use this:
SELECT * FROM my_tables WHERE date > "2012-11-16" ORDER BY date LIMIT 4
Try the WHERE statement:
select * from my_table where date_column > "2012-11-18 00:00:00" and date_column < "2012-11-18 23:59:59" order by date_column
What about
SELECT * FROM my_tables GROUP BY YEAR(date), MONTH(date), DAY(date) ORDER BY date DESC LIMIT 20
I wrote some code to select duplicates and group them using first and last names. I gather them into a multidimensional array and dedupe/merge them using jQuery/Ajax on the resulting page. I would like to ask if there is a better method of creating the array than how I'm doing it. Here is my code. Thank you.
$dataArr=fetchDups($conn, 13, 5); // get a few at a time
print '<div style="clear:both;"></div><pre>';
print_r($dataArr);
print '</pre><div style="clear:both;"></div>';
function fetchDups($conn, $client_id, $limit='')
{
$sql=' SELECT * FROM `contacts` WHERE `clientid`=\'13\' GROUP BY fname, lname ';
//$sql=' SELECT DISTICT fname, lname, * FROM `clients` WWHERE `clientid`=\'13\' ';
$res=mysql_query($sql, $conn)or die(mysql_error());
$contactsRow=array();
while($row=mysql_fetch_array($res)){
echo $row['fname'].'<br>';
$contactsRow[]=$row;
}
mysql_freeresult($res);
$dataArr=array();
$i=0;
$limitNum=0;
//----------------------------------
foreach($contactsRow AS $rowNew){
$sql=' SELECT * FROM `contacts` WHERE `clientid`=\'13\' AND `id`!=\''.$rowNew['id'].'\'
AND (`fname` = \''.$rowNew['fname'].'\' OR `lname` = \''.$rowNew['lname'].'\')
';
//echo $sql;
$res=mysql_query($sql, $conn)or die(mysql_error());
$rowCountDup=mysql_num_rows($res);
if($rowCountDup>0){
$d=0;
$dataArr[$i]=array();
$dataArr[$i][$d]=$rowNew;
while($rowNew=mysql_fetch_array($res)){
$dataArr[$i][($d+1)]=$rowNew;
$d++;
}
$i++;
$limitNum++;
}
// limit the results. too many crashes the browser
if($limitNum==$limit){
break;
}
}
mysql_freeresult($res);
return $dataArr;
}
For this kind of things, you should probably try using:
SELECT * FROM contacts refC JOIN contacts allC USING (fname, lname) WHERE refC.clientid='13'
This does a self-join on contacts based on first and last name, so allC aliases to the list of all contacts that share refC's first and last names (including himself).
This way, you get all the information you're looking for in only one SQL query. Tuning may be achieved on the query by adding an index on columns fname and lname of table contacts, so the join doesn't have to parse the whole table to match.
--edit: You may get to specify more finely how you join your tables as for instance:
SELECT *
FROM contacts refC
JOIN contacts allC ON (allC.fname LIKE CONCAT(refC.fname, '%') AND allC.lname LIKE CONCAT(refC.lname, '%'))
WHERE refC.clientid='13'
Which is strictly equivalent (but IMO easier to read than) to:
SELECT *
FROM contacts refC,contacts allC
WHERE allC.fname LIKE CONCAT(refC.fname, '%')
AND allC.lname LIKE CONCAT(refC.lname, '%')
AND refC.clientid='13'
If you just want to avoid displaying duplicates and not actually removing them from your db, use DISTINCT SQL keyword.
Or you could try something like the second query here which uses a derived table:
mysql> select * from contacts ;
+----+--------+---------+
| id | fname | lname |
+----+--------+---------+
| 1 | Annie | Haddock |
| 2 | Annie | Haddock |
| 3 | Ginger | Mole |
| 4 | Ted | Ted |
| 5 | Ted | Ted |
+----+--------+---------+
5 rows in set (0.01 sec)
mysql> select id, fname, lname, total from
(select *, count(*) as total
from contacts group by fname, lname) people
where total > 1;
+-----------+--------------+--------------+--------------+
| people.id | people.fname | people.lname | people.total |
+-----------+--------------+--------------+--------------+
| 1 | Annie | Haddock | 2 |
| 4 | Ted | Ted | 2 |
+-----------+--------------+--------------+--------------+
2 rows in set (0.01 sec)
then just iterate through it with foreach. Note that "people" above is an alias for the derived table created by the inner select