PDO retrieve all fields with value 1 and echo with alternate name - pdo

i have a table (facility) in which field names are swimming_pool, restaurant, WiFi, library etc.
if a particular house having only two of those facilities available, i give those available field names value 1 and if not 0.
I want to retrieve all the field names with value 1 and echo each field with value 1 with an alternate name.
here is what i want to achieve
$st = $db->prepare(select * from facility where house_id = ?);
$st->execute(array($_GET['house_id']));
$row = $st->fetch();
from above i have to select all fields with value 1. And for all those fields with value one i have to echo name (for example: if swimming_pool value is 1 i have to echo Swimming Pool, if it is 0 then check for the next column)
i hope you understood my goal.

I hope I solved your question? I didn't test it yet, so if there might be a problem, do a comment.
<?php
/*
* Sample Link: web.com/index.php?house_id=1&search=1,0,0,1
*/
/*
* Sample Fields:
* swimming_pool, restaurant, wifi, library
*/
//Explode the $_GET['search'] to create an array
$fields_to_search = explode(",",$_GET['search']);
//Manually set the fields
$db_fields = [
'swimming_pool',
'restaurant',
'wifi',
'library'
];
$fields_to_be_selected = "";
//Create a counter as basis to store if the Link is 1 or 0, then pass it to $db_fields[]
$counter = 0;
foreach($fields_to_search as $field) {
//Check if $field is 1
if($field == 1) {
//Then pass it to $table_to_be_selected and add a COMMA
$fields_to_be_selected .= $db_fields[$counter].",";
}
$counter++;
}
//Remove the last COMMA
$fields_to_be_selected = substr($fields_to_be_selected,0,-1);
/*
* LASTLY DO THE prepare()
*/
$query = sprintf("SELECT %s FROM `facility` WHERE `house_id` = ?",$fields_to_be_selected);
$stmt = $db->prepare($query);
$stmt->execute(array($_GET['house_id']));
$rows = $stmt->fetchAll();
//It will only print the selected fields
print_r($rows);
?>

Related

CDbMigration::update does not work inside foreach loop

Following this question. There is something wrong, when using CDbMigration::update() inside foreach loop.
This code does not work correctly:
//This is executed inside Yii migration, so $this is CDbMigration.
foreach($idMap as $menuId=>$pageId)
{
$this->update
(
'menus_items',
array('link'=>'/content/show?id='.$pageId),
array('id = '.$menuId)
);
}
For each item in $idMap value of $pageId is always the same and equals value of last item in $idMap array. Therefore, every menu item points to the same URL.
This code works like a charm:
foreach($idMap as $menuId=>$pageId)
{
$sql = "UPDATE `menus_items` SET link = '/content/show?id=".$pageId."' WHERE id = ".$menuId."; ";
Yii::app()->db->createCommand($sql)->execute();
}
For each item in $idMap value of $pageId is always different and equals value of current item in $idMap array. Therefore, every menu item points to correct URL.
The same goes, when executing all statements in one SQL query:
$sql = '';
foreach($idMap as $menuId=>$pageId)
{
$sql .= "UPDATE `menus_items` SET link = '/content/show?id=".$pageId."' WHERE id = ".$menuId."; ";
}
Yii::app()->db->createCommand($sql)->execute();
Again, everything is OK.
Why using CDbMigration::update() fails, while direct SQL execution works like a charm?
I don't think you are providing the criteria parameter properly # array('id = '.$menuId)
. You should use a string if you want to send it like that, putting it in an array presumes you are mapping out the conditions in a key => value pair. Also you should be wrapping the value constraint in quotes id = "$menuId".

Two separate database queries to relate separate tables with Drupal 7 module?

