Finding array items PHP - php

I have gone code blind and don't know how to get the results I need to output values in a desired format.
I have a search function on an internal website which queries MSSQL based on multiple strings. For instance if a user enters "CCENT MCSE" the query will return all users with that have either certification accredited to them.
To be clear this will return all users who have CCENT cerfificate OR MCSE
My boss now want to change this to AND by using an operator (+) sign so when a user enters "CCENT+MCSE" the query should return users who have the CCENT AND MCSE certification.
The way I have built the query is to explode the search string into an array referencing the + sign as the delimiter.
My SQL statement pulls back the following result
Array
(
[0] => Array
(
[username] => mshort
[fname] => Matthew
[lname] => Short
[location_name] => CENTRAL REMOTE
[grade_name] => E6
[skill_name] => CCENT
)
[1] => Array
(
[username] => mark.parry
[fname] => Mark
[lname] => Parry
[location_name] => CENTRAL OFFICE
[grade_name] => E4
[skill_name] => MCSE Messaging
)
[2] => Array
(
[username] => mark.parry
[fname] => Mark
[lname] => Parry
[location_name] => CENTRAL OFFICE
[grade_name] => E4
[skill_name] => CCENT
)
)
What needs to happen in this case is I need to display only unique users who have both CCENT AND MCSE and discard the users who only have one of them.
In the above example I need to output only Mark Parry and discard Matthew Short
I am not sure how to do it. Please can you help?
Thanks
The SQL Statement
SELECT username,fname,lname,el.location_name, eg.grade_name,el.location_name
,sl.skill_nameFROM engineer e
INNER JOIN engineer_skills es ON e.id=es.engineer_id INNER JOIN skills_list sl ON es.skill_id=sl.id
INNER JOIN engineer_grades eg ON e.grade=eg.id
INNER JOIN engineer_location el ON e.location=el.id INNER JOIN team t ON e.team=t.id
WHERE e.id > 0 AND '.$sql_where.' ORDER BY lname'
$sql_where is this
sl.skill_name LIKE '%".$search[$i]."%' OR
and I strip the last OR

You could filter the array (assuming it is names $data)
First, emulate group by username
$result = array();
foreach($data as $item) {
if(!isset($result[$item["username"]])) $result[$item["username"]] = $item;
else $result[$item["username"]]["skill_name"].="+".$item["skill_name"];
}
Second, filter the result
$filter = array("CCENT","MCSE");
function skill_and_filter($item) {
global $filter;
foreach($filter as $f) if(strpos($item["skill_name"],$f)===false) return false;
return true;
}
$result = array_filter($result,"skill_and_filter");

Related

Pushing pointers to followers with the metadata (MySQL Query)

