How can I echo the position number of SQL row in PHP? - php

Before you misread the title... I'm not asking how to echo the number of rows, I'm simply looking to find the position that the row is in.
Let's say we have five total rows:
+---------------------+
| Post ID | Author |
+---------------------+
| 463 | Me |
| 477 | Me |
| 718 | Me |
| 883 | Me |
| 276 | Me |
+---------------------+
Now I'd like to get the position of the row that contains the post ID of 718. From looking at the data, we can visually see that it is the third row in the data. How can I echo this in PHP?

when you fetch records, you may use a variable as position number.
#DB is a class connect to mysql database.
DB::init();
$sql = "SELECT * FROM RowNo ";
$stmt = DB::query( $sql );
$i = 1;
while( $rec1 = $stmt->fetch() ) {
echo "row $i : ";
print_r( $rec1 );
echo '<BR>'.PHP_EOL;
$i++;
};
result :
row 1 : Array ( [Post ID] => 8788277463 [Author] => Me )
row 2 : Array ( [Post ID] => 2894728477 [Author] => Me )
row 3 : Array ( [Post ID] => 3898994718 [Author] => Me )
row 4 : Array ( [Post ID] => 4891784883 [Author] => Me )
row 5 : Array ( [Post ID] => 1185819276 [Author] => Me )

You may use row_number :
#1. ORDER BY Post ID
SELECT * , row_number() over ( order by Post ID ) FROM RowNo order by Post ID asc
Post ID Author row_number() over ( order by `Post ID` )
1185819276 Me 1
2894728477 Me 2
3898994718 Me 3
4891784883 Me 4
8788277463 Me 5
#2. ORDER BY Post ID DESC
SELECT * , row_number() over ( order by Post ID desc ) FROM RowNo order by Post ID desc
Post ID Ascending 1 Author row_number() over ( order by `Post ID` desc )
8788277463 Me 1
4891784883 Me 2
3898994718 Me 3
2894728477 Me 4
1185819276 Me 5
#3. ORDER BY part of Post ID
SELECT * , substr(Post ID, 4, 2), row_number() over ( order by substr(Post ID, 4, 2) ) FROM RowNo order by substr(Post ID, 4, 2) asc
Post ID Author substr(`Post ID`, 4, 2) Ascending 1 row_number() over ( order by substr(`Post ID`, 4, 2) )
4891784883 Me 17 1
2894728477 Me 47 2
1185819276 Me 58 3
8788277463 Me 82 4
3898994718 Me 89 5

Related

Not getting any results back from a raw query in Laravel