I am developing a custom module for a site I'm working on and have created the following code. This is my first module, so any ideas of what I could be doing better would be appreciate.
As it is, this module works perfectly for me. But, I want to optimize it and be sure that I fix shoddy code.
Thanks!
The function in question is as follows:
// Declared variables for future incrementation
$total=0;
$countOne=0;
$countTwo=0;
$countThree=0;
$countOld=0;
// Call the native global user object from Drupal
global $user;
$userID = $user->uid;
// Check for nodes of given type owned by current user
$sql = db_query("SELECT nid FROM {node} WHERE type = 'content_type' AND uid = " . $userID);
// Iteratively checks each node id against a custom Drupal field on a separate table
foreach ($sql as $record) {
// SQL query for all custom fields attached to the node id given above
$query = db_query("SELECT * FROM {field_birth} WHERE entity_id = " . $record->nid);
$result = $query->fetchObject();
// The unmodified birth format (Y-m-d 00:00:00)
$originalBirth = $result->field_date_of_birth_value;
// The sanitized birth format for comparison (Y-m-d)
$birth = date('Y-m-d', strtotime($originalBirth));
// The current date/time (Y-m-d)
$now = date('Y-m-d');
//Future dates (Y-m-d)
$one_year = date('Y-m-d', strtotime('+1 year', strtotime($birth)));
$two_years = date('Y-m-d', strtotime('+2 years', strtotime($birth)));
$three_years = date('Y-m-d', strtotime('+3 years', strtotime($birth)));
// A count of all records returned before logical statements
$total++;
// Logic to determine the age of the records
if($now < $one_year) {
$countOne++;
}
else if($now >= $one_year && $now < $two_years) {
$countTwo++;
}
else if($now >= $two_years && $now < $three_years) {
$countThree++;
}
else {
$countOld++;
}
My question is, can I avoid having two separate database queries to hit both tables? I am not really sure how to go about that. Also, am I doing things in a manner which will be resource intensive and highly inefficient? As I am not a programmer by trade, I am not certain when code is 'good'. I do want to try my best to make this good code though since it is a module for a website I hope will last a long time.
Thank you stackoverflow community!
EDIT: The code I got working thanks to Mike is as follows. If anyone has a similar question / problem hopefully this will help!
// Join field_birth_table to nodes of given type owned by current user
$sql = db_select('node', 'n');
$sql->join('field_birth_table', 'b', 'n.nid = b.entity_id');
$sql
->fields('b', array('field_birth_field_value', 'entity_id'))
->condition('n.type', 'content_type')
->condition('n.status', '1')
->condition('n.uid', $user->uid)
->addTag('node_access');
$results = $sql->execute();
You can use a left join between the node and field_birth table:
$query = db_select('node', 'n');
$query->leftJoin('field_birth', 'b', '(b.entity_id = n.nid AND b.entity_type = :node)', array(':node' => 'node'));
$query
->fields('b', array())
->condition('n.type', 'content_type')
->condition('n.uid', $user->uid)
$results = $query->execute();

Nested while loop needed?

I've got this code working but it's only pulling out the first neighbourhood group that matches one of the values from the 1st query. The code is in a Node ID PHP handler in a view in Drupal.
The first query puts all of the postal codes from the government's jurisdiction into an array. The second query reads through all of the neighbourhood groups to find all those that match those in that array.
It looks like I need a second loop or something since the while that's there now isn't getting every neighbourhood groups that match any of the values in the array. Can anyone see what I'm missing?
Here's the code:
$government_nid = custom_get_groupid();
$codes_list = array();
$neighbourhood_list = array();
$results = db_query("SELECT field_jurisdiction_postal_codes_value FROM {content_field_jurisdiction_postal_codes} WHERE
nid = %d", $government_nid);
while($return_list = db_fetch_array($results)){
$codes_list[] = $return_list[field_jurisdiction_postal_codes_value];
}
$results1 = db_query("SELECT nid FROM {content_type_neighbourhood_group} WHERE
field_postal_code_3_value IN ('%s')", $codes_list);
while($return_list1 = db_fetch_array($results1)){
$neighbourhood_list[] = $return_list1[nid];
}
$neighbourhood_string = implode(', ', $neighbourhood_list);
return $neighbourhood_string;
Here's the answer:
foreach ($codes_list AS $value) {
$results1 = db_query("SELECT nid FROM {content_type_neighbourhood_group} WHERE
field_postal_code_3_value = '%s'", $value);
while($return_list1 = db_fetch_array($results1)){
$neighbourhood_list[] = $return_list1[nid];
}
}
$neighbourhood_string = implode(', ', $neighbourhood_list);
return $neighbourhood_string;

SELECT issue moving from PG_query to PDO

I have a select statement see below. Using PDO how would I recreate this same Select statement, as I want to grab two values from it and combine them into the $geomstring. I can figure out the combine, but not the first 3 lines.
$sql1 = "SELECT easting_value, northing_value FROM gridreference_tbl WHERE gridref_id='$_POST[gridref_id]'";
$result1 = pg_query($sql1);
$row1 = pg_fetch_array($result1);
$geomstring = $row1['easting_value']. $_POST['grid_eastings']." ".$row1['northing_value'].$_POST['grid_northings'];
*php website for prepared statements says *
$stmt = $dbh->prepare("SELECT * FROM REGISTRY where name = ?");
if ($stmt->execute(array($_GET['name']))) {
while ($row = $stmt->fetch()) {
print_r($row);
}
}
I have something similar working for populating a dropdown that partly uses this
$stmt = $conn->prepare("SELECT easting_value, northing_value FROM gridreference_tbl WHERE gridref_id=$gridref_id");
$stmt->setFetchMode(PDO::FETCH_OBJ);
Found it on php.net, I was googling the wrong stuff:
$stmt4 = $conn->prepare("SELECT easting_value, northing_value from gridreference_tbl WHERE gridref_id = 4");
$stmt4->execute();
print("PDO::FETCH_ASSOC: ");
print("Return next row as an array indexed by column name\n");
$result = $stmt4->fetch(PDO::FETCH_ASSOC);
print_r($result);
print("\n");

SQL optimisation

I want to optimize some of the SQL and just need an opinion on whether I should do it or leave it as is and why I should do it. SQL queries are executed via PHP & Java, I will show an example in PHP which will give an idea of what Im doing.
Main concerns are:
-Maintainability.
-Ease of altering tables without messing with all the legacy code
-Speed of SQL (is it a concern???)
-Readability
Example of what I have right now:
I take a LONG array from a customer (cant make it smaller unfortunately) and update the existing values with the new values provided by a customer in the following way:
$i = 0;
foreach($values as $value)
{
$sql = "UPDATE $someTable SET someItem$i = '$value' WHERE username='$username'";
mysql_query($sql, $con);
$i+=1;
}
Its easy to see from the above example that if the array of values is long, than I execute a lot of SQL statements.
Should I instead do something like:
$i = 0;
$j = count($values);
$sql = "UPDATE $someTable SET ";
foreach($values as $value)
{
if($i < $j) //append values to the sql string up to the last item
{
$sql .= "someItem$i = '$value', ";
}
$i+=1;
}
$sql .= "someItem$i = '$value' WHERE username='$username'"; //add the last item and finish the statement
mysql_query($sql, $con); //execute query once
OR which way should it be done / should I bother making these changes? (there a lot of the type and they all have 100+ items)
Thanks in advance.
The only way you'll get a definitive answer is to run both of these methods and profile it to see how long they take. With that said, I'm confident that running one UPDATE statement with a hundred name value pairs will be faster than running 100 UPDATE statements.
Don't run 100 seperate UPDATE statements!
Use a MySQL wrapper class which, when given an array of name => value pairs will return an SQL UPDATE statement. Its really simple. I'm just looking for the one we use now...
We use something like this (registration required) but adapted a little more to suit our needs. Really basic but very very handy.
For instance, the Update method is just this
/**
* Generate SQL Update Query
* #param string $table Target table name
* #param array $data SQL Data (ColumnName => ColumnValue)
* #param string $cond SQL Condition
* #return string
**/
function update($table,$data,$cond='')
{
$sql = "UPDATE $table SET ";
if (is_string($data)) {
$sql .= $data;
} else {
foreach ($data as $k => $v) {
$sql .= "`" . $k . "`" . " = " . SQL::quote($v) . ",";
}
$sql = SQL::trim($sql , ',');
}
if ($cond != '') $sql .= " WHERE $cond";
$sql .= ";";
return $sql;
}
If you can't change the code, make sure it is enclosed in transaction (if the storage engine is InnoDB) so no non-unique indexes will be updated before commiting transaction (this will speed up the write) and the new row won't be flushed to disk.
If this is MyISAM table, use UPDATE LOW_PRIORTY or lock table before the loop and unlock after read.
Of course, I'm sure you have index on the username column, but just to mention it - you need such index.