do not print duplicate entries from php array [duplicate] - php

I have a MySQL table which contains the following type of information:
Date product
2011-12-12 azd
2011-12-12 yxm
2011-12-10 sdx
2011-12-10 ssdd
Here is an example of a script I use to get data from this table:
<?php
$con = mysql_connect("localhost","username","password");
if (!$con)
{
die('Could not connect: ' . mysql_error());
}
mysql_select_db("db", $con);
$sql=mysql_query("SELECT * FROM buy ORDER BY Date");
while($row = mysql_fetch_array($sql))
{
echo "<li><a href='http://www.website/". $row['Date'].".html'>buy ". date("j, M Y", strtotime($row["Date"]))."</a></li>";
}
mysql_close($con);
?>
This script displays every date from the table, e.g.
12.dec 2011
12.dec.2011
10.dec.2011
10.dec.2011
I would like to only display unique dates, e.g.
12.dec.2011
10.dec.2011

Use the DISTINCT operator in MySQL:
SELECT DISTINCT(Date) AS Date FROM buy ORDER BY Date DESC;

use
SELECT DISTINCT Date FROM buy ORDER BY Date
so MySQL removes duplicates
BTW: using explicit column names in SELECT uses less resources in PHP when you're getting a large result from MySQL

Use this query to get values
SELECT * FROM `buy` group by date order by date DESC

The rest are almost correct, except they should order by Date DESC
SELECT DISTINCT(Date) AS Date FROM buy ORDER BY Date DESC;

DISTINCT is always a right choice to get unique values. Also you can do it alternatively without using it. That's GROUP BY. Which has simply add at the end of the query and followed by the column name.
SELECT * FROM buy GROUP BY date,description

Another DISTINCT answer, but with multiple values:
SELECT DISTINCT `field1`, `field2`, `field3` FROM `some_table` WHERE `some_field` > 5000 ORDER BY `some_field`

Use something like this in case you also want to output products details per date as JSON and the MySQL version does not support JSON functions.
SELECT `date`,
CONCAT('{',GROUP_CONCAT('{\"id\": \"',`product_id`,'\",\"name\": \"',`product_name`,'\"}'),'}') as `productsJSON`
FROM `buy` group by `date`
order by `date` DESC
product_id product_name date
| 1 | azd | 2011-12-12 |
| 2 | xyz | 2011-12-12 |
| 3 | ase | 2011-12-11 |
| 4 | azwed | 2011-12-11 |
| 5 | wed | 2011-12-10 |
| 6 | cvg | 2011-12-10 |
| 7 | cvig | 2011-12-09 |
RESULT
date productsJSON
2011-12-12T00:00:00Z {{"id": "1","name": "azd"},{"id": "2","name": "xyz"}}
2011-12-11T00:00:00Z {{"id": "3","name": "ase"},{"id": "4","name": "azwed"}}
2011-12-10T00:00:00Z {{"id": "5","name": "wed"},{"id": "6","name": "cvg"}}
2011-12-09T00:00:00Z {{"id": "7","name": "cvig"}}
Try it out in SQL Fiddle
If you are using a MySQL version that supports JSON functions then the above query could be re-written:
SELECT `date`,JSON_OBJECTAGG(CONCAT('product-',`product_id`),JSON_OBJECT('id', `product_id`, 'name', `product_name`)) as `productsJSON`
FROM `buy` group by `date`
order by `date` DESC;
Try both in DB Fiddle

Depends on what you need.
In this case I suggest:
SELECT DISTINCT(Date) AS Date FROM buy ORDER BY Date DESC;
because there are few fields and the execution time of DISTINCT is lower than the execution of GROUP BY.
In other cases, for example where there are many fields, I prefer:
SELECT * FROM buy GROUP BY date ORDER BY date DESC;

There is a specific keyword for the achieving the same.
SELECT DISTINCT( Date ) AS Date
FROM buy
ORDER BY Date DESC;

Related

Codeigniter count using month?