I have a raw query and when I run this query in phpMyAdmin it returns 3 results but when I try to use Laravel Query Builder I get an empty array.
My query
SELECT id, reply_text, sending_time
FROM sms_sender_inbox_replies
WHERE phone_number
IN ('+1234567819', '+19873216154', '+15984989898')
AND id IN (
SELECT MAX( id )
FROM sms_sender_inbox_replies
GROUP BY phone_number
)
Result:
+----+-----------------+---------------------+
| id | reply_text | sending_time |
+----+-----------------+---------------------+
| 87 | This is a test | 2019-07-30 08:25:26 |
| 54 | And another one | 2019-07-29 06:35:11 |
| 12 | Last test | 2019-06-16 09:44:26 |
+----+-----------------+---------------------+
But when I try to do this query with Laravel I get back an empty array []
dump($phone_numbers);
// 0 => "+1234567819"
// 1 => "+19873216154"
// 2 => "+15984989898"
$phone_numbers = implode("','", $phone_numbers);
dump($phone_numbers);
// +1234567819','+19873216154','+15984989898
dump("SELECT id, reply_text, sending_time
FROM sms_sender_inbox_replies
WHERE phone_number IN ('$phone_numbers')
AND id IN (
SELECT MAX(id)
FROM sms_sender_inbox_replies
GROUP BY phone_number
)");
// SELECT id, reply_text, sending_time
// FROM sms_sender_inbox_replies
// WHERE phone_number
// IN ('+1234567819', '+19873216154', '+15984989898')
// AND id IN (
// SELECT MAX( id )
// FROM sms_sender_inbox_replies
// GROUP BY phone_number
// )
$replies = DB::connection('second_connection')
->select("
SELECT id, reply_text, sending_time
FROM sms_sender_inbox_replies
WHERE phone_number IN (':phone_numbers')
AND id IN (
SELECT MAX(id)
FROM sms_sender_inbox_replies
GROUP BY phone_number
)
", ['phone_numbers' => $phone_numbers]);
dump($replies);
// []
P.S. Here is the output of the Query Log
I can't understand why it is returning an empty array. But when I run the raw query in phpMyAdmin it returns results so I know that the query is correct.
Array
(
[0] => Array
(
[query] =>
SELECT id, reply_text, sending_time
FROM sms_sender_inbox_replies
WHERE phone_number IN (':phone_numbers')
AND id IN (
SELECT MAX(id)
FROM sms_sender_inbox_replies
GROUP BY phone_number
)
[bindings] => Array
(
[phone_numbers] => +1234567819','+19873216154','+15984989898
)
[time] => 0.7
)
)
When you bind it like that, you try to find the phone_number IN as a single value (not as 3 values). A placeholder can only be to a single value, not to an array - but you can work around this using the QueryBuilder methods, which simplifies bindings.
$phone_numbers = ["+1234567819", "+19873216154", "+15984989898"];
$result = DB::connection('second_connection')
->table('sms_sender_inbox_replies')
->select('id', 'reply_text', 'sending_time')
->whereIn('phone_number', $phone_numbers)
->whereIn('id', DB::table('sms_sender_inbox_replies')
->selectRaw('MAX(id)')
->groupBy('phone_number')
->get())
->get();

Create tree structure from current child id PHP SQL

i have a database table in mySQL like this and want create tree results with current value child.
id item_id secondary_id
1 1 1
2 1 1
3 1 1
4 1 3
5 1 3
6 1 3
7 1 3
8 1 3
9 1 3
10 1 3
11 1 3
12 1 1
13 1 1
14 1 1
15 1 1
16 1 7
17 1 7
18 1 7
19 1 7
20 1 7
I want get final result like this:
$current_value = 18;
-> Root with id = 1
---> Reply with id = 2
---> Reply with id = 3
-----> Reply with id = 6
-----> Reply with id = 7
-------> Reply with id = 16
-------> Reply with id = 17
-------> Reply with id = 18 <-- this target $current_value
-------> Reply with id = 19
-------> Reply with id = 20
-----> Reply with id = 8
-----> Reply with id = 9
---> Reply with id = 12
---> Reply with id = 13
I use this SQL query, but only get result current target, previous value and next value from target.
$query = "(
SELECT *
FROM (
SELECT *
FROM table_name
WHERE id < $current_target
ORDER BY id
LIMIT 2
) AS comment
ORDER BY comment.id ASC
)
UNION ALL
(
SELECT *
FROM (
SELECT *
FROM table_name
WHERE id = $current_target
ORDER BY id DESC
LIMIT 2
) AS comment
ORDER BY comment.id ASC
)
UNION ALL
(
SELECT *
FROM (
SELECT *
FROM table_name
WHERE id > $current_target
ORDER BY id
LIMIT 2
) AS comment
ORDER BY comment.id
)";
I want get result up to Root.

Laravel - update multiple records with different values

I have a table , similar to this:
| key | value |
|----------|-------|
| limit | 15 |
| viplimit | 25 |
| .. | |
And i have an array :
Array
(
[0] => Array
(
[key] => limit
[value] => 10
)
[1] => Array
(
[key] => viplimit
[value] => 99
)
...
Now , saying we have 100 rows. What would be the best way to update the table corresponding to the array ?
There would be the option of a query for each 100 row, but that is just bad performance.
This should work:
$statement = "UPDATE mytable
SET key = CASE id
WHEN 1 THEN 'key'
WHEN 2 THEN 'another_key'
WHEN 3 THEN 'some_key'
END,
value = CASE id
WHEN 1 THEN 15
WHEN 2 THEN 25
WHEN 3 THEN 45
END
WHERE id IN (1, 2, 3)
");
DB::statement($statement);
Just think how to create correct query. If it's admin panel or something that will be run not very often, I'd just use iteration to keep things simple.

Instead of php while loop and multiple connections to mysql want to connect only once

Example of mysql is here http://sqlfiddle.com/#!9/68653/2
Mysql table (named topics)
TopicId | TopicName | ClosestUpperLevelId
--------------------------------------------
1 | Books | 0
2 | BooksAboutCss | 1
3 | BooksAboutHtml | 1
4 | BooksAboutCss1 | 2
5 | BooksAboutCss2 | 2
6 | BooksAboutHtml1 | 3
7 | BooksAboutHtml2 | 3
8 | E-Books | 0
9 | Magazines | 0
For top level topics ClosestUpperLevelId is 0. For subtopics ClosestUpperLevelId is TopicId of closest upper level topic
(TopicId - ClosestUpperLevelId)
Books (1-0)
BooksAboutCss (2-1)
BooksAboutCss1 (4-2)
BooksAboutCss2 (5-2)
BooksAboutHtml (3-1)
BooksAboutHtml1 (6-3)
BooksAboutHtml2 (7-3)
E-Books (8-0)
Magazines (9-0)
For example, i have created one page and location of the page is domain.com/Books/BooksAboutCss/BooksAboutCss2
Now i decided to edit the page. For example i want to edit location (topic or category) of the page and set it to domain.com/Magazines. So i need to fetch all topics, related with existing (saved) page. Then will create select boxes for each group (level) of topics.
At the moment tried to use php while and multiple times to connect to mysql and get data. Like below code. How can i get the same result without php while? How connect to mysql only once and fetch all necessary data? Do i need to use mysql while https://dev.mysql.com/doc/refman/5.1/en/while.html?
$topic_names_1[0]['UpperLevelNumberRenamed'] = 5;//just set some value to start to fetch
while ( trim($topic_names_1[0]['ClosestUpperLevelId']) != 0 ){
try {
$stmt_1 = $db->prepare('
SELECT `TopicId`, `TopicName`, `ClosestUpperLevelId`
FROM `topics`
WHERE `ClosestUpperLevelId` =
(
SELECT `ClosestUpperLevelId`
FROM `topics`
WHERE `TopicId` = ?
)
;');
$stmt_1->execute( array( trim($topic_names_1[0]['UpperLevelNumberRenamed']) ) );
$topic_names_1 = $stmt_1->fetchAll(PDO::FETCH_ASSOC);
echo '<pre>', print_r($topic_names_1), ' topic_names_1 __</pre>';
}//try {
catch (PDOException $e){
echo "<br> stmt_1 DataBase Error: " .htmlspecialchars( $e->getMessage() , ENT_QUOTES, "UTF-8").'<br>';
}
catch (Exception $e) {
echo " stmt_1 General Error: ".htmlspecialchars( $e->getMessage() ).'<br>';
}
}//while ( trim($topic_names[0]['UpperLevelNumberRenamed']) != 0 )
As result get arrays like this
Array
(
[0] => Array
(
[TopicId] => 4
[TopicName] => BooksAboutCss1
[ClosestUpperLevelId] => 2
)
[1] => Array
(
[TopicId] => 5
[TopicName] => BooksAboutCss2
[ClosestUpperLevelId] => 2
)
)
1 topic_names_1 __
Array
(
[0] => Array
(
[TopicId] => 2
[TopicName] => BooksAboutCss
[ClosestUpperLevelId] => 1
)
[1] => Array
(
[TopicId] => 3
[TopicName] => BooksAboutHtml
[ClosestUpperLevelId] => 1
)
)
1 topic_names_1 __
Array
(
[0] => Array
(
[TopicId] => 1
[TopicName] => Books
[ClosestUpperLevelId] => 0
)
[1] => Array
(
[TopicId] => 8
[TopicName] => E-Books
[ClosestUpperLevelId] => 0
)
[2] => Array
(
[TopicId] => 9
[TopicName] => Magazines
[ClosestUpperLevelId] => 0
)
)
1 topic_names_1 __
Update
Found one example with mysql while. Trying to create own code
Created this
SET `ClosestUpperLevelId` := 2;
WHILE `ClosestUpperLevelId` > 0
DO
SELECT `TopicId`, `TopicName`, `ClosestUpperLevelId`;
END WHILE;
and this (http://sqlfiddle.com/#!9/68653/7)
CREATE PROCEDURE dowhile()
BEGIN
DECLARE `ClosestUpperLevelId` INT DEFAULT 2;
WHILE `ClosestUpperLevelId` > 0 DO
SELECT `TopicId`, `TopicName`, `ClosestUpperLevelId`;
END WHILE;
END;
Got error...
You could just move your select statement before the while loop and take out the topic_id from the where clause. Then in your loop retrieve from the complete record set using an array search function or similar. By running same query once your dB will be able to cache results
Relational databases like MySQL aren't naturally good at storing hierarchical data, but there are ways of doing it. The two ways I know of are "adjacency lists" and "nested sets".
For an adjacency list, you'd simply store a "parent_id" field for each row. Root rows (that have no parent) can just have NULL for their parent_id field. Adjacency lists are easy to manage, but not very flexible and require recursive queries to find a path from root to leaf (unless you're only going 2 levels deep, then you can simply JOIN).
Here's an example:
id | parent_id | name
0 NULL grandfather
1 0 father
2 1 grandson
3 1 granddaughter
This query would help assemble the data:
SELECT * FROM
`people` AS p1
JOIN `people` p2
ON p1.id = p2.parent_id
Any more than those two levels and you need recursion. Alternatively, you could just query the entire table and assemble it in code.
Nested sets are a little more complicated, but allow you to easily query all the way up the tree for a given leaf node. It's much easier to understand nested sets at first by seeing a visual, check this out:
https://en.wikipedia.org/wiki/Nested_set_model
And here's what your schema would look like:
left | right | name
0 7 grandfather
1 6 father
2 3 grandson
4 5 granddaughter
And here's an example to fetch father and children:
SELECT *
FROM `people`
WHERE `left` >= 1 AND `right` <= 6
Nested sets have the downside that the entire table's left and right values need to be updated when the hierarchy changes.
Google "managing hierarchical data in mysql" for more information. I hope this helps.

Sum php array (created from mysql results) depending on mysql values in another mysql column

One table called 18_7_ChartOfAccounts looks like this:
ID | AccountNumber
-------------
1 | 2310
2 | 2380
3 | 2610
Another table called 2_1_journal looks like this:
ID | Amount | DebitAccount
--------------------------
1 | 26.03 | 2310
2 | 200.00 | 2310
3 | 3.63 | 2380
4 | 119.83 | 2380
5 | 33.86 | 2610
6 | 428.25 | 2610
Aim is to get results that looks like this:
DebitAccount 2310 total is: 226.03
DebitAccount 2380 total is: 123.46
DebitAccount 2310 total is: 462.11
226.03 in this example is total of 26.03 + 200.00
At first mysql code
$query = "SELECT j.Amount, j.DebitAccount FROM 18_7_ChartOfAccounts AS c LEFT JOIN 2_1_journal AS j ON (c.AccountNumber = j.DebitAccount)";
$sql = $db->prepare($query);
$sql->execute();
$data = $sql->fetchAll(PDO::FETCH_ASSOC);
With print_r($data); get long list of arrays like
[31] => Array
(
[Amount] => 26.03
[DebitAccount] => 2310
[32] => Array
(
[Amount] => 200.00
[DebitAccount] => 2310
If in mysql query use SUM(j.Amount) then get only one total amount (suppose total amount of Column Amount).
With
foreach($data as $result){
if(strlen($result['Amount']) > 0 ) {
echo "Amount ". $result['Amount']. "Account name ". $result['DebitAccount']. "<br>";
print_r (array_sum($result));
}
}
Get something like this
Amount 123.97Account name 2310
2433.97Amount 26.03Account name 2310
2336.03Amount 200.00Account name 2310
Any ideas how to get necessary results (marked bold)?
Update
Changed $query to
$query = "SELECT SUM(j.Amount), j.DebitAccount FROM 18_7_ChartOfAccounts AS c LEFT JOIN 2_1_journal AS j ON (c.AccountNumber = j.DebitAccount) group by j.DebitAccount";
with print_r($data); get array like this
Array
(
[0] => Array
(
[SUM(j.Amount)] =>
[DebitAccount] =>
)
[1] => Array
(
[SUM(j.Amount)] => 110900.16
[DebitAccount] => 2310
)
[2] => Array
(
[SUM(j.Amount)] => 3660.86
[DebitAccount] => 2380
)
With array seems all works. Now with foreach changed to
echo "Amount ". $result['SUM(j.Amount)']. " Account name ". $result['DebitAccount']. "<br>";
Get
Amount 110900.16 Account name 2310
Amount 3660.86 Account name 2380
Amount 85247.40 Account name 2610
Seems also ok. Thanks
You are going about it wrong. You can get the sum through MySql statement itself.
Use the aggrgate function sum along with group by clause.
Like this,
SELECT DebitAccount,sum(Account) from 2_1_journal group by DebitAccount
Your full code:
$query = " SELECT DebitAccount,sum(Account) as Total from 2_1_journal group by DebitAccount";
$sql = $db->prepare($query);
$sql->execute();
$data = $sql->fetchAll(PDO::FETCH_ASSOC);
foreach($data as $result){
if(strlen($result['Total']) > 0 ) {
echo "DebitAccount ". $result['DebitAccount']. "Total is: ". $result['Total']. "<br>";
print_r (array_sum($result));
}
}
SELECT DebitAccount, SUM(Amount)
FROM 2_1_journal
GROUP BY DebitAccount
You have to use the GROUP BY in the query
SELECT DebitAccount, SUM(Amount) AS Amount FROM 2_1_journal GROUP BY DebitAccount

Categories