I have a checking script, it checks if the server/switch/router is alive.
The records are stored all in one db
CREATE TABLE IF NOT EXISTS `mod_monitoring` (
`id` int(11) NOT NULL,
`parentid` int(11) NOT NULL,
...
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
So a router could have a switch below it(connected via parent ID) and that could have a server under it, now if a server goes down, its fine because nothing would be under it and no double email would get sent out, however lets say a router goes out that has a router under it and a couple servers.
Because we check them all, we would send out emails for each item to the admin telling them each one is dead, but I need to send out only one email about the router going down. Hope that makes sense, I need to somehow only make an array of the IDs that have no children under it..
I could make an array of all the nodes that are down, but then how do I check if its the first one in the tree? and remove all the ones that are under it
Anyone could help? Been thinking about this for ages now!
If I understood what you want and that is iterate from parent to parent (which required a not specified number of JOIN), you need to use a Stored Procedure. Infact, to achieve this goal you need the Kleene closure that is not doable in a SQL query.
In the end I ended up making array of all the dead id's $key => $id
and then using the following
if(is_array($dead)) {
foreach($dead as $key => $id) {
$conn = $db->query("SELECT * FROM mod_monitoring WHERE id = {$id}");
$data = $db->fetch_array($conn);
if($data['parentid'] == 0) {
$final[] = $id;
unset($dead[$key]);
}
}
}
if(is_array($dead)) {
foreach($dead as $key => $id) {
$conn = $db->query("SELECT * FROM mod_monitoring WHERE id = {$id}");
$data = $db->fetch_array($conn);
if(in_array($data['parentid'], $final)) {
unset($dead[$key]);
}
if(in_array($id, $dead)) {
unset($dead[$key]);
}
}
}
Related
So I was trying to make a "create new user" function in PHP which should basically check in the database which is the lowest possible ID to assign to that new user. But I have now tried around with so many different methods and they all do not work as they should. Here is my current version:
function newUser($connection) {
$notNewId = sqlsrv_query ($connection, "SELECT id FROM users"); //get id from users table
while($notNewId2 = sqlsrv_fetch_array ($notNewId)) {
for ($i = 0; $i <= sizeOf($notNewId2); $i++) {
foreach ($notNewId2 as $key => $value ) {
if ($i != $value) {
break;
}
}
}
$id = $i;
return $id;
}
}
the $connection is a element of type sqlsrv_connect.
as far as I can tell my current version should be able to read the ids and put them in an array, but from there on something went wrong. As well... I may have to sort the array after id, but I have no clue how to do that.
I would really appreciate any help, even if it's no actual code and just the logic explained, thx.
EDIT: Seems like it is not clear enough, what I want. My script should assign a new ID to the new row in the users table, if that is possible automatically somehow with SQL, then please explain to me how. (Right now ID is not a primary key, I will change that as soon as I can)
Taking the highest number and adding one is not enough (like when I have 0, 1, 2, 4 and 5, the new ID should be 3, not 6). But still thanks, I didn't knew about that MAX thing.
Assuming id is your primary key and you're not trying to auto increment it in your users table, you can find the maximum value of it and add 1 in your SQL query. This mitigates the need for your nested for loops. Use ISNULL to check if that value is not null and default to 1 otherwise.
function newUser($connection) {
$query = sqlsrv_query ($connection, "SELECT ISNULL(MAX(id)+1, 1) FROM users");
return sqlsrv_fetch($query);
}
I have the following rows in the database inside url column:
http://some_url/something/34123122.json
http://some_url/something/53124322.json
http://some_url/something/22214322.json
And I want to retrieve them in some function, like this (pseudocode):
function retrieve($ids) {
return $this->fetchAll("SELECT * FROM table WHERE url IN $ids");
}
The problem is that $ids parameter MUST BE an array with ids from those urls only, like:
array(
[0] => 34123122
[1] => 22214322
)
So I have to do something in this function so that I can retrieve rows with urls that contain those ids. How can I do that? Urls can change, but the /******.json ending has always the same pattern.
I don't want to make another query selecting the beginning of the url, it will slow down the application too much.
The proper way to do this is to query only the part of the data that you are interested in - the number. So, you receive an instant +10 to intelligence from performing a quest nearby and you determine that you could create another column to save that number. Your table looks like this now:
CREATE TABLE mytable (
id int not null auto_increment,
url varchar(255) not null,
json_number int not null,
PRIMARY KEY(id),
INDEX(json_number)
) ENGINE = InnoDB;
Before inserting into the table, you use integer sanitizing filter to extract the number from the URL without wasting too much time
Given a URL like this: http://some_url/something/34123122.json you can easily extract the number like this:
$url = 'http://some_url/something/34123122.json';
$number = filter_var($url, FILTER_SANITIZE_NUMBER_INT);
echo $number; // echoes 34123122
And now your query is trivial, you check the json_number column which is also indexed at the same time.
Naturally, you can ignore all I wrote and try other answers which are ugly hacks and worst of all - they're all full table scans.
you will have to use regex in mysql, change your function:
function retrieve($ids) {
$regex = '('.implode('|', $ids).').json$';
return $this->fetchAll("SELECT * FROM table WHERE url REGEXP '$regex'");
}
Note: this is not an optimal solution for large tables. I would suggest you to create an id field in your table and if all ids are unique then you can make id a primary key. Also whenever you insert in that table take out the id part from url and insert it into the id field. In that way you can skip regex. If you are willing to create an id field, then you can execute the following query to update your current table id field:
mysql> update your_table_name set id=replace(substring_index(url, '/', -1), '.json', '');
I do not know if this is a neat solution, but it should work.
function getData($ids) {
foreach($ids as $item) {
$str[] = $item . ".json";
}
$where = "";
foreach($str as $item) {
$where .= "url LIKE '%$item' OR ";
}
return substr("SELECT * FROM table WHERE " . $where, 0, -4);
}
$ids = array(34123122, 53124322, 22214322);
echo getData($ids);
Result:
SELECT * FROM table WHERE url LIKE '%34123122.json' OR url LIKE '%53124322.json' OR url LIKE '%22214322.json'
I think this should do it. Of course you have to run the query aswell.
I have written this code which in theory i want to loop round an array and for every value use in a select statement to retrieve the applicable information. Then map a particular value id as a key and the value from the sql statement as its associated value. Though i cant seem to figure out how to add it as a value into my array im sure im a word out.
heres my code
/*
* Loop through the hasNewModelIdInYear and retrieve the exterior media paths
* with a mapped id as a key.
*/
$mediapatharray = array();
foreach ($hasNewModelIdInYear as $key => $value) {
$selectMediaPathFromValue = "SELECT `name` FROM `media` WHERE `id`='".$value['img1_media_id']."'";
$res = $mysqli->query($selectMediaPathFromValue);
$mediapatharray[$value['model_id']] = $res;
}
All that array returns is an array full of keys but no values.. With the variable $res do i then have to ->fetch_value? as im not sure on the syntax needed in order to access the data from the query?
regards mike
it is not good writing whan you have query inside loop. you should search based on array of img1_media_id
you can do follwing
$selectMediaPathFromValue = "SELECT `name` FROM `media`
WHERE `id` IN = '$hasNewModelIdInYear'";
array should be following format
$hasNewModelIdInYear = "12,21,22,65";
The result will return false on failure or the results on success. Mysqli result will be returned the first set of array that consist of the array index. You will need to fetch the values and store it in array. Try adding this code.
while($row = $res->fetch_assoc()){
$mediapatharray[$value['model_id']] = $row['name'];
}
Thanks for your responses i was trying to make it more complicated than it needed to be. I done it by putting the whole media table in a multidimension array then looping through them both and comparing values and if mathcing id map the name.
simple connection and sql query to populate the array, then map the id to a key and name as its value. heres my code.
mediaarray is an array with the media table contents populated in it
$mediaIdPAthFromOld = array();
foreach ($hasNewModelIdInYear as $hnkey => $hsvalue) {
foreach ($mediaarray as $mpavalue) {
if ($hsvalue['img1_media_id'] == $mpavalue['id']) {
$mediaIdPAthFromOld[$hsvalue['model_id']] = $mpavalue['name'];
}
}
}
though this has done what i wanted i assume there is a more effient way to do this.
regards mike
I have a bunch of photos on a page and using jQuery UI's Sortable plugin, to allow for them to be reordered.
When my sortable function fires, it writes a new order sequence:
1030:0,1031:1,1032:2,1040:3,1033:4
Each item of the comma delimited string, consists of the photo ID and the order position, separated by a colon. When the user has completely finished their reordering, I'm posting this order sequence to a PHP page via AJAX, to store the changes in the database. Here's where I get into trouble.
I have no problem getting my script to work, but I'm pretty sure it's the incorrect way to achieve what I want, and will suffer hugely in performance and resources - I'm hoping somebody could advise me as to what would be the best approach.
This is my PHP script that deals with the sequence:
if ($sorted_order) {
$exploded_order = explode(',',$sorted_order);
foreach ($exploded_order as $order_part) {
$exploded_part = explode(':',$order_part);
$part_count = 0;
foreach ($exploded_part as $part) {
$part_count++;
if ($part_count == 1) {
$photo_id = $part;
} elseif ($part_count == 2) {
$order = $part;
}
$SQL = "UPDATE article_photos ";
$SQL .= "SET order_pos = :order_pos ";
$SQL .= "WHERE photo_id = :photo_id;";
... rest of PDO stuff ...
}
}
}
My concerns arise from the nested foreach functions and also running so many database updates. If a given sequence contained 150 items, would this script cry for help? If it will, how could I improve it?
** This is for an admin page, so it won't be heavily abused **
you can use one update, with some cleaver code like so:
create the array $data['order'] in the loop then:
$q = "UPDATE article_photos SET order_pos = (CASE photo_id ";
foreach($data['order'] as $sort => $id){
$q .= " WHEN {$id} THEN {$sort}";
}
$q .= " END ) WHERE photo_id IN (".implode(",",$data['order']).")";
a little clearer perhaps
UPDATE article_photos SET order_pos = (CASE photo_id
WHEN id = 1 THEN 999
WHEN id = 2 THEN 1000
WHEN id = 3 THEN 1001
END)
WHERE photo_id IN (1,2,3)
i use this approach for exactly what your doing, updating sort orders
No need for the second foreach: you know it's going to be two parts if your data passes validation (I'm assuming you validated this. If not: you should =) so just do:
if (count($exploded_part) == 2) {
$id = $exploded_part[0];
$seq = $exploded_part[1];
/* rest of code */
} else {
/* error - data does not conform despite validation */
}
As for update hammering: do your DB updates in a transaction. Your db will queue the ops, but not commit them to the main DB until you commit the transaction, at which point it'll happily do the update "for real" at lightning speed.
I suggest making your script even simplier and changing names of the variables, so the code would be way more readable.
$parts = explode(',',$sorted_order);
foreach ($parts as $part) {
list($id, $position) = explode(':',$order_part);
//Now you can work with $id and $position ;
}
More info about list: http://php.net/manual/en/function.list.php
Also, about performance and your data structure:
The way you store your data is not perfect. But that way you will not suffer any performance issues, that way you need to send less data, less overhead overall.
However the drawback of your data structure is that most probably you will be unable to establish relationships between tables and make joins or alter table structure in a correct way.
I have spent many hours debugging, and scouring the internet for a solution to this unusual problem. Heres the deal:
I am working on a Work Order Submission and Tracking system. There are two databases involved:
The database where the submissions data gets posted, which is located on the same physical machine, but on a separate virtual machine as the webserver serving the php. They are on the same class C subnet.
The database of our tracking system. Located on a different physical server on a different IP altogether, also a virtual machine.
Our work order system allows for multiple 'services requested', stored in an array. In our sumbissions database, this is stored as a comma separated string, i.e. "40,60,70" but in our tracking system database, each 'service requested' needs a separate entry, as to allow the different aspects of the project to be tracked and completed at different times, by different staff.
THE PROBLEM IS: When I place my second insert statement, the one destined for the tracking database, in a for loop, it completely hangs, and takes maybe 5 to 15 minutes, before it passes that point in the code, and sends the confirmation email. The data does not get inserted either.
When I take it out of the for loop and simply do one insert in the submissions database and one insert into the tracking system, it works fine.
First, Ill post the code that works, but only posts one 'service' to the tracking system:
public function insertOrder()
{
$services = implode( ',', $this->model->chk );
$curdate = $this->model->getMySQLDate( $this->model->curdate );
$dueDate = $this->model->getMySQLDate( $this->model->dueDate );
$sql = "INSERT INTO orders VALUES(DEFAULT,
{$this->sanitize($services)},
{$this->sanitize($curdate)},
{$this->sanitize($this->model->submittedBy)},
{$this->sanitize($this->model->shortDesc)},
{$this->sanitize($this->model->projDetails)},
{$this->sanitize($dueDate)},
{$this->sanitize($this->model->dueDateNotes)},
{$this->sanitize( $this->model->approveBy)},
{$this->sanitize( $this->model->cost )} )";
$this->execute( $sql );
$this->convertServicesToTracks();
$notes = $this->model->getTracksNotes();
$dueDate = $dueDate.' 12:00:00';
$shortDescNoQuotes = str_replace("\"","'",$this->model->shortDesc);
$sqlTracks = "INSERT INTO todos VALUES(DEFAULT,
{$this->sanitizeTracks($this->model->chk[0])},
NULL,
{$this->sanitizeTracks($shortDescNoQuotes)},
{$this->sanitizeTracks($notes)},
now(),
{$this->sanitizeTracks($dueDate)},
NULL,
12,
NULL,
'active',
NULL,
now() );";
//echo $sqlTracks;
$this->executeTracks( $sqlTacks );
} private function executeTracks( $sql )
{
$db = $this->getTracksDB( );
$this->check4Error( $db, $sql );
return $result;
}
private function getTracksDB()
{
if (!$this->tracksdb) $this->tracksdb = new mysqli(AbstractSQL::TRACKS_HOST, AbstractSQL::USER, AbstractSQL::PASS, AbstractSQL::TRACKS_SCHEMA);
return $this->tracksdb;
}
private function convertServicesToTracks()
{
//converts submission data to tracking system data
}
private function sanitizeTracks($arg)
{
if (!isset($arg)) return "NULL";
if (is_numeric($arg) && !is_double( $arg) ) return $arg;
return "'{$this->getTracksDB()->escape_string($arg)}'";
}
When I add this simple for loop around the second INSERT statement, it hangs, even if the array only has one item!
for($i = 0; $i < count($this->model->chk); ++$i)
{
$sqlTracks = "INSERT INTO todos VALUES(DEFAULT,
{$this->sanitizeTracks($this->model->chk[$i])},
NULL,
{$this->sanitizeTracks($shortDescNoQuotes)},
{$this->sanitizeTracks($notes)},
now(),
{$this->sanitizeTracks($dueDate)},
NULL,
12,
NULL,
'active',
NULL,
now() );";
//echo $sqlTracks;
$this->executeTracks( $sqlTacks );
}
Any help would be greatly appreciated. And I apologize for the long code snippets!!
Is it iterating through the for loop? I see you have an echo, did that write anything out? How many items does it have to iterate through? 5 min seems like a long time but if there are a lot of items that could be why it's taking so long. Are you seeing any errors in your logs?
Something you might try is hold the count in a variable so it doesn't have to calculate that each time. It might speed up your for loop but I'm not sure it will insert the data.
for($i = 0, $count = count($this->model->chk); $i < $count; ++$i)
{
$sqlTracks = "INSERT INTO todos VALUES(DEFAULT,
{$this->sanitizeTracks($this->model->chk[$i])},
NULL,
{$this->sanitizeTracks($shortDescNoQuotes)},
{$this->sanitizeTracks($notes)},
now(),
{$this->sanitizeTracks($dueDate)},
NULL,
12,
NULL,
'active',
NULL,
now() );";
//echo $sqlTracks;
$this->executeTracks( $sqlTacks );
}
I found this in the PHP for loop reference: http://php.net/manual/en/control-structures.for.php
Well, this may not be the problem, but shouldn't you generally use a foreach loop to avoid hitting parts of the array that may not exist? There is more about this here. If you loop through an empty index, it would break your SQL statement. Like this:
foreach($this->model->chk as $val)