Know lower value and its column name from select - php

I have a PHP document with MySQL database storing with the following structure:
DATE FIELD
24 float values corresponding to the 24 hours. (The name is 1h, 2h, 3h, 4h... 24h)
I fetch a row with the simple select: SELECT * from table where DATE = "2014-02-02" obtaining the 25 fields.
I want to know wich field of 1h, 2h, 3h.... has the lower value. I'm trying doing that with PHP and min() function, but I only retreive the value, not the index of the array.
Is this possible a simple way to know this result? Maybe in the SQL function?
Thank you
EDIT: I tried this (Considering $arraySQL has a valid result obtained before):
function ObtainArrayFromSQL($arraySQL){
$array = array();
for ($i = 1; $i < 25; $i++)
{
array_push($array, $data_day[$i."h"]);
}
return $array;
}
[...]
$array = ObtainArrayFromSQL($arraySQL)
echo min($array);

Assuming you are using MySQL, you can use the least() function:
select t.*,
(case when col1 = leastval then 'col1'
when col2 = leastval then 'col2'
when col3 = leastval then 'col3'
. . .
when col24 = leastval then 'col24'
end) as leastvalcol
from (select t.*,
least(col1, col2, . . . , col24) as leastval
from table t
) t;
Before complaining about all the typing you need, you should know that this query is much more complicated than it needs to be -- because you are storing things on a row that should be in a column. Your table should have a separate row for each hourly value, rather than putting all the daily values on one row. With a more normalized structure, your query would be much simpler.
EDIT:
This table would have columns such as:
Date date,
Hour time, -- or int or varchar() depending on how you really want it captured
Value float
Then the query might look like:
select date, min(value) as minvalue,
substring_index(group_concat(hour order by value asc), ',', 1) as minhour
from newtable t
group by date;

At first, thank you everyone for the help.
Finally I made the solution with PHP instead of manipulate a big SQL sentence.
I create the array using the function ObtainArrayFromSQL, and then, use the function array_search() with min() as needle in the haystack (array).
function ObtainArrayFromSQL($arraySQL){
$array = array();
for ($i = 1; $i < 25; $i++)
{
array_push($array, $data_day[$i."h"]);
}
return $array;
}
...
$index_lower_value = array_search(min($array), $array);
Thank you everyone!

Related

select count doesn't count

