Total of an array using only top 3 values - php

With help from a fellow member I have been able to add together the values of an array called by a MySQL query. However, the code I have is adding up all values.
$top_1st = mysql_fetch_array(mysql_query("SELECT SUM(1ET)/10 AS top_1st
FROM scoring_data WHERE Competition='$competition' AND Club='$row[Club]'
AND Team='$row[Team]' ORDER BY 1ET DESC LIMIT 0, 3"));
echo $top_1st[0] ;
I have used
LIMIT 0, 3
as I only want to add up the highest 3 values from the query returned, but this doesn't seem to work.
Apologies if there is a simple solution; novice skills really being put to the test!
EDIT
Advice from #marc-b (thanks) has led me to this, however it is giving a blank return.
$top_1st = mysql_fetch_array(mysql_query("
SELECT SUM(1ET)/10
FROM (
SELECT 1ET AS top_1st FROM scoring_data WHERE Competition='$competition' AND
Club='$row[Club]' AND Team='$row[Team]' ORDER BY 1ET DESC LIMIT 0, 3 ) "));
echo $top_1st[0] ;

You need to get the top 3 values first, then sum in another query, e.g.
SELECT SUM(foo)
FROM (
SELECT whatever AS foo
FROM ...
LIMIT 3
)
The limit has to be applied in the inner query. Otherwise you'd be summing up to a single row, which would then fall within the 3-row limit anyways.

Related

php pg_fetch_array only show first result

i query to check if a point(input) is intersect with polygons in php:
$sql1="SELECT ST_intersects((ST_SetSRID( ST_Point($startlng, $startlat),4326))
, zona_bahaya.geom) as intersek
FROM zona_bahaya";
$query1 = pg_query($conn,$sql1);
$check_location = pg_fetch_array($query1);
if (in_array('t',$check_location)) {
dosemthing1;}
else {dosomething2;}
it's work peroperly before i update the data
after data updated, it's only show the first row when i check the pg_fetch_array result. here is the result {"0":"f","intersek":"f"} .
i try to check from pgadmin and it's can show 8 result (1 true(intersected) and 7 false(not intersect)) using updated data with this query:
SELECT ST_intersects((ST_SetSRID( ST_Point(110.18898065505843, -7.9634510320131175),4326))
, zona_bahaya.geom) as intersek
FROM zona_bahaya;
to solve it, i order the query result descended so the 'true' gonna be the first like this:
order by intersek desc
anybody can help me to findout way it just only show the first row???
here some geom from STAsText(zonabahaya.geom) not all of them : MULTIPOLYGON(((110.790892426072 -8.19307615541514,110.791999687385 -8.19318330973567,110.794393723931 -8.1927980624753,110.794586347561 -8.19205508561603,110.795329324421 -8.19120203811094,110.796540101525 -8.19023891996003,110.797503219676 -8.18933083713203,110.798576408472 -8.18919324882476,110.79929186767 -8.18957849608512,110.800337538805 -8.19059664955894,110.800585197758 -8.19150473238694,110.80022746816 -8.19238529755349,110.799787185576 -8.19290813312112,110.799589319279 -8.19300706626968,110.798788231202 -8.19299429992581,110.798537293576 -8.19311976873883,110.79850269889 -8.1933090511224,110.798620939451 -8.19433728092441)))
In order to filter only the records that intersect you have to use ST_Intersects in the WHERE clause:
SELECT *
FROM zona_bahaya
WHERE ST_Intersects(ST_SetSRID(ST_Point(110.18, -7.96),4326),zona_bahaya.geom);
Since you're dealing with points and polygons, perhaps you should take a look also at ST_Contains.
In case you want to fetch only the first row you must set a limit in your query - either using LIMIT 1 or FETCH FIRST ROW ONLY -, but it would only make sense combined with a ORDER BY, e.g.
SELECT *
FROM zona_bahaya
JOIN points ON ST_Intersects(points.geom,zona_bahaya.geom)
ORDER BY gid
FETCH FIRST ROW ONLY;
Demo: db<>fiddle

how to get last 10 and then show random 5

hello all i am a php developer and right now i am having a simple issue like i want to get the last 10 data out of my database table and then show random 5 out of them .
like see the code below.
$random=rand(0,18);
mysqli_query(
$connection,
"SELECT something1,something2
FROM `table`
where (id !='0')
ORDER BY time DESC
LIMIT 4 OFFSET $random");
this query selects last 4 updated fields randomely out of 18 but i want a something better solution to this
First, define "the last 10"; for now let's assume the last ten when ordered by time. So, that is in fact the first ten when I order them the order way (I guess you got that):
SELECT * FROM `table` WHERE (id != '0') ORDER BY time DESC LIMIT 10;
then we subselect that to randomize and limit:
SELECT * FROM (
SELECT * FROM `table` WHERE (id != '0') ORDER BY time DESC LIMIT 10;
) A ORDER BY RAND() LIMIT 5
Remember, your database is extremely powerful and fast, use it for any data-processing.
Not sure there is a great solution with Select. Your sample take 4 line in a row with an OFFSET which is not a truly random selection. You should limit your select to 10 and then get 5 row of the 10 by another php code.
$rows = mysqli_query($connection,
"SELECT something1,something2 FROM `table` where (id !='0')
ORDER BY time DESC LIMIT 10");
//then, get 5 random key from your array of row from the mysql select
$rand_keys = array_rand($rows, 5);
In case you prefer randomizing in PHP, you can use PHP's shuffle and array_slice.
<?php
$last_10_rows = mysqli_query($connection, "simple query to get last 10 rows");
shuffle($last_10_rows); // randomize the array
$random_5_rows = array_slice($last_10_rows, 0, 5); // take first 5
?>
For

How to count if value of a variable is repeated?

I am learning how to work with MySQL, and at the moment I succeed to show data from my table, using:
while($objResult2 = mysqli_fetch_assoc($objQuery_product)) {
Results are shown by using this variable $objResult2["id_product"]; this way i can take from DB any field I want like: $objResult2["name"]; $objResult2["email"]; etc.
But what i do if i have in the table more rows with the same id_product?
I want to write a if statment, which counts if id_product repeats. How to do that? If it is a lot of work, atleast please give me an idea of the right tutorial that I must read. Because i am trying second day to fix this, and searched google but i didnt find what i need, or maybe i coulndt understand it....
This is my query
$sql_product = "SELECT * FROM ps_product AS prod";
$join_product = " LEFT JOIN ps_product_lang AS lang ON lang.id_product = prod.id_product";
$join2_product = " LEFT JOIN ps_stock_available AS stok ON stok.id_product = prod.id_product";
$where_product =" WHERE prod.id_category_default = $idp AND lang.id_lang = 8";
$sql_product = $sql_product.$join_product.$join2_product.$where_product;
$objQuery_product = mysqli_query($objConnect, $sql_product) or die ("Error Query [".$sql_product."]");
You can simple remove the same id_product using DISTINCT keyword in your query. Such as:
SELECT DISTINCT id_product FROM my_table
This will give you results with different ids only.
The second way of doing it is taking the output values inside an array.
In your while loop:
$my_array[] = $objResult2["id_product"];
Then using array_filter remove all the duplicates inside the array.
YOu can also use array_count_values() if you want to count the duplicate values.
Ok here we go. For example you are fetching data with this query.
select id_product, name from PRODUCTS;
Suppose above query gives you 5 records.
id_product name
1 bat
2 hockey
2 hockey
3 shoes
4 gloves
Now you got 2,2 and hockey, hockey. Instead of thinking this way that you have to introduce an if statement to filter repeating records or same name or id_product records.
Rewrite your sql query like this.
select distinct id_product, name from PRODUCTS;
Or if you need count of each then my friend you will write your query something like this...
Graham Ritchie, if Andrei needs count of each repeating record then we will do something like this in our query.
SELECT PRODUCT_ID,
COUNT(PRODUCT_ID) AS Num_Of_Occurrences
FROM PRODUCTS
GROUP BY PRODUCT_ID
HAVING ( COUNT(PRODUCT_ID) > 1 );
SELECT id_product,COUNT(*) AS count
FROM tablename
GROUP BY id_product;
This query will then return you two items in your query
$objResult2["id_product"] //and
$objResult2["count"]
The if statement is then just
if($objResult2["count"] > 1){
//Do whatever you want to do with items with more than 1 occurence.
//for this example we will echo out all of the `product_id` that occur more than once.
echo $objResult2["id_product"] . " occurs more than once in the database<br/>";
}

Did I mess up my where clause? Getting unexpected results

$active_sth = $dbh->prepare("SELECT * FROM user_campaign
WHERE status='blasting'
OR status='ready'
OR status='followup_hold'
OR status='initial_hold'
AND uid=:uid
ORDER BY status ASC");
$active_sth->bindParam(':uid', $_SESSION['uid']['id']);
$active_sth->execute();
I am positive $_SESSION['uid']['id'] = 7
but it will also pull results of id 10 or any other number.
Is my AND/OR clause written wrong?
Yes, query is wrong
SELECT * FROM user_campaign
WHERE (
status='blasting'
OR status='ready'
OR status='followup_hold'
OR status='initial_hold'
)
AND uid=:uid
ORDER BY status ASC
You have to group all ORs to make sure that row got one of this values, and separately check if it have given uid.
The proper way to write that is:
SELECT * FROM user_campaign
WHERE status IN ('blasting', 'ready', 'followup_hold', 'initial_hold')
AND uid =: uid
ORDER BY status ASC
You should use IN instead of that huge amount of ORs :)

Mysql Order by Tweak

I have a database with nearly 100 fields.
DB structure is
id | comment | time
I need to fetch only 5 newest record (I can get those records using ORDER by time DESC). But while printing them I need to print the oldest of those 5 records first and proceed in reverse in a way that the newest record will be printed last.
SELECT s.* FROM (
SELECT id, comment, time FROM table1
ORDER BY time DESC
LIMIT 5 ) as s
ORDER BY s.time ASC
Ok, after fetching result set in ascending order with a limit of number of rows
you can do this to print them in reverse order (descending order)
$data= array();
while ($row = mysql_fetch_assoc($result)) {
$data[] = $row;
}
$records = array_reverse($data);
OR
This could be done with mysql_data_seek
Directly taken from here
for ($i = mysql_num_rows($resultset) ā€“ 1; $i >= 0; $iā€“) {
mysql_data_seek($resultset, $i);
$row = mysql_fetch_assoc($result);
echo $row['abc'] . ' ' . $row['xyz'] . "\n";
}
You can use PHP's array_reverse() function on your result list.
http://php.net/manual/en/function.array-reverse.php
You can use also something like this:
select * from (select * from table_name where 1=1 order by time desc
limit 5) as tbl order by tbl.time;
Edit if you have a lot of accesses to this statement it would be much better to represent it as materialized view. Though there are no materialized views in mysql it is possible to simulate them (http://lists.mysql.com/mysql/207808)
Using a materialized view or a simulated materialized view will seriously outperform the suggested php approaches. Most of the mentioned ones consume to much memory anyways .
I guess you could do something along the lines of (untested):
SELECT
*
FROM (
SELECT
id, comment, time
FROM
table
ORDER BY
time DESC
LIMIT 5
)
ORDER BY
time ASC
UPDATE
Apparently, the "derived table must have its own alias" (error #1248). Other answers have already done this, so I'll jump on the bandwagon. Below you'll find the revised (and tested) query:
SELECT
derived.*
FROM (
SELECT
id, comment, time
FROM
table
ORDER BY
time DESC
LIMIT 5
) AS derived
ORDER BY
derived.time ASC
By the way, this is supported as of MySQL 4.1.

Categories