The scenario is I am the admin and I have a session to make, the session table consists of a session_id, coach_name, date(format Y-m-d).
Now I want to count the total activity of the coach every "MONTH".
So my point is how will I get this kind of output in a SQL query.
The desired output is the amount of activity per month, per coach.
Name | No. of session this month
Coach_name1 = 13
Coach_name2 = 5
This is my current query that gives me the coach name but I don't know how to get for each MONTH
public function getAll(){
$query = $this->db->query('SELECT DISTINCT coach_name FROM sessions);
return $query->result();
}
Use this query to get the result.
Use mysql MONTH() to get Month number from date and group by it. You will get all month wise data.
SELECT coach_name,
Count(*) AS activities
FROM sessions
WHERE Month(date) = 8 //for specfic month
GROUP BY coach_name, Month(date) // for all months
Use this query to dynamincally get current month based on system date
SELECT coach_name,
Count(*) AS activities
FROM sessions
WHERE Month(date) = MONTH(CURRENT_DATE()) //for selecting current month.
GROUP BY coach_name
You have to prepare query like below:
select
coach_name,
month(your_date_field),
count(1)
from
your_table
where
month(your_date_field) = 8
group by
coach_name, month(your_date_field)
Which would return records like below,
| coach_name | month(your_date_field) | count(1) |
+---------------+------------------------+------------+
| Coach_name1 | 8 | x |
| Coach_name2 | 8 | x |
| Coach_name3 | 8 | x |
+---------------+------------------------+------------+
In codeigniter
$this->db->select("coach_name, month(your_date_field) as month_number,count(1) as counts");
$this->db->where('month(your_date_field)',8);
$this->db->group_by('coach_name,MONTH(your_date_field)');
$query = $this->db->get('your_table');
// results
foreach ($query->result_array() as $row)
{
// do this to see array
print_r($row);
// to access individual fields
echo $row['coach_name'];
echo $row['month_number'];
echo $row['counts'];
}
Use MySQL's MONTH() in your query. So basically if all your data is in your sessions table try the following in your query.
SELECT DISTINCT(`name`),COUNT(`name`) AS `activity` FROM `session`
WHERE MONTH(`date`)=8 GROUP BY `name`;
Check in SQLFiddle

MYSQL: closest to supplied date grouped by user_id

I need to get multiple rows with a date_added closest to but not past a user supplied date, grouped by user_id.
I've looked at a bunch of max in group type answers but I'm not quite there:
Get nearest records to specific date grouped by type
SQL Query to show nearest date?
Find closest datetime to specified datetime in mysql query
Get closest date from MySQL table
https://dev.mysql.com/doc/refman/5.0/en/example-maximum-column-group-row.html
This is close: https://stackoverflow.com/a/17038667/5319244. Finds the max date though, I need the max specified by user input, not max outright.
Here's a subset of the data with the correct organisation_id, framework_id and level_id already filtered.
+----+---------+-----------------+--------------+----------+---------------------+
| id | user_id | organisation_id | framework_id | level_id | date_added |
+----+---------+-----------------+--------------+----------+---------------------+
| 2 | 1 | 2 | 1 | 1 | 2015-07-31 14:02:49 |
| 9 | 2 | 2 | 1 | 1 | 2015-09-01 11:05:09 |
| 11 | 1 | 2 | 1 | 1 | 2015-09-07 14:13:39 |
+----+---------+-----------------+--------------+----------+---------------------+
If the supplied date is 2015-09-07. I'd expect to see id's: 9 and 11.
If the supplied date is 2015-09-01. I'd expect to see id's: 2 and 9.
If the supplied date is 2015-07-31. I'd expect to see id: 2.
This query is as close as I got:
SELECT t1.id
, t1.user_id
, t1.date_added
FROM
completed_frameworks AS t1
WHERE date_added = (
SELECT
MAX(date_added)
FROM
completed_frameworks
WHERE
user_id = t1.user_id
AND
date_added <= '2015-09-07 23:59:59'
)
AND
(
t1.organisation_id = 2
AND
t1.framework_id = 1
AND
t1.level_id = 1
)
It returns what I expect for the date: 2015-09-07
When the date is 2015-09-01 however it only returns id 9. Not also 2 as I'd expect.
When the date is 2015-07-31 it returns 0 rows..
Let me know if I there's anything else I can provide.
Cheers!
EDIT:
Thanks for the replies thus far. I need to clarify two points:
1) I don't have a limit. I'm expecting those rows due to the user id's. There could be n users returned. I just want a row for each user where the date_added is closest to the user supplied date.
2) The date supplied will not have a time value. It will be from a simple datepicker UI. In my example query I've added the time of 23:59:59 to encompass all of that day.
Try this subquery instead. The organisation_id/framework_id/level_id filter is moved into the subquery and it now returns the right values for the examples you've given.
SELECT t1.id, t1.user_id, t1.date_added
FROM
completed_frameworks AS t1
WHERE date_added = (
SELECT
MAX(date_added)
FROM
completed_frameworks
WHERE
user_id = t1.user_id
AND
date_added <= '2015-09-01 23:59:59'
AND
organisation_id = 2
AND
framework_id = 1
AND
level_id = 1
)
Here is a sample query you could use for an input date of '2015-09-07 14:13:39'. The inner query returns the input date along with the next highest date. This temporary table is then used to filter completed_frameworks to give you only records from the two dates most recent to the input date.
SELECT t1.id, t1.user_id, t1.date_added
FROM completed_frameworks t1
INNER JOIN
(
SELECT cf.date_added
FROM completed_frameworks cf
GROUP BY cf.date_added
HAVING cf.date_added <= '2015-09-07 14:13:39'
ORDER BY cf.date_added DESC
LIMIT 2
) t2
ON t1.date_added = t2.date_added
WHERE t1.organisation_id = 2 AND t1.framework_id = 1 AND t1.level_id = 1
I think this does what you want:
SELECT f.id, f.user_id f.date_added
FROM completed_frameworks f
WHERE date(f.date_added) <= '2025-09-07' -- or whatever your date is
ORDER BY f.date_added DESC
LIMIT 2;
EDIT:
If you want one date per user id that is closest to the specified date, I would suggest:
select f.*
from completed_frameworks f join
(select user_id, max(date_added) as maxda
from completed_frameworks
where date(date_added) <= '2015-09-07'
group by user_id
) u
on f.user_id = u.user_id and f.date_added = maxda

