How to count the number of rows before a given row in MySQL with CodeIgniter? - php

Simply put, how can I count how many rows there are before a certain row. I'm using incremental ID's, but rows are deleted a random, so just checking to see what the ID is won't work.
If I have, say, 30 rows, and I've selected one based on a name (or anything really), how many rows are there before that one? It could be 16, 1, 12, or anything.
I'm using MySQL and CodeIgniter.

I assume your primary key column has datatype integer
SELECT COUNT(*) FROM `table`
WHERE id < (SELECT id FROM `table` WHERE `conditions are met for specific row`)

Assuming it's an auto_increment column, deleted rows won't be filled in again so this should do the job.
SELECT COUNT(*) FROM table WHERE id_column < your_selected_row_id;

On your model:
$id = $this->db->get('users')->where("name", "John")->id;
$rows = $this->db->get('users')->where("id < ", $id)->num_rows();
return $rows;
Notice how I'm using "chained methods" and for that you need PHP5 which is the default for CI 2.
You first need to get the ID of the record you need to start counting "backwards" which is the first line, considering a table called users and that the column you are filtering is "name" and the row you want to find has the name value of John.
The second line will give you the number of rows that the query "where id < number" returned where number is the ID you got from the first query. Maybe you can even chain both lines.

Related

Mariadb: Pagination using OFFSET and LIMIT is skipping one row

