Find lowest date (custom) in mysql - php

I have no idea how can I find the lowest string in date-type
I will just find lowest month(by years in a table)
TableName
Id | M | D | Y |
=======================
1 | 01 | 22 | 2012 |
2 | 11 | 29 | 2012 |
3 | 12 | 30 | 2013 |
4 | 01 | 30 | 2011 | <--- this !
5 | 12 | 14 | 2012 |
PHP:
$sql = "SELECT * FROM TableName WHERE M=?? AND Y=??";
$selected = mysql_query($sql);
so $selected should give me a result like "4/01/30/2011" (Id,M,D,Y)
Any?

SELECT min(concat(Y,M,D)) FROM TableName
Edit: This just looks nice and clean but it is kind of very bad answer, so please use this answer

Just use the ORDER BY clauses:
SELECT * FROM TableName
ORDER BY Y ASC, M ASC, D ASC
More info here : http://www.tizag.com/mysqlTutorial/mysqlorderby.php

bugwheels94's answer will give you the correct result:
SELECT min(concat(Y,M,D))
FROM `TableName`
but this will be unable to use any index you have on any of the date's constituent fields, so will have to visit every row in the table to determine the minimum value.
Combining m4t1t0 and koopajah's answers gives you:
SELECT *
FROM `TableName`
ORDER BY Y, M, D
LIMIT 1
This will be able to use an available index on Y, and maybe even a combined index on (Y,M,D) which can perform much faster on larger tables.
All this being said; It's almost criminal to put an answer to this question that doesn't suggest using a date field instead of your three column setup. The only reason I can think of to separate a date column would be for performance on niche queries that require separate indexes on day or month, but the choice of accepted answer suggests to me that this isn't the case.
As pointed out by Lucius.. If it's a date, store it as a date and run:
SELECT MIN(`DateColumnName`) FROM `TableName`
As a bonus this will give you access to all the MySQL Temporal functions on the column, including the ability to extract day and month, format it how you like and a single field to index and order by.

Please, do yourself a favour and use a date field instead.. you'll save yourself a lot of troubles.
ALTER TABLE `TableName` ADD `date` DATE NOT NULL;
UPDATE `TableName` SET `date` = CONCAT( `Y` , '-', `M` , '-', `D` );
then you'll be able to do:
SELECT MIN(`date`) FROM `TableName`

Simply perform a query ordering by year, month and day and limit your result to the first row.
SELECT * FROM TableName ORDER BY Y, M, D ASC limit 1;

Try this:
SELECT MIN(ColumnName) FROM TableName;
In your case, that would be:
SELECT MIN(Y) FROM TableName;

I am giving you some idea for your query. Kindly follow that :
$sql="SELECT * FROM tbl_name ORDER BY Y, M, D ASC limit 1;
$res=mysql_query($sql);
$row=mysql_fetch_array($res);
$date=$row["id"]."/".$row["M"]."/".$row["D"]."/".$row["Y"];
echo $date;
I hope It will help you

SELECT concat(Y,M,D) FROM TableName
ORDER BY Y ASC, M ASC, D ASC
Limit 1
That way you can return the whole row by replacing "concat(Y,M,D)" with * and easily adapt for different use cases. You could e.g. return the last date row inside the first year by:
SELECT * FROM TableName
ORDER BY Y ASC, M DESC, D DESC
Limit 1
Storing as DATETIME and using native MySQL sorting speeds it up a lot. If you need to keep the seperate values (for whatever reason, e.g. import/export with other systems out of your scope), maybe you can just add another value to the table and synchronise the values?

Related

how should i do this query in mysql

