MSSQL: Must declare the scalar variable #rownum - php

One of my queries is a ranking from a game.
The query is below and the error SQL Server Management Studio shows is: "Must declare the scalar variable #rownum"
what is wrong with it?
Thanks a lot!
$sql1_1 = "SET #rownum := 0";
$sql2_2 = "SELECT * FROM (
SELECT #rownum := #rownum + 1 AS rank, totalpoints, useridFB, game2points
FROM theuser ORDER BY game2points DESC
) as result WHERE useridFB=1234";
mssql_query($sql1_1);
$result = mssql_query($sql2_2);
$row = mssql_fetch_array($result);
$therank = $row['rank'];

You are using MySql syntax in SQL Server.
Use the row_number() function to reproduce your current logic.
SELECT *
FROM (SELECT row_number() OVER (ORDER BY game2points DESC) AS [rank],
totalpoints,
useridFB,
game2points
FROM theuser) AS result
WHERE useridFB = 1234
Or you might want to investigate rank depending on how you want ties to be treated.

Related

Using multiple SQL Statements to get single result query in PHP

I am looking to create 2 teams. After research, I have found that I can sort my table, then assign a "ranking" system in the new sorted order. Now, I am trying to pull just the odd number rows (and even number after I figure out odd).
This statement will do the sorting and ranking:
SELECT t.*, #rownum := #rownum + 1 AS weight FROM golfers t, (SELECT #rownum := 0) r WHERE trip_name_table_ID = 1 ORDER BY golfer_handicap
See SQLfiddle for visual.
So I am creating weight after the sorting. Now, I want to pull my data off of that weight column with this code I found for pulling Odd row (which should now be pulling odd number of weighted sort):
SELECT * FROM golfers WHERE weight IN(SELECT weight FROM golfers WHERE weight%2 <> 0);
How do I use both statements off of each other since weight is an AS column? and what would my
while($rowid = mysqli_fetch_array($result)) {}
look like?
If you want to select only the odd numbered rows from your SQL query then you should use weight%2=1 instead.
The full query should look like this:
SELECT * FROM (
SELECT t.*, #rownum := #rownum + 1 AS weight
FROM golfers t, (SELECT #rownum := 0) r
WHERE trip_name_table_ID = 1
ORDER BY golfer_handicap
) as t1
WHERE weight%2=0
I don't know why you are using while($rowid = mysqli_fetch_array($result)) {} but your mysqli result will contain the exact data that your query returned. You can use foreach instead though.
foreach($result as $row) {
echo $row['golfer_name'];
echo $row['weight'];
}

how to manipulate record's ID order?

I'm trying to select a group of list and get results in re-ordered number fashion.
e.g.
ID name
jack
jack
paul
bob
bob
paul
bob
Say I select name='bob' thus got its ID numbers 4,5,7
Now I want the results to be
in this order 1, 2, 3 ...
instead of 4, 5, 7 ...
because it's bob's first second and third, etc...
What's the easiest way to accomplish this?
Here mysql variables can do the work. Declare & initialize a variable #a = 0, assign an incremented value and select in query. The query should look like:
SET #a = 0;
SELECT #a := #a + 1 AS id, name FROM table_name WHERE name = 'bob';
SET #a = 0;
In the end, again set value of #a = 0.
If you are using Mysql 8 then you could use window function rank() and common table expression
with ordered_data as (
select *,
rank() over (partition by name order by id asc ) rnk
from your_table
order by rnk
)
select * from ordered_data where name = 'bob';
Or if you are using older release then you could use a correlated query to get the rank
select a.id,a.name,
(select count(*)
from your_table
where name= a.name
and id <= a.id) rnk
from your_table a
where a.name = 'bob'
order by a.id;
Demo

Make counter in sql query

I am using codeigniter and have working query which take user 3 images. I want to make a count an give every image a number 1,2,3,4,5,6,7 ... and want that query output
-number (count),
-id,
-image,
-date
my sql query :
function bar_images_first($user_id)
{
$sql = "SELECT id, image, UNIX_TIMESTAMP(date) as date FROM images WHERE user_id = 3 LIMIT 3";
$query = $this->db->query($sql, $user_id);
return $query->result_array();
}
Is it possible to do counter in query?
It is possible by setting a SQL parameter as
SET #cnt := 0;
SELECT
#cnt := #cnt + 1,
id,
image,
UNIX_TIMESTAMP(date) as date
FROM images WHERE user_id = 3 LIMIT 3";
But such multiple statements cannot be executed from the PHP's mysql_query() method. But, mysqli function like mysqli_multi_query() does allow to execute multiple queries too, so if possible use mysqli method rather than the AR methods.
However, you can run multiple sets of query one by one.
$query = array(
"SET #cnt := 0;",
"SELECT
#cnt := #cnt + 1,
id,
image,
UNIX_TIMESTAMP(date) as date
FROM images WHERE user_id = 3 LIMIT 3"
);
foreach($query as $qry) {
$result= $this->db->query($qry);
//.........
}
To run as a single query:
SELECT #curRow := #curRow + 1 AS row_number, id, image, UNIX_TIMESTAMP(date) as date
FROM images
JOIN (SELECT #curRow := 0) r
WHERE user_id = 3
LIMIT 3
This is very specific to MySQL though. If you want more portable code I would recommend making your row counter in code instead.
Edit - forgot to give due credit: MySQL - row number in recordset?

how to get the position of sorted rows using mysql and php

I have a table which stores high-scores, along with player ids. I want to be able to extract a record by a players id, and then get the rank, or position of their score in the table. Means, Basically I want to be able to say "you are in Nth" position, purely based on the players score against all other scores. For Example: if i am at 46th position then to me the position message will be like you are at 46th position out of total scores. Can anyone show me small example?
There are two ways of doing it:
Method 1:
SET #i = 0;
SELECT * FROM
scores s1 INNER JOIN (SELECT *, #i := #i + 1 AS rank FROM scores ORDER BY score DESC) AS s2 USING (id);
Method 2:
SELECT *, (SELECT COUNT(1) AS num FROM scores WHERE scores.score > s1.score) + 1 AS rank FROM scores AS s1
ORDER BY rank asc
This will provide duplicate rank values when there are duplicates:
SELECT t.playerid,
t.highscore,
(SELECT COUNT(*)
FROM TABLE x
WHERE x.playerid = t.playerid
AND x.highscore >= t.highscore) AS rank
FROM TABLE t
WHERE t.playerid = ?
IE: If three players have the same score for second place, they'll all have a rank value of two.
This will give a distinct value - three players tied for second place, only one will be ranked as 2nd:
SELECT x.playerid,
x.highscore,
x.rank
FROM (SELECT t.playerid,
t.highscore,
#rownum := #rownum + 1 AS rank
FROM TABLE t
JOIN (SELECT #rownum := 0) r
ORDER BY t.highscore DESC) x
WHERE x.playerid = ?
Here is an example.
You want to store the user's ID when they log in, like so...
$_SESSION['username'] = $usernamefromdb;
$_SESSION['id'] = $userid;
And then you want to open a session on every page on yoru website that you will be pulling dynamic information depending on the $_SESSION['id']
session_start();
Then find the row of data in the datebase according to the userID
$userid = $_SESSION['id'];
$rank_query = "SELECT * FROM table_name WHERE id='$userid'";
$rank_result = mysqli_query($cxn, $rank_query) or die("Couldn't execute query.");
$row = mysqli_fetch_assoc($rank_result)
Then using PHP, declare the nth postiion as a variable. And pull the total amount of rows from the DB
$rank = $row['rank'];
$all = $numrows = mysqli_num_rows($result);
echo out the players rank.
echo $rank . "out of" . $all;

Mysql Limit column value repetition N times

I have two tables
Customer (idCustomer, ecc.. ecc..)
Comment (idCustomer, idComment, ecc.. ecc..)
obviously the two table are joined together, for example
SELECT * FROM Comment AS co
JOIN Customer AS cu ON cu.idCustomer = co.idCustomer
With this I select all comment from that table associated with is Customer, but now I wanna limit the number of Comment by 2 max Comment per Customer.
The first thing I see is to use GROUP BY cu.idCustomer but it limits only 1 Comment per Customer, but I wanna 2 Comment per Customer.
How can I achieve that?
One option in MySQL is server-side variables. For example:
set #num := 0, #customer := -1;
select *
from (
select idCustomer
, commentText
, #num := if(#customer = idCustomer, #num + 1, 1)
as row_number
, #customer := idCustomer
from Comments
order by
idCustomer, PostDate desc
) as co
join Customer cu
on co.idCustomer = cu.idCustomer
where co.row_number <= 2
This version doesn't require the SET operation:
select *
from (select idCustomer
, commentText
, #num := if(#customer = idCustomer, #num + 1, 1) as row_number
, #customer = idCustomer
from Comments
JOIN(SELECT #num := 0, #customer := 1) r
order by idCustomer, PostDate desc) as co
join Customer cu on co.idCustomer = cu.idCustomer
where co.row_number <= 2
SELECT * FROM Comments AS cm1
LEFT JOIN Comments AS cm2 ON cm1.idCustomer = cm2.idCustomer
LEFT JOIN Customer AS cu ON cm1.idCustomer = cu.idCustomer
WHERE cm1.idComment != cm2.idComment
GROUP BY cm1.idCustomer
However, if you are going to change the number of comments it's better to use Andomar's solution.
There is no need to use cursor, which is very slow. See my answer to Complicated SQL Query About Joining And Limitting. DENSE_RANK will do the trick without all cursor intricacies.
If you are using a scripting language such as PHP to process the results, you could limit the number of results shown per customer after running the query. Set up an array to hold all the results, set up another array to hold the number of results per customer and stop adding the query results to the result set after the count exceeds your limit like so:
$RESULTS = array();
$COUNTS = array();
$limit = 2;
$query = "SELECT customer_id, customer_name, customer_comment FROM customers ORDER BY RAND()";
$request = mysql_query($query);
while ($ROW = mysql_fetch_assoc($request))
{
$c = $ROW['customer_id'];
$n = $COUNTS[$c];
if ($n<$limit)
{
$RESULTS[] = $ROW;
$COUNTS[$c]++;
}
}
This guarantees only two comments per customer will be shown pulled randomly or however you want, the rest gets thrown out. Granted you are pulling ALL the results but this is (probably) faster than doing a complex join.

Categories