I have this MariaDB table:
id, name
The id column has these attributes: Primary, auto_increment, unique.
The table has 40,000 rows.
I'm using this PHP & MariaDB to load rows from this table.
This is the PHP code:
$get_rows = $conn->prepare("SELECT * FROM my_table where id> 0 ORDER BY id ASC LIMIT 30 OFFSET ?");
$get_rows->bind_param('i', $offset);
//etc.
The query returned everything correctly at the first time, but in the next query (made through AJAX), I received the next 30 rows with a gap of one row between the current result and the next one. And this goes on and on.
In the table, the row #1 had been deleted. So, I restored it, and now the query works. However, I will definitely have to delete more rows in the future. (I don't have the option of soft-deleting).
Is there any way I can keep deleting rows, and have these queries return correct results (without skipping any row)?
EDIT
Here's an example of the range of the ids in the first 2 queries:
Query 1:
247--276
Query 2:
278--307
(277 is missing)
NB I asked ChatGPT, but it couldn't help. :')
LIMIT and OFFSET query rows by position, not by value. So if you deleted a row in the first "page," then the position of all subsequent rows moves down by one.
One solution to ensure you don't miss a row is to define pages by the greatest id value on the preceding page, instead of by the offset.
$get_rows = $conn->prepare("
SELECT * FROM my_table where id> ?
ORDER BY id ASC LIMIT 30");
$get_rows->bind_param('i', $lastId);
This only works if your previous query viewed the preceding page, so you can save the value of the last id in that page.

How to target specific rows returned by mysqli query

Let's say I have a table with following columns: id-1, id-2, col-1, col-2, col-3
Here, id-1 is the primary key and is auto-incremented. id-2 is a different id and is not necessary to be unique. There are multiple instances of same id in that column. col-1, col-2, col-3 are just necessary columns.
I pass a query to select data from the table.
mysqli_query($connect, SELECT * FROM table WHERE id-2='some_specific_id')
It will return multiple rows. I would like to know how can I target specific rows, say row number 3.
First, use ":
mysqli_query($connect, "SELECT * FROM table WHERE id-2 = 'some_specific_id'");
Target specific row? Do you mean to limit the fetched rows? Or get the 3rd row?
For limiting the fetched rows, you can use LIMIT:
SELECT * FROM table WHERE id-2='some_specific_id' LIMIT 3
For getting the third row:
SELECT * FROM table WHERE id-2='some_specific_id' LIMIT 2, 1
Well although it seems you just rather needed to learn basic SQL to get your answer, there is still the question in the title, that may attract other people whose problem is formulated exactly like that. So goes the answer:
Mysqli is not very convenient for this task, so we would use PDO.
In case your query is intended to return multiple rows and you need to address one of them by number (which is rather makes little sense, but anyway), use fetchAll() method:
$stmt = $connect->prepare("SELECT * FROM table WHERE id2=?");
$stmt->execute(['some specific id']);
$data = $stmt->fetchAll();
and you will be able to address returned rows by number, starting from zero:
echo $data[0]['col1'];
However, it makes more sense to address the returned rows by some unique id. In this case just add this unique field fiset in the field list and then use the special PDO street magic:
$stmt = $connect->prepare("SELECT id1, table.* FROM table WHERE id2=?);
$stmt->execute(['some specific id']);
$data = $stmt->fetchAll(PDO::FETCH_UNIQUE);
and you will be able to address returned rows by that unique field :
echo $data[$id1]['col1'];
Use LIMIT to get what you want like:
SELECT * FROM table WHERE id-2='some_specific_id' LIMIT 2, 1;
Or, if you want to fetch from array, then use the 3rd index of array.
LIMIT Explanation:
The following illustrates the LIMIT clause syntax with two arguments:
SELECT
column1,column2,...
FROM
table
LIMIT offset , count;
Let's examine the LIMIT clause parameters:
The offset specifies the offset of the first row to return. The offset of the first row is 0, not 1.
The count specifies the maximum number of rows to return.

MYSQL: GROUP BY on all values except 0 and null?

I have a simple SQL Query:
SELECT tid,
COUNT(*) AS bpn
FROM mark_list
WHERE userid = $userid
GROUP BY tid
Now the column tid is basically a category list associated with each entry. The categories are unique numeric values.
What I am trying to do is get an overall count of how many records there as per userid, but I only want to count an entire category one time (meaning if category 3 has 10000 records, it should only receive a count of 1).
The caveat is that sometimes the category is listed as null or sometimes a 0. If the item has either a 0 or a null, it has no category and I want them counted as their own separate entities and not lumped into a single large category.
Wheeee!
SELECT SUM(`tid` IS NULL) AS `total_null`,
SUM(`tid` = 0) AS `total_zero`,
COUNT(DISTINCT `tid`) AS `other`
FROM `mark_list`
WHERE `user_id` = $userid
Edit: note that if total_zero is greater than 0, you will have to subtract one from the "other" result (because tid=0 will get counted in that column)
You can alter the query to not take into account those particular values (via the WHERE clause), and then perhaps run a separate query that ONLY takes into account those values.
There may be a way to combine it into only one query, but this way should work, too.

How get incremented value from table

I need to get next id from table (auto_increment).
I could just use SELECT * from table ORDER BY id DESC LIMIT 1;
For example I get 50. But if we delete from table two items I will get 48 but correct one
will be 51. How get correct value even we something delete from table ?
You can only use SHOW TABLE STATUS LIKE 'tablename' to fetch the auto_increment value. A simpler solution might be: SELECT MAX(id) + 1 FROM table, but this is buggy if the last entry was deleted.
show table status like 'table_name'
next id value is in 'Auto_increment' field
SHOW TABLE STATUS LIKE 'table'
The value you want is in the Auto_increment field.
Be careful about concurrency though: by the time you get around to using this value, some other client could have inserted into the table and thus your value is out of date. It's usually best to try to not need this.
SELECT LAST_INSERT_ID() + 1;
gets the last ID used in an insert in an autoincrement column + 1
I see two solutions for the next ID:
1) Select bigger value of a column with max function. Example: select max( id ) from table;
2) Using the command SHOW STATUS LIKE and get the correct index of array. Take a look: http://dev.mysql.com/doc/refman/5.1/en/show-table-status.html
Seems to me you're creating a race condition here.
Why exactly can you not insert the row you want to insert and then use LAST_INSERT_ID() to find it's ID?

Selecting a single row in MySQL

I am using MySQL, I have a table that has 9 columns. One of them is the primary key.
How can I select a single row, by the primary key or column 8 or 4?
If I understand your question correctly:
SELECT * FROM tbl WHERE id = 123 OR colname4 = 'x' OR colname8 = 'y' LIMIT 1
The 'LIMIT' keyword makes sure there is only one row returned.
select *
from MyTable
where MyPrimaryKey = 123
Columns in SQL don't have a defined 'order'. Database systems generally keep track of an order for display purposes, but it doesn't make sense to ask a database to select a column by number. You need to know the column's name in order to query its contents.
The same thing goes for the primary key (which, incidentally, may not be just a single column). You have to know which column it is, and what that column is named, in order to execute a query.
If you don't know these things, or need to figure them out dynamically, then
DESCRIBE tablename;
will tell you the names of each column, and whether it is part of the primary key or not. It will return a table that you can read, like any other result.

Categories