I’ve seen the following question on StackOverflow, Intelligent MySQL GROUP BY for Activity Streams posted by Christian Owens 12/12/12.
So I decided to try out the same approach, make two tables similar to those of his. And then I pretty much copied his query which I do understand.
This is what I get out from my sandbox:
Array
(
[0] => Array
(
[id] => 0
[user_id] => 1
[action] => published_post
[object_id] => 776286559146635
[object_type] => post
[stream_date] => 2015-11-24 12:28:09
[rows_in_group] => 1
[in_collection] => 0
)
)
I am curious, since looking at the results in Owens question, I am not able to fully get something, and does he perform additional queries to grab the actual metadata? And if yes, does this mean that one can do it from that single query or does one need to run different optimized sub-queries and then loop through the arrays of data to render the stream itself.
Thanks a lot in advanced.
Array
(
[0] => Array
(
[id] => 0
[user_id] => 1
[fullname] => David Anderson
[action] => hearted
[object_id] => array (
[id] => 3438983
[title] => Grand Theft Auto
[Category] => Games
)
[object_type] => product
[stream_date] => 2015-11-24 12:28:09
[rows_in_group] => 1
[in_collection] => 1
)
)
In "pseudo" code you need something like this
$result = $pdo->query('
SELECT stream.*,
object.*,
COUNT(stream.id) AS rows_in_group,
GROUP_CONCAT(stream.id) AS in_collection
FROM stream
INNER JOIN follows ON stream.user_id = follows.following_user
LEFT JOIN object ON stream.object_id = object.id
WHERE follows.user_id = '0'
GROUP BY stream.user_id,
stream.verb,
stream.object_id,
stream.type,
date(stream.stream_date)
ORDER BY stream.stream_date DESC
');
then parse the result and convert it in php
$data = array(); // this will store the end result
while($row = $result->fetch(PDO::FETCH_ASSOC)) {
// here for each row you get the keys and put it in a sub-array
// first copy the selected `object` data into a sub array
$row['object_data']['id'] = $row['object.id'];
$row['object_data']['title'] = $row['object.title'];
// remove the flat selected keys
unset($row['object.id']);
unset($row['object.title']);
...
$data[] = $row; // move to the desired array
}
you should get
Array
(
[0] => Array
(
[id] => 0
[user_id] => 1
[fullname] => David Anderson
[verb] => hearted
[object_data] => array (
[id] => 3438983
[title] => Grand Theft Auto
[Category] => Games
)
[type] => product
[stream_date] => 2015-11-24 12:28:09
[rows_in_group] => 1
[in_collection] => 1
)
)
It seems that you want a query where you can return the data you're actually able to get plus the user fullname and the data related to the object_id.
I think that the best effort would be to include some subqueries in your query to extract these data:
Fullname: something like (SELECT fullname FROM users WHERE id = stream.user_id) AS fullname... or some modified version using the stream.user_id, as we can't identify in your schema where this fullname comes from;
Object Data: something like (SELECT CONCAT_WS(';', id, title, category_name) FROM objects WHERE id = stream.object_id) AS object_data. Just as the fullname, we can't identify in your schema where these object data comes from, but I'm assuming it's an objects table.
One object may have just one title and may have just one category. In this case, the Object Data subquery works great. I don't think an object can have more than one title, but it's possible to have more than one category. In this case, you should GROUP_CONCAT the category names and take one of the two paths:
Replace the category_name in the CONCAT_WS for the GROUP_CONCAT of all categories names;
Select a new column categories (just a name suggestion) with the subquery which GROUP_CONCAT all categories names;
If your tables were like te first two points of my answer, a query like this may select the data, just needing a proper parse (split) in PHP:
SELECT
MAX(stream.id) as id,
stream.user_id,
(select fullname from users where id = stream.user_id) as fullname,
stream.verb,
stream.object_id,
(select concat_ws(';', id, title, category_name) from objects where id = stream.object_id) as object_data,
stream.type,
date(stream.stream_date) as stream_date,
COUNT(stream.id) AS rows_in_group,
GROUP_CONCAT(stream.id) AS in_collection
FROM stream
INNER JOIN follows ON 1=1
AND stream.user_id = follows.following_user
WHERE 1=1
AND follows.user_id = '0'
GROUP BY
stream.user_id,
stream.verb,
stream.object_id,
stream.type,
date(stream.stream_date)
ORDER BY stream.stream_date DESC;
In ANSI SQL you can't reference columns not listed in your GROUP BY, unless they're in aggregate functions. So, I included the id as an aggregation.

Update multiple rows in database based on multiple checkboxes and inputs

I have array below and I need to update database according to this.
It should be something like example code below but I don't know how to do it correctly:
UPDATE productPercent SET percent="$percent" WHERE
store="$store" AND
startDate>"$start_date" AND
endDate<"$end_date" AND
storeGroup="$storeGroup" AND
productGroup="$product_group" AND
productName LIKE '$search%'
I need to check for each store, store group, product (if contains word) and product group and then update productPercent table. Percent, product group, store group, product name and store are in different tables so some kind of inner join is needed.
I need some directions regarding this because I don't know how to start, thank you.
Array
(
[percent] => 3
[store] => Array
(
[0] => 36
[1] => 45
[2] => 56
)
[start_date] => 2015-02-09
[end_date] => 2015-03-31
[storeGroup] => Array
(
[0] => 2
[1] => 4
)
[product_group] => Array
(
[0] => 13
[1] => 31
[2] => 32
)
[search] => iphone
[setPercent] => Submit
)
UPDATED: data model - tableName: columns(connected tables)
store: id,name,startDate,endDate
storeGroup: id,storeGroupID(in table storeGroupName: id,name),storeID
productGroup: id,productID(in table productName: id,name),groupID(in table productGroupName: id,name)
productName: id,name
productPercent: id,productID,storeID,percent
$pdoHandle = $this->getPDOHandle();
$searchword = 'iphone';
$sql = "UPDATE
productPercent
inner join store on productPercent.storeID=store.id
inner join storeGroup on storeGroup.storeID=store.id
inner join productGroup on productGroup.id=storeGroup.groupID
inner join productName on productPercent.productID=productName.id and productGroup.productID=productName.id
SET percent=:percent
WHERE productName.name like :searchword";
$pdo->prepare($sql);
$pdo->setAttribute('percent', floatval($percent/100));
$pdo->setAttribute('searchword', $searchword . '%');

Return a value not found in the table with MySQL?

Assuming the following array:
$users = array(
// User ID => Username
'72' => 'jack192',
'23' => 'robert1984',
'253' => 'mary111',
'4' => 'jason92'
);
and the following table:
Table myTable:
username | colFoo | colBar
I would like run a query like the following, however I would like the output to additionally include a column not in the table (The user's ID from the array):
$user_string = implode("','", array_values($users));
$query = "SELECT username, colFoo, colBar FROM myTable WHERE username IN ('$user_string')";
This would normally output something like this:
Array
(
[0] => Array
(
[username] => jack192
[colFoo] => 98
[colBar] => 7
)
[1] => Array
(
[username] => robert1984
[colFoo] =>
[colBar] => 2
)
[2] => Array
(
[username] => mary111
[colFoo] => 41
[colBar] => 9
)
[3] => Array
(
[username] => jason92
[colFoo] => 46
[colBar] => 13
)
)
However, I would like the output to look like this, with user_id corresponding to the key in the original array:
Array
(
[0] => Array
(
[username] => jack192
[colFoo] => 98
[colBar] => 7
[user_id] => 72
)
[1] => Array
(
[username] => robert1984
[colFoo] =>
[colBar] => 2
[user_id] => 23
)
[2] => Array
(
[username] => mary111
[colFoo] => 41
[colBar] => 9
[user_id] => 253
)
[3] => Array
(
[username] => jason92
[colFoo] => 46
[colBar] => 13
[user_id] => 4
)
)
I suppose I basically want to just feed the user's ID into the query and get it back out as output, without MySQL doing anything further with it. Is this possible to do purely in SQL without any additional PHP code?
Note: I do not have write access to the DB I'm pulling this data from, and I did not create the schema, so I can't add a user_id field to it or anything.
Here is another way to do it, almost a mashup of the other 2 answers. You can build a 'fake' table and JOIN it to myTable.
SELECT t.username, t.colFoo, t.colBar, s.user_id
FROM myTable t
LEFT JOIN
(
SELECT 72 as user_id, 'jack192' as username
UNION SELECT 23 as user_id, 'robert1984' as username
UNION SELECT 253 as user_id, 'mary111' as username
UNION SELECT 4 as user_id, 'jason92' as username
) s
ON t.username = s.username;
SQLFiddle example - sqlfiddle.com/#!2/64650/2
The fake table structure can be created by a php foreach loop.
$select = '';
foreach ($users as $k => $v){
$select .= "UNION SELECT $k as user_id, '$v' as username\n";
}
echo ltrim($select, "UNION ");
Still a tedious, and not ideal solution, but another option.
You might try CASE
SELECT username, colFoo, colBar,
CASE `username`
WHEN 'jack192' THEN SELECT 72;
WHEN 'robert1984' THEN SELECT 23;
ELSE SELECT NULL;
...
END CASE userid
FROM myTable ...
It will get a bit cumbersome if there are a lot of values in the array.
http://dev.mysql.com/doc/refman/5.0/en/case.html
You can't do this with SQL alone because the id is not defined in the table (not withstanding the cumbersome case statement proposed by Hulka).
Less directly answer the question but providing an alternate solution:
However, you can make a 'small' modification to your php which will accomplish the desired result:
$user_string = implode("','", array_values($users));
foreach ($users as $k => $v){
$query[$k] = "SELECT \"$v\"
,username
,colFoo
,colBar
FROM myTable WHERE username IN ('$user_string')";
}
the query is is basically the same as 'SELECT "6" as user_id, field from TABLE;' for each user, this which would return
6 field
----------
6 value1
6 value2
...
depending on your interface you may be able to prepare and execute, but you did not give enough details to produce specific code.
You would have to run the query multiple times, but you could push or array_merge. Although, I personally think you should use the user_ids as the indexes for this new array. That would require a modest rewrite of above.

codeigniter join multiple rows where

I'm trying to code a search function for a site written on CodeIgniter but have trouble with the join statement in the model.
A controller passes an array of search criteria to the model function: get_sales($search_criteria);
function get_sales($search_criterie){
$this->db->join('sales_prices', 'sales_prices.sale_id = sales.sale_id', 'left');
$this->db->join('sales_sizes', 'sales_sizes.sale_id = sales.sale_id', 'left');
$query = $this->db->get_where('sales', $search_criterie);
$sale_data = $query->result_array();
}
I'm running into two problems:
1) I need a WHERE clause in the sales_sizes join. Right now it joins sales_sizes.sale_id ON sales.sale_id but I want to be able to filter by size via the $search_criteria array. How can I do this?
2) Every sales usually has multiple sizes and I want the output of the query formatted like:
Array
(
[sale_id] => 1
[sale_category] => shoes
[sale_price] => 29.99
[sale_sizes] => Array
(
[0] => 10
[1] => 10.5
[2] => 11
)
)
I've tried some foreach loops to format the output but can't get it to work. Hope somebody can help.
Update:
How do I process the following query result into a format like the one above?
Array
(
[0] => Array
(
[sale_id] => 1
[sale_category] => shoes
[sale_price] => 29.99
[sale_size] => 10
)
[1] => Array
(
[sale_id] => 1
[sale_category] => shoes
[sale_price] => 29.99
[sale_size] => 10.5
)
[2] => Array
(
[sale_id] => 1
[sale_category] => shoes
[sale_price] => 29.99
[sale_size] => 11
)
)
I am personally not a big fan of using the active record as given. I find that it often restricts the programmer from writing more complex queries. If you find that this is true as well you could rewrite your query as followed:
$this->db->query('SELECT * FROM `sales_prices`, `sales_sizes` WHERE `sales_prices`.`sale_id` = `sales`.`sale_id` AND `sales_sizes`.`sale_id` = `sales`.`sale_id` AND `sales` = ?', array($search_criterie));
$sale_data = $query->results();
This will generate the same result and will also parameterize your query. Note that the question mark corresponds in order to values in your array that will make up the second parameter of you $this->db->query() function.
Try this type of query
$this->db->select('places.*, category.*')
->from('places')
->join('category', 'places.category_id = category.category_id', 'left')
->join('places_reviews', 'places_reviews.place_id = places.id', 'left')
->where('places.category_id', $category_id)
->limit($limit, $offset)
->order_by($sort_by, $sort_order);
The below solution will work for you, it won't generate exact output, but very close to one.
$this->db->select('sales.*, GROUP_CONCAT(DISTINCT sales_prices.sale_id) as sales_price GROUP_CONCAT(DISTINCT sales_sizes.sale_id) as sales_size')
This will generate a comma separated value for you.

