Using Limit in SQL according to row_count - php

I want to fetch number of rows with highest number of multiple of 20, Like if my table have 148 rows then limit should be 140 leaving the latest 8 entry behind, or if my table have 170 rows then limit will be 160. What will be the query in this case.
$conn = mysqli_connect($server_name, $mysql_username, $mysql_password,
$db_name);
if($conn === false){
die("ERROR: Could not connect. " . mysqli_connect_error());
}
$number= $_POST['number'];
$sql1 = "SELECT * FROM abc_table LIMIT WHAT TO ENTER HERE ";

As far as I know, what follows LIMIT has to be an integer literal. LIMIT won't even take something like 6/2, which would evaluate to an integer literal. I recommend just reading in the entire table, and then only processing how many rows you need in PHP.
$row_cnt = $result->num_rows;
$rs_size = $row_cnt - ($row_cnt % 20);
while ($rs_size > 0 && $row = mysqli_fetch_assoc($result)) {
// process a row
--$rs_size;
}
The above while loop should exit after reading the greatest number of multiples of 20 available. This approach is not too wasteful, since at most you would be reading in 19 extra rows from MySQL which you would end up not using.

You can use variables for this:
select t.*
from (select t.*, (#rn := #rn + 1) as rn
from t cross join
(select #rn := 0) params
order by ?
) t
where rn <= floor(rn / 20) * 20;
The ? is for the column used to specify the ordering, presumably something like id asc.
In MySQL 8+, you would use window functions:
select t.*
from (select t.*,
row_number() over (order by ?) as seqnum,
count(*) over () as cnt
from t
) t
where seqnum <= floor(cnt / 20) * 20;

Related

Echo value and percentage from SQL server Union query in PHP

I have an issue where I'm trying to find the percentage of two queries but want to retain the session value to echo elsewhere. let me explain.
My first union query returns a value E.G. 100
$sql1 = "select COUNT(*) From
(select inc.INCIDENT_NUMBER as TICKET
From dbo.HELP_DESK as inc
Where inc.STATUS < 3
and inc.ASSIGNED_GROUP = 'Scheduling'
UNION ALL
SELECT chg.INFRASTRUCTURE_CHANGE_ID AS TICKET
FROM dbo.CHANGE as chg
WHERE chg.CHANGE_REQUEST_STATUS NOT IN (1,4,5,8,9,10,11,12)
and chg.ASGRP in = 'Scheduling') num1";
I then want to echo the result as a session value so:
$SCH = sqlsrv_query($conn,$sql1);
if( $SCH === false) {
die( print_r( sqlsrv_errors(), true) );
}
while( $Row = sqlsrv_fetch_array( $SCH, SQLSRV_FETCH_NUMERIC) ) {
$_SESSION['$SCH'] = $Row[0];
}
so far so good. However, I want to calculate the percentage based on my second union query.
$sql2 = "select COUNT(*) From
(select inc.INCIDENT_NUMBER as TICKET
From dbo.HELP_DESK as inc
Where inc.STATUS < 4
and inc.ASSIGNED_GROUP = 'Scheduling'
UNION ALL
SELECT chg.INFRASTRUCTURE_CHANGE_ID AS TICKET
FROM dbo.CHANGE as chg
WHERE chg.CHANGE_REQUEST_STATUS < 9
and chg.ASGRP = 'Scheduling') num2"
The second value is 250 as an example. So I'm trying to calculate the percentage e.g. (100/250) * 100 = 40%
function percentage ($sql1,$sql2)
{
return ($sql1/$sql2) * 100;
}
Echo percentage
The last bit pulls back nothing, blank screen. There's probably a much easier way of doing this and given my relative php newcomer status, I'm probably mixing up several functions at once.
I'd appreciate a little help getting it working. Thanks for taking the time to read.
Managed to resolve the percentage issues, can output seperate session values.
select
s.activeCount * 100 / s.totalCount as Percentage
FROM
(select activecount = (select COUNT(*) From
(select inc.INCIDENT_NUMBER AS TICKET
From dbo.HELP_DESK as inc
Where inc.STATUS < 3
and inc.ASSIGNED_GROUP = 'Scheduling'
UNION ALL
SELECT chg.INFRASTRUCTURE_CHANGE_ID AS TICKET
FROM dbo.CHANGE as chg
WHERE chg.CHANGE_REQUEST_STATUS NOT IN (1,4,5,8,9,10,11,12)
and chg.ASGRP = 'Scheduling') num),
totalCount = (select COUNT(*) From
(select inc.INCIDENT_NUMBER AS TICKET
From dbo.HELP_DESK as inc
Where inc.STATUS < 4
and inc.ASSIGNED_GROUP = 'Scheduling'
UNION ALL
SELECT chg.INFRASTRUCTURE_CHANGE_ID AS TICKET
FROM dbo.CHANGE as chg
WHERE chg.CHANGE_REQUEST_STATUS < 9
and chg.ASGRP = 'Scheduling') num)) s

Display number of duplicates from database [SQL]

This is my code.
$sqlcount = "SELECT count(*) AS C, Horse_ID FROM images WHERE Horse_ID = 24 GROUP BY Horse_ID HAVING COUNT(*) > 1 LIMIT 0, 30";
//echo $sqlcount;
$resultcount = $conn->query($sqlcount);
$rowcount = $result->fetch_assoc();
echo $rowcount['C'];
Why won't it echo the number 4, which is what shows when I test it in phpmyadmin? There are 4 duplicate values in that table hence the 4.
$rowcount = $result->fetch_assoc();
to
$rowcount = $resultcount->fetch_assoc();
If you want the number of duplicates in the database, why not write the query to get that value?
SELECT COUNT(*)
FROM (SELECT count(*) AS C, Horse_ID
FROM images
WHERE Horse_ID = 24
GROUP BY Horse_ID
HAVING COUNT(*) > 1
) i;
Then, you will only be returning one value from the database to the application (which is faster) and there is no need to artificially limit the count to 30.

mysql ranking for a single user

Im using a suggestion from Daniel Vassallo here to rank entries in my mysql table.
The suggestion doesn't deal with ties and thats the way I want it as a newer entry does not get a higher rank than an older entry with the same score on my scoreboard that way and it works for my needs.
My problem is that I want to be able to use this type of ranking to get the ranking for a single user. So from the output of this query I would like to define a name so that the script returns the rank, name and score of only that user.
I have tried a lot of different methods and as some of them deal with ties the results for a single user end up different from what is displayed in the results of the code below.
Your help would be greatly appreciated....going grey over this!
this is my current code:
it currently outputs:
rank name score
me 1111
me 1111
you 1110
<?php
include("common.php");
$link=dbConnect();
$limit = safe($_POST['limit']);
$query = "SELECT name, score, #curRank := #curRank + 1 AS rank
FROM $dbName . `scores`, (
SELECT #curRank := 0
) q
ORDER BY score DESC LIMIT $limit";
$result = mysql_query($query);
$my_err = mysql_error();
if($result === false || $my_err != '')
{
echo "";
}
$num_results = mysql_num_rows($result);
for($i = 0; $i < $num_results; $i++)
{
$row = mysql_fetch_array($result);
echo $row[rank] . " ". $row['name'] . " - " . $row['score'] . "\n";
}
?>
UPDATE
To clarify on ties; the original script will always increment regardless of ties this is how I want it to be because I don't want it so ties are ranked the same (no joint places) and it just so happens the script will favour the first person to achieve the score so that a new player can't knock him/her off the top spot with the same score, they have to beat it.
I know this is deprecated as I have seen in allot of similar posts but I'm just trying to get the skeleton built before I add the meat to the bones.
As kindly suggested by Spencer7593 I have tried the following code without much luck so far.
<?php
include("common.php");
$link=dbConnect();
$limit = safe($_POST['limit']);
$query = "SELECT name, score, #curRank := #curRank + 1 AS rank
FROM $dbName . `scores`, (
SELECT #curRank := 0
) q
ORDER BY score DESC LIMIT $limit";
$result = mysql_query($query);
$my_err = mysql_error();
if($result === false || $my_err != '')
{
echo "";
}
$num_results = mysql_num_rows($result);
while ($row = $result->fetch_assoc()) {
if ( $row['rank'] == 'you' )
{
// output this row because it's for the specified user
echo $row['name'];
}
else
{
continue;
}
}
?>
To get rankings for a single user extracted from the query results, you could run through the results in PHP, just like you are doing, but "skip" the output of rows that aren't for the specified user.
There's no need for a for ($i=0;i< loop. Use a "while fetch" loop. (I'm loathe to give you any example code using the deprecated mysql interface; new development should use either mysqli or PDO.)
while ($row = $result->fetch_assoc()) {
if ( $row['name'] == 'you' ) {
// output this row because it's for the specified user
echo $row['rank'];
} else {
// skip this row
}
}
You make some noise about handling "ties", but what's not clear what you actually want as output. If you want rows that have the same value for "score" have the same value for rank, just handle that in your query. If the score on the current row matches the score from the previous row, don't increment the rank. e.g.
SELECT #curRank := IF(s.score=#prev,#curRank,#curRank + 1) AS rank
, s.name
, #prev := s.score AS score
FROM $dbName . `scores` s
CROSS
JOIN (SELECT #curRank := 0, #prev := NULL) q
ORDER BY s.score DESC
LIMIT $limit
Including potentially unsafe values into the SQL text leads to SQL Injection vulnerabilities; we're going to assume that you've guaranteed the values of $dbName and $limit are safe.
If you want the query to filter out rows for a particular name, then wrap that query in parens and reference it as an inline view, e.g.
SELECT v.rank
, v.name
, v.score
FROM ( SELECT #curRank := IF(s.score=#prev,#curRank,#curRank + 1) AS rank
, s.name
, #prev := s.score AS score
FROM $dbName . `scores` s
CROSS
JOIN (SELECT #curRank := 0, #prev := NULL) q
ORDER BY s.score DESC
LIMIT $limit
) v
WHERE v.name = 'you'
ORDER BY v.rank ASC

SQL query construction

I recently created a scoring system where the users are ordered by their points on descending basis. First I used to store ranks in a column of its own. I used to run this loop to update the rank:
$i = 1;
$numberOfRows = mysql_query('SELECT COUNT(`id`) FROM sector0_players');
$scoreboardquery = mysql_query("SELECT * FROM sector0_players ORDER BY points DESC");
while(($row = mysql_fetch_assoc($scoreboardquery)) || $i<=$numberOfRows){
$scoreid = $row['id'];
$mysql_qeury = mysql_query("UPDATE sector0_players SET scoreboard_rank = '$i' WHERE id = '$scoreid'");
$i++;
}
And it was really hard, not to mention slow to actually run this on a huge amount of users.
Instead, I tried to construct a query and ended up with this.
SET #rownum := 0;
SELECT scoreboard_rank, id, points
FROM (
SELECT #rownum := #rownum + 1 AS scoreboard_rank, id, points FROM sector0_players ORDER BY points DESC
)
as result WHERE id = '1';
But, this is just a select statement. Is there anyway I could get around it and change it so that it updates the table just as the loop does?
Please try using the following query :
set #rownum:=0;
update sector0_players set scoreboard_rank=#rownum:=#rownum+1 ORDER BY points DESC;
PHP code can be ,
mysql_query("set #rownum:=0;");
mysql_query("update sector0_players set scoreboard_rank=#rownum:=#rownum+1 ORDER BY points DESC;");
You can try using the RANK function .. I haven't actually executed the SQL, but it should work
UPDATE sector0_players
SET scoreboard_rank =
(
SELECT srank
FROM
(
SELECT id,points, RANK() OVER (ORDER BY points) AS srank
FROM sector0_players T
) D
WHERE D.id = sector0_players.id
AND D.points = sector0_players.points
)

MySQL query returns rows in mysql but empty set in PHP

The following MySQL query runs in PHP without errors, but the resultset is empty. Directly outputting the query string to a file and running the query in the MySQL client using 'source [filename]' returns several rows of results, as expected.
Is there something that would cause this query not to work with PHP? categorylinks.cl_to and smw_spec2.value_string are both varbinary(255). Show create table indicates engine=InnoDB and default charset=binary.
Things I have tried without success:
$sql = preg_replace("/[\n\t]+/", " ", $sql);
Changing '_wpg' and 'Derp' to CAST('_wpg' AS BINARY(255))
Changing '_wpg' and 'Derp' to BINARY '_wpg'
I am using the MediaWiki DatabaseMysql class to execute the query and fetch rows, but it's a very thin abstraction, and I'm certain it's not the problem (see below).
SELECT
prop.name AS prop_name, prop.count AS prop_count, prop.type AS prop_type,
val.value AS val_value, val.unit AS val_unit, val.count AS val_count
FROM
(
SELECT
s_id, name, type, COUNT(foo.name) AS count
FROM (
(
SELECT
cl.cl_to AS cat_name, s.smw_id AS s_id, s.smw_sortkey AS name, spec.value_string AS type
FROM `smw_ids` s
INNER JOIN (`categorylinks` cl, `page` p, `smw_ids` s2, `smw_atts2` a)
ON (cl.cl_from = p.page_id AND
p.page_title = s2.smw_title AND
s2.smw_id = a.s_id AND
a.p_id = s.smw_id)
LEFT JOIN `smw_spec2` spec ON s.smw_id = spec.s_id
)
UNION ALL
(
SELECT
cl.cl_to AS cat_name, s.smw_id AS s_id, s.smw_sortkey AS name, '_wpg' AS type
FROM `smw_ids` s
INNER JOIN (`categorylinks` cl, `page` p, `smw_ids` s2, `smw_rels2` a)
ON (cl.cl_from = p.page_id AND
p.page_title = s2.smw_title AND
s2.smw_id = a.s_id AND
a.p_id = s.smw_id)
)
) AS foo
WHERE foo.cat_name = 'Derp'
GROUP BY name
ORDER BY count DESC
LIMIT 10
) AS prop
INNER JOIN
(
SELECT
bar.p_id AS p_id, bar.value AS value, bar.unit AS unit, COUNT(bar.value) AS count,
IF( #prev != p_id, #rownum := 1, #rownum := #rownum+1 ) AS rank,
#prev := p_id
FROM (
(SELECT a.p_id AS p_id, a.value_xsd AS value, a.value_unit AS unit FROM `smw_atts2` a)
UNION ALL
(SELECT r.p_id AS p_id, s.smw_sortkey AS value, NULL AS unit
FROM `smw_rels2` r INNER JOIN `smw_ids` s ON r.o_id = s.smw_id)
) AS bar
GROUP BY value, unit
ORDER BY count DESC
) AS val
ON prop.s_id = val.p_id
WHERE val.rank <= 50
ORDER BY prop_count DESC, prop_name, val_count DESC, val_value
Edit: The following test script outputs nothing. query.sql contains exactly the query above, written to file immediately preceding the mysql_query() call in MediaWiki's database class.
$db = mysql_connect('localhost', 'root', '');
mysql_select_db('mediawiki', $db);
$res = mysql_query(file_get_contents("query.sql"), $db);
while ($row = mysql_fetch_assoc($res)) {
var_dump($row);
}
echo mysql_error($db);
Edit: I imported a huge database dump and afterwards, when I loaded the PHP page, there was a noticeable wait that seemed to indicate that the query was running, but still no results showed. I ended up reworking the query, and I no longer have this problem.
Try this to detect and report errors better:
$db = mysql_connect('localhost', 'root', '');
mysql_select_db('mediawiki', $db);
$res = mysql_query(file_get_contents("query.sql"), $db);
if (!$res) {
print "SQL Error ".mysql_errno().":".mysql_error().", from query: '".file_get_contents("query.sql")."'";
} else {
while ($row = mysql_fetch_assoc($res)) {
var_dump($row);
}
}
Try this after mysql_connect:
mysql_query('SET NAMES utf8;');

Categories