I try to build a variable that integrates some other variable.
one of that will be the number of an auto-increment-field where later on an insert-query will happens.
I tried to use:
$get_num = $db/*=>mysqli*/->query("SELECT COUNT (*) auto_increment_column FROM table1");
$num = $query->fetch_assoc($get_num);
$end = $num + 1;
I don't have any update/insert query before that so I can't use
$end = $db->insert_id;
that's why i thought i can just count the numbers of the auto_increment rows and have my last variable that is necessary to build my new variable.
for a reason this wonT count the entries and outputs 0. i dont understand why this happens.
i really would appreciate if there is someone who could tell me what am i doing wrong. thanks a lot.
UPDATE
For everyone who likes to know about what's the goal:
I like to create a specific name or id for a file that later on will be created by the input of the fields from the insert query. I like to have an unique key. this key consists of an user_id and a timestamp. at the end of this generated variable it should be placed the auto_increment nr. of the query that will be placed in the table. so the problem is, that I create an variable before the insert query happens so that this variable will be part of the insert query like:
$get_num = $db->query("SELECT COUNT (*) FROM tableA");
$num = $query->fetch_assoc();
$end = $num + 1;
$file_id = $id .".". time() .".". $end;
$insert = $db->query("INSERT INTO tableA ( file_id, a, b, c) VALUES('".$file_id."','".$a."','".$b."','".c."')");{
hope now, it will be clear what I like to approach.
If you need an auto-incrementing column in MySQL then you should use AUTO_INCREMENT. It implements it all for you and avoids race conditions. The manual way you are trying to implement it has a couple of flaws, namely
If two scripts are trying to insert concurrently they might both get the same COUNT (say 10) and hence both try to insert with ID 11. One will then fail (or else you will have duplicates!)
If you add 10 items but then delete item 1, the COUNT will return 9 but id 10 will already exist.
try
SELECT COUNT(*) FROM table1

PHP MySQL - Find Row ID

I have a table called "participants" that has 3 fields:
prt_id
prt_event_id
prt_participant_id
What I have is a select query with a where condition on event_id. The query returns let's say 20 rows (20 different participants). What I would like to do is to be able to figure out the row number for a given participant (prt_id).
SELECT *
FROM participants
WHERE prt_id = someinteger
While you can't specifically find a row ID using MySQL, you could do something like the following:
$conn = new mysqli(/*dbinfo*/);
$res = $conn->query("SELECT prt_id FROM participants");
$rowids = array(); $currid = 1;
while ($row = $res->fetch_object()) { // this is using the mysqli library
$rowids[$row->prt_id] = $currid;
$currid++;
}
This would give you an array of ids associated with prt_id.
You could do something like:
<?php
$counter = 1; // Start at one for first entry
$res = mysql_query("SELECT * FROM participants WHERE prt_id = 12");
while( $array = mysql_fetch_assoc($res) )
{
// Do something with the counter, store it into array with details
$counter++;
}
?>
This should do what you want inside MySQL (ie assign a rownum in the order of prt_id), but the performance will be dependent on the number of rows in the table so it's not optimal.
SELECT * FROM (
SELECT #tmp:=#tmp+1 rownum, p.*
FROM (SELECT #tmp:=0) z, participants p
ORDER BY prt_id
) participants
WHERE prt_id = 36;
Demo here.
Edit: This "doh level" rewrite uses an simple index range instead of a table scan, so should be much faster (provided prt_id is a PRIMARY KEY)
SELECT *, COUNT(p2.prt_id) ROWNUM
FROM participants p1
JOIN participants p2
ON p1.prt_id >= p2.prt_id
WHERE p1.prt_id=36;
Demo here.
you could just add an index column in your database, set it as int, primary key and auto increment. then when retrieving the row you retrieve the index number.
RowID is a feature of Oracle: http://docs.oracle.com/cd/B19306_01/server.102/b14200/pseudocolumns008.htm.
MySQL does not have something like that, you can basically emulate that by assign number to an array inside php as you retrieve each row, but that doesn't guarantee you the same number next time you retrieve that results. You probably have to settle for using one of the primary IDs

Updating several records in a database with increasing value

I need to update several records in a table, and am hoping to accomplish it in one query.
I have a php array of id's for a few of the records in my table. The array is in a specific order, and I need to update a value for each id with the position/key that the id is in the array. I could easily loop through each value in the array and run a query for each record that needs to be updated, but I am looking for a way to possibly update each record in one query.
The following will give me the desired result, but I am looking for a one query solution.
$ID = array('3','2','6','5','9');
for($i = 0; $i <= 4; $i++){
$q = "UPDATE table SET blah = ".$i." WHERE id = ".$ID[$i];
mysql_query($q) or die();
}
Thanks.
2 queries:
First only needed in case you have used #var already.
SET #var := -1;
And then (note FIND_IN_SET wants a comma-separated string):
UPDATE tablename
SET blah = #var := #var +1
WHERE id IN (3,2,6,5,9)
ORDER BY FIND_IN_SET(id,'3,2,6,5,9');
If you have an array with key=>postition pairs, this could be used:
$array = array(2 => 40,3 => 12,5 => 8,6 => 9,9 =>13129);
mysql_query("
UPDATE bla
SET blah = ELT(
FIELD(id,".implode(',',array_keys($array))."),
".implode(',',$array).")
WHERE id IN (".implode(',',array_keys($array)).")");
A big long ugly if or case statement would do the trick:
UPDATE ...
SET blah = IF(id=3,1,IF(id=2, 2, IF(id=6,3, IF....))))
WHERE id IN (3,2,6,....)
it'd quickly become unmanageable, but it would accomplish things in a single query. A slightly cleaner, more portable alternative:
UPDATE
SET blah = CASE id WHEN 3 THEN 1 WHEN 2 THEN 2 WHEN 6 THEN 3 .... END CASE
WHERE id in (3,2,6,...)
Try this:
INSERT INTO tbl_name (idCol, valCol) VALUES (id1, value1),(id2, value2)
ON DUPLICATE KEY UPDATE
idCol = VALUE(idCol),
valCol = VALUE(valCol)
You could also use a stored procedure, passing it a string of the ID's:
CREATE PROCEDURE updateItems( firstNum INT NOT NULL, ids TEXT NOT NULL) BEGIN
#id := ... # Some expression to get the first ID.
WHILE id != "" DO
SET ids := ... # Some expression to get the rest of the string.
UPDATE table SET blah = firstNum WHERE id = #id;
SET firstNum = firstNum +1;
#id := ... ;
END;
END $$
Also, there was one trick with LAST_INSERT_ID() - if you call it with a param, like LAST_INSERT_ID( 123 ), successive call to LAST_INSERT_ID() will give you 123.
Could be used together with #variables to achieve that goal.
You might get some inspiration here: http://ondra.zizka.cz/stranky/programovani/sql/mysql_stored_procedures.texy
It's impossible in this way ...Well, it's possible but I'd suggest you not to do it, 5 queries aren't horrors
$q = "UPDATE table SET blah = ".$i." WHERE id in ('3','2','6','5','9')";
If you are concerned about performance, you should take a look at using prepared statements and transactions.
There is most likely a solution to doing this in one single query, but it would most likely get really messy.
your better of using foreach then you don't have to set a $i limit.
i think its quick to do it this way
$id = array('3','2','6','5','9');
$i=0;
foreach ($id as $v){
$q = "UPDATE table SET blah = ".$i++." WHERE id = '$v'";
mysql_query($q) or die();
}

sort an $array of ints by repetition and remove repetitions

i need to do this in php
lets say i have [1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,3,4,5,5,5,5,5,5,5,5,5,5,5,9,9,9,9,9]
i would like [1,5,9,2,3,4]
but my situation its a bit different, it's result from a mysql query
i have only an asociative atribute 'id_deseada', so i do now
while($row = mysql_fetch_array($result){
$t = $row['id_deseada'];
}
so instead of that, i guess i'd have to do domething like the first example; sort $result ordered by times of repetition and maybe beetter in a new array with a new field 'count' ?
This all begins because of this query:
SELECT articles.id as id_deseada,tags.* FROM articles,tags WHERE tags.id_article = articles.id AND tags.name IN ('name one','name two','form search inputs','...)
the problem is that returns one result for every tag and i want on result for every article..
First, generate the value array like this:
$vals = array();
while($row = mysql_fetch_array($result){
$vals[] = $row['id_deseada'];
}
Then, count and sort:
$valCounts = array_count_values($vals);
arsort($valCounts);
$result = array_keys($valCounts);
You can actually do it using an SQL query. For example, we have this table:
create table lol (id_deseada int);
insert into lol values (1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(2),(3),(4),(5),(5),(5),(5),(5),(5),(5),(5),(5),(5),(5),(9),(9),(9),(9),(9);
You can select the id_deseada's from the database sorting by repetitions by using grouping and ordering.
SELECT id_deseada FROM lol
GROUP BY id_deseada
ORDER BY COUNT(*) DESC
Result: 1, 5, 9, 2, 3, 4.

How to find missing data either in array or in mySQL table?

I have an array filled with values (twitter ids) and I would like to find the missing data between the lowest id and the highest id? Any care to share a simple function or idea on how to do this?
Also, I was wondering if I can do the same with mySQL? I have the key indexed. The table contains 250k rows right now, so a temporary table and then a join wouldn't be very fast or efficient. I could do a PHP loop to loop through the data, but that would also take a long time, and a great deal of memory. Is there a specific mysql query I can run? or can I somehow use the function from above with this?
Thanks,
James Hartig
http://twittertrend.net
I had a similar requirement and wrote a function that would return a list of missing IDs.
---------------------------
create function dbo.FreeIDs ()
---------------------------
returns #tbl table (FreeID int)
as
begin
declare #Max int
declare #i int
select #Max = MAX(ID) from [TheTable]
set #i = 0
while #i < #Max begin
set #i = #i + 1
if not exists (select * from [TheTable] where ID = #i)
insert into #tbl select #i
end
return
end
Do you mean sequential ID's?
In that case
$new_ids = range($lowid, $highid, 1);
$ids = array_merge($ids, $new_ids);
$ids = array_unique($ids);
sort($ids);
And in SQL (with placeholders)
SELECT key, other_data from `table` WHERE key > :low_id AND key < :high_id
Your range() gave me a good idea, your code didn't work as unique preserves unique keys, so I was just left with the range functions result.
However, this worked:
$diff = array_values(array_diff(range(min($array), max($array), 1), $array)); //returns array of incomplete values

Categories