I want to do the following. I have a table in the database, I am working on a table called asistencia and this table has 3 columns
id_asistencia as a int AUTOINCREMENT
nro_matricula as an int which I took it from another table called
alumnos
fecha as a date
This is a sketch of the database
id_asistencia | nro_matricula | fecha
1 | 0001| 2015-01-10
2 | 0002| 2015-01-10
3 | 0002| 2015-02-10 (another date )
The thing is I have to do a percentage
select all id_1 records in my nro_matricula column and see how many times its repeated in my rows and do a percentage respect all the dates in my database
EG : id_1 came to class day(whatever day) and he/she did not came to class the next day so id_1 has 50% assistance
Expected result
nro_matricula | percentage
0001| 50
0002| 100
The question is how can I make this query. If can be done in PHP its even better but i feel that this can be done in SQL
PS : The Database wasn't created by me
And excuse my English is not the better and i expect it to be understandable for you to help me
You can use sql statement like this:
select (
sum (if nro_matricula = '001' ,1,0 )
/ count(*)
from asistencia
--where nro_matricula = '001'
Maybe just simply:
select al.nro_matricula,
100 * count(distinct al.fecha) / (select count(distinct al1.fecha) from alumnos al1) as percentage
from alumnos al
group by al.nro_matricula
I did found the answer to my question. Thank you all for helping me out
SELECT
asistencia.nro_matricula as matricula,
COUNT( DISTINCT asistencia.fecha)* 100 /
COUNT( DISTINCT asistencia.nro_matricula) / (SELECT COUNT(DISTINCT asistencia.fecha)
FROM asistencia
ORDER BY COUNT(*) DESC
LIMIT 1 )
as porcentaje_asistencia
FROM asistencia
JOIN alumno
WHERE asistencia.nro_matricula = alumno.nro_matricula AND alumno.id_curso = 'basica6a'
Tried this in Oracle. Should work in MySQL too.
SELECT aa.NRO_MATRICULA , days_present/total_count* 100 FROM
(SELECT DISTINCT NRO_MATRICULA,
COUNT(*) as days_present FROM ASISTENCIA GROUP BY NRO_MATRICULA ) AA
,
(SELECT COUNT(*) as total_count FROM (SELECT DISTINCT(FECHA) FROM ASISTENCIA GROUP BY FECHA)) BB
Ouptut
nro_matricula percentage
0001 50
0002 100
The query (SELECT COUNT(*) FROM (SELECT DISTINCT(FECHA) FROM ASISTENCIA AA GROUP BY FECHA)) will give count of distinct date (2 in your case). Then we are getting distinct nro_matricula group by nro_matricula to get its count which will give the days it was present. Then divide both values from above steps to get percentage.

Select previous record with multiple conditions in mysql

This one's been tricky to quantify, so I may not have this question worded properly first time around.
I have a table following a format similar to this:
| id | other_id | timestamp |
| 1 | 1 | 2012-01-01 |
| 2 | 1 | 2012-01-02 |
| 3 | 2 | 2012-01-02 |
What I am attempting to do is, given the record with 'id' 2, and similar records, for which the 'id' column value is known and is unique and the 'other_id' is known corresponding with it, how do I find, for each, the 'id' of the record having the same 'other_id' but the first lower 'id' than the one I already know.
E.g.
$arrKnownIds = array (
0 => array('id'=>2,'other_id'=>1),
1 => array('id'=>3,'other_id'=>2)
);
With this info, I'd like to run a query such that this results:
while($row = mysql_fetch_assoc($result)) {
$arrPreviousIds[$row['other_id']] = $row['id'];
// having in this case values of:
// $row['other_id'] = 2;
// $row['id'] = 1;
}
I can't quite work out if I need to tackle this using UNION, multiple php query statements or if there's another way.
Any thoughts on how to tackle this one are greatly appreciated.
Thanks :)
Edit - The original query takes the following form:
SELECT DISTINCT(`other_id`), MAX(`id`), MAX(`timestamp`)
FROM `event`
GROUP BY `other_id`
ORDER BY `id` DESC, `other_id` ASC
LIMIT 0, 10
// This is intended to get the last 10 unique events and find when they occurred.
// From this, I then try to find when they previously occurred.
How about this?
SELECT t1.id, (SELECT id
FROM tbl t2
WHERE t2.other_id = t1.other_id
AND t2.id < t1.id
ORDER BY t2.id DESC
LIMIT 1)
FROM tbl t1
WHERE t1.id IN (1,2,3)
There are more efficient ways of doing this if you will be dealing with large result sets. Can you explain exactly how you will be using this query?
UPDATE - based on addition of existing query to question here is an updated query to combine the two -
SELECT tmp.*, (SELECT `timestamp`
FROM `event`
WHERE `event`.`other_id` = `tmp`.`other_id`
AND `event`.`id` < `tmp`.`id`
ORDER BY `event`.`id` DESC
LIMIT 1) AS `prev_timestamp`
FROM (
SELECT `other_id`, MAX(`id`) AS `id`, MAX(`timestamp`) AS `timestamp`
FROM `event`
GROUP BY `other_id`
ORDER BY `id` DESC, `other_id` ASC
LIMIT 0, 10
) tmp
I have not tried this but it should give the desired result.

select mysql missing columns in php