Mysql: Gap detection query not detecting gaps

It seems as though my gap detection is just picking up whatever I set as the timedifference and doing it every interval based on that.
So here's an explanation of my data structure and what I'm after:
I have a database that's set up like this:
(Schema Name)
Historical
-CID int UQ AI NN
-ID Int PK
-Location Varchar(255)
-Status Varchar(255)
-Time datetime
My data comes in looking something like this (example 5 rows for selected ID)
433275 | 97 | MyLocation | OK | 2013-08-20 13:05:54
433275 | 97 | MyLocation | OK | 2013-08-20 13:00:54
433275 | 97 | MyLocation | OK | 2013-08-20 12:25:54
433275 | 97 | MyLocation | OK | 2013-08-20 12:20:54
433275 | 97 | MyLocation | OK | 2013-08-20 12:15:54
In the case above you'll notice that I'm missing data from 12:25:54 -> 13:00 for ID 97. I am trying to write a report that will tell me the: Start of downtime, Duration of DownTime, and End of Downtime (which I've been handling in php by adding timediff to Time)
Here's my code (php -> mysql) (non-working) as it stands now:
select *from (
SELECT
y.*,
TIMESTAMPDIFF(MINUTE, #prevDT, `Time`) AS timedifference,
#prevDT := `Time`
FROM ddHistorical y,
(SELECT #prevDT:=(SELECT MIN(`Time`) FROM ddHistorical)) vars
Where ID = '". mysql_real_escape_string($ID)."'
HAVING timedifference > 16
) s
order by Time desc
Limit 25";
You need two levels of subquery:
SELECT *
FROM (
SELECT y.*,
TIMESTAMPDIFF(MINUTE, #prevDT, `Time`) AS timedifference,
#prevDT := `Time`
FROM (SELECT *
FROM ddHistorical
WHERE ID = '97'
ORDER BY `Time`) y,
(SELECT #prevDT:=(SELECT MIN(`Time`) FROM ddHistorical)) vars) z
WHERE timedifference > 16
LIMIT 25
I'm actually not sure why the outermost level is needed. I tried without it (i.e. starting with SELECT y.*) and using HAVING timedifference > 16. For some reason, this reported a single row with timedifference = 45. But if I removed that HAVING clause, it showed all the rows, with the gap reported as 35 minutes. Usually, there's no difference between
SELECT ... HAVING <cond>
and
SELECT * FROM (SELECT ...) WHERE <cond>
I'm not sure why this query violates the rule -- I suspect it has something to do with the user-variables.
EDIT:
I think I've figured out why it didn't work with HAVING. MySQL is apparently evaluating that condition as soon as it calculates the timedifference column for each row, and discarding the row. When timedifference <= 16, it doesn't bother calculating the rest of the columns in the SELECT clause, so it never does #prevDT := Time. So until it gets past that condition, it's always comparing with MIN(Time).
Moving the timedifference check into an outer query forces it to calculate all the differences before filtering.
SQLFIDDLE
Please try this:
"
SELECT y.*,
TIMESTAMPDIFF(MINUTE, y.prevDT, y.`Time`) AS timedifference
FROM (SELECT w.*, (SELECT MAX(x.`Time`)
FROM ddHistorical x
WHERE x.ID = w.ID
AND x.`Time` < w.`Time`) AS prevDT
FROM ddHistorical w
WHERE w.ID = '". mysql_real_escape_string($ID)."') y
WHERE TIMESTAMPDIFF(MINUTE, y.prevDT, y.`Time`) > 16
ORDER BY y.`Time` DESC
LIMIT 25";

Get all Mysql columns containing same other column

Hi lets say I have a table like this:
________________________________________________________
|
| id | order | date | item | price|
-------------------------------------------------------
| 1 1st date i1 10,00|
|-------------------------------------------------------
| 2 2nd date u2 15,00|
|-------------------------------------------------------
| 3 1st date i1 20,00|
|-------------------------------------------------------
| 4 2nd date u2 30,00|
|-------------------------------------------------------
I need to get total sum of items containing same order name and print DISTINCT orders like:
order_name - date - total sum. or better way to create new tabel and store there total sum of each order and in this table add sum id in each row?
This will literally return order_name - date - total sum, assuming your date column is date
SELECT CONCAT(order, " - ", date, " - ", SUM(price)) as Result
FROM orders
GROUP BY `order`
To add a quantity, try this:
SELECT CONCAT(order, " - ", date, " - ", CASE WHEN quantity > 1 THEN (quantity * SUM(price)) ELSE SUM(price) END) as Result
FROM orders
GROUP BY `order`
Use GROUP BY:
SELECT SUM(`price`)
FROM `orders`
GROUP BY `order`
http://dev.mysql.com/doc/refman/5.0/en/group-by-functions.html

Reports by month with php and mysql?

I want to know how to display report by month using PHP and Mysql
Example of Report on the web page:
January 2011
==============
Store Name | Total Order Cost
SHOP A | £123
SHOP B | £100
February 2011
==============
Store Name | Total Order Cost
SHOP A | £123
SHOP B | £100
SHOP C | £99.40
I have mysql tables
tbl_shop
ShopID
ShopName
tbl_order
OrderID
ShopID
OrderDate
Total
You will need to iterate trough the result of the query and create an multidimensional array using the month/year combination as keys. The query below should be a good indication on how to fetch the required information from your database.
SELECT
MONTH(to.OrderDate),
YEAR(to.OrderDate),
SUM(to.Total),
to.*
FROM tbl_order as to
INNER JOIN tbl_shop as ts ON ts.ShopID = to.ShopID
GROUP BY to.ShopID, MONTH(to.OrderDate), YEAR(to.OrderDate)
Note that I havn't tested this query - please handle it as pseudo-code. You might need to throw around the GROUP BY fields a little and test if it works.
Use
SELECT ShopName,SUM(Total),MONTHNAME(OrderDate) from tbl_shop
left join tbl_order
on tbl_shop.ShopID = tbl_order.ShopID
GROUP By(ShopID),MONTHNAME(OrderDate)
will give you All months report.
Use this query:
SELECT monthname(o.OrderDate) as Month, year(o.OrderDate) as Year,
s.ShopName, sum(o.Total) as Total
FROM tbl_Shop s JOIN tbl_Order o
ON s.ShopID=o.ShopID
GROUP BY o.shopID,year(o.Orderdate),month(o.Orderdate)
ORDER BY year(o.OrderDate),month(o.OrderDate)
then for every row from result if month+year has changed (a variable $last_date could help) then print
$Month $Year
==============
Store Name | Total Order Cost
$ShopName | $Total
else print
$ShopName | $Total

Categories