Get meta information for selected columns from PostgreSQL using PHP

is there a way of getting table name for each column in a postgre result in PHP?
Imagine you have a select with join, for example:
$Q = <<<E2OD
SELECT * FROM user U
LEFT JOIN department D ON U.department_id = D.id
E2OD;
In PHP/FirebirdSQL:
$R = ibase_query($Q);
$D = ibase_fetch_row($R);
$info = ibase_field_info($R, 0);
Returns
Array
(
[0] => id
[name] => id
[1] => id
[alias] => id
[2] => user
[relation] => user
[3] => 8
[length] => 8
[4] => BIGINT
[type] => BIGINT
)
While in PHP/PostgreSQL:
$select = $DB->query($Q);
$meta = $select->getColumnMeta(0);
Returns
Array
(
[pgsql:oid] => 20
[native_type] => int8
[name] => id
[len] => 8
[precision] => -1
[pdo_type] => 2
)
As you see, there's no information about the table the column is from. There's a missing key [relation] => user or similar displaying the table name.
http://php.net/manual/en/pdostatement.getcolumnmeta.php
Can PHP get this information with it's PG or PDO libraries? Does PostgreSQL provide this information to client libraries? What needs to be done to make this happen?
Thanks for any hint,
Michal
Check pg_field_table().

Categories