i need to get the latest order (from our custon admin panel). here's my query:
select *
from order
left join customer
on (customer.id = order.fk_cid)
where date = curdate()
order by time desc
limit 1;
this output everything from orders and customers which i need except 1 therefore that is why i use the *
here's my table structure:
order table:
id, fk_cid, date, time
customer table:
id, name, lastname, street, city, zip, country, phone, email, lastlogin
now, in my php i have:
$result = mysql_query("
select *
from `order`
left join customer
on (customer.id = order.fk_cid)
where date = curdate()
order by time desc
limit 1");
$row = mysql_fetch_assoc($result, MYSQL_ASSOC);
at this point my order is not correct, why?
Your customers.id is overwriting the order.id because you are using the same column name.
select *
from `order`
left join customer on (customer.id = order.fk_cid)
where date = curdate() order by time desc limit 1;
+------+--------+------------+----------+------+-------+------
| id | fk_cid | date | time | id | name | ....
+------+--------+------------+----------+------+-------+------
| 1 | 2 | 2011-11-30 | 07:01:23 | 2 | asasd | ....
+------+--------+------------+----------+------+-------+------
1 row in set (0.03 sec)
As you can see in this example you have two id, so PHP when retrieve the data using mysql_fetch_assoc it overwrites the second id because it's the same key in the array. To fix this, you will have to specify the columns in your query:
select `order`.id AS order_id, customer.id AS customer_id, customer.name /* etc... */
This will output:
Also, I recommend to use different name for your tables and fields. order, date, time since they are reserved word (in case you forget for use the ` ).
Array
(
[order_id] => 1
[customer_id] => 2
// etc...
)
Also here's a topic you should read: Why is SELECT * considered harmful?

Select adjacent records in Mysql

Assuming this table is ordered by date
id | date | customer
3 | 2009-10-01| Frank
1 | 2010-10-11| Bob
4 | 2010-11-01| Mitchel
2 | 2010-11-02| Jim
I would like to make a query so that knowing ID = 4 the resulting rows are
$row[0]['id'] == 1 //previous
$row[1]['id'] == 4 //most recent/current
$row[2]['id'] == 2 //next
A mysql only solution would be best, but if there is an elegant php solution that would be cool as well.
As the table IS sorted by date column, you can run following queries to get it:
For previous row:
select * from tablename where `date` < (select `date` from tablename where id=4) order by `date` desc limit 1
For current row:
select * from tablename where id=4
For next row:
select * from tablename where `date` > (select `date` from tablename where id=4) order by `date` asc limit 1
Output: These three queries return the result (one by one) as following:
id date customer
1 2010-10-11 Bob
4 2010-11-01 Mitchel
2 2010-11-02 Jim
Since you are ordering by date, but basing the row you want the adjacent rows on id, your going to have to do 2 queries. The first to determine the date for the ID you have selected, the second to get the adjacent rows.
Step 1 - Get the date
Select date
FROM yourtable
WHERE id = 4
Step 2 - Get all the rows
SELECT *
FROM yourtable
WHERE date IN ( (select MAX( date ) from yourtable where date < $datefromquery1)
, $datefromquery1
, (select MIN( date ) from yourtable where date > $datefromquery1)
)
The LIMIT function can take two arguments, an offset and a number of rows to return. In your case, you want the offset to be (the number of rows with dates before the desired row) - 1, or in this case 2 - 1 = 1, and the number of rows to be three. So the SQL you want is
SELECT * FROM customers ORDER BY date ASC LIMIT 1,3;
and the number "1" will be the result of the query
SELECT COUNT(*)-1 FROM customers WHERE date > "2010-11-01";
I don't believe MySQL will let you use a subselect or function value as the argument of LIMIT, so you'll have to store that using PHP and construct the next query that way.

How to use DATEDIFF? How many days are inside of two dates

How to use DATEDIFF? How can I make this to work? or should I use DATEDIFF completly differently?
SELECT DATEDIFF('Started ','will_end') AS 'Duration' FROM my_table WHERE id = '110';
I try to get answer, how many days are inside of two dates.
I would like to get an aswer like:
Duration = 7 days;
I have this kind of database:
Started | will_end
2009-12-17 | 2009-12-24
2009-12-12 | 2009-12-26
Put will_end first, started second:
SELECT DATEDIFF('2009-12-24', '2009-12-17')
---
7
Also, remove the single quotes from your field names:
SELECT DATEDIFF(will_end, started) AS Duration
FROM my_table
WHERE id = 110
, or replace them with the backticks:
SELECT DATEDIFF(`will_end`, `started`) AS `Duration`
FROM `my_table`
WHERE `id` = 110
Are you getting a NULL result? You have the column names in single quotes in your query, which means you are passing the strings 'Started ' and 'will_end' to DATEDIFF rather than the column values. Try removing the single quotes, and you will start to see some results:
SELECT DATEDIFF(Started, will_end) AS Duration FROM my_table WHERE id = '110';
Note that this will give you a negative result. To get a positive result, reverse the order of the columns:
SELECT DATEDIFF(will_end, Started) AS Duration FROM my_table WHERE id = '110';
replace the order
DATEDIFF('will_end','Started')
I think there are 3 parameter to be passed in
DATEDIFF ( datepart , startdate , enddate )
so your code would be
DATEDIFF ( dd , 'Started ','will_end' )
http://msdn.microsoft.com/en-us/library/ms189794.aspx

Categories