I am useing Yii framework to do a criteria selection for all rows that fit the criteria.
I am trying to take the ID of one table and search another tables codes that contain the prefix of the ID. (exp ID-code or 1-sdfa). Currently the code below is returning all of the rows as a result. Below are the details, any insight would help. Thank you.
[table 1]
tbl_School
---------------------------
| ID | Name |
---------------------------
| 1 | forist hills |
| 2 | Dhs |
---------------------------
[table 2]
tbl_ticket
------------------
| ID | code |
------------------
| 1 | 1-fd23s |
| 2 | 2-fdet2 |
| 3 | 1-4wscd |
| 4 | 2-oifjd |
| 5 | 1-zzds6 |
------------------
After runing the function on ID=1 I would like to see
------------------
| ID | code |
------------------
| 1 | 1-fd23s |
| 3 | 1-4wscd |
| 5 | 1-zzds6 |
------------------
Here is my code:
public static function get_tickets($ticket_ID){
$match = '';
$match = addcslashes($match, "$ticket_ID".'_%');
$q = new CDbCriteria( array(
'condition' => "code LIKE :match",
'params' => array(':match' => "$match%")
) );
$rows = Ticket::model()->findAll( $q );
return $rows;
}
PDO does escaping for you so you don't need to do the addcslashes yourself (I didn't even know that existed, always used addslashes :) )
Secondly, you end up selecting on [NUMBER]_%%, those are 3 wildcards.
As Ryan already changed in its comment, you might want to select on -% instead:
public static function get_tickets($ticket_ID){
$ticket_ID = intval($ticket_ID);
if (!$ticket_ID)
return null;
$q = new CDbCriteria( array(
'condition' => "code LIKE :match",
'params' => array(':match' => $ticket_ID . "-%")
) );
$rows = Ticket::model()->findAll( $q );
return $rows;
}
As you can see, I did do a numeric sanity check for the ticket number, just like being cautious.
Lastly: I hope you don't mind the suggestion, but isn't it simply possible adding the ticket number as a separate column? You are going to end up with perfectly avoidable performance problems if there are a lot of rows in this table. With a separate column that is an index you'd use a lot less cpu for the same result.
Related
I have a table in my Laravel application which I wish to query.
id | company_name | contact |
-----------------------------
1 | Tesco | Name 1 |
2 | Tesco | Name 2 |
3 | Asda | Name 3 |
4 | Tesco | Name 4 |
5 | Asda | Name 5 |
I'm trying to get an array of all unique company names with all ID numbers.
'Tesco' => [1,2,4]
'Asda' => [3,5]
I have tried
$companies = Contact::select('company_name','id')->groupBy('company_name')->get();
However this requests the 'id' to be included in the group by which defeats the purpose. I understand it's asking for this because it's not a SUM or COUNT etc.
The above table may seem unusual and I know I should have a relation to a companies table however this is necessary at this stage.
You could use GROUP_CONCAT()
$companies = Contact::select('company_name', DB::raw('GROUP_CONCAT(id) as ids'))
->groupBy('company_name')
->get();
This would return something like:
company_name | ids
Tesco | 1,2
Edit: if you want the ids in the form an array, you could just map over the collection to convert it:
$companies->map(function($column) {
$column->ids = explode(',', $column->ids);
});
That should do the trick.
I have four columns in a properties table: property_id, value, id, material_id.
I also have an array of properties: Array $properties
The schema is a bit complicated, because I want to find the material_id based on the matching properties.
An example:
$properties = array(['property_id'=>1,'value'=>3],['property_id'=>2,'value'=>6],['property_id'=>3,'value'=>4]);
Example table output:
+----+-------------+-------------+-------+
| id | material_id | property_id | value |
+----+-------------+-------------+-------+
| 1 | 1 | 3 | 5 |
| 2 | 1 | 3 | 5 |
| 3 | 1 | 3 | 5 |
| 4 | 2 | 1 | 3 |
| 5 | 2 | 2 | 6 |
| 6 | 2 | 3 | 4 |
| 10 | 4 | 1 | 9 |
| 11 | 4 | 2 | 3 |
| 12 | 4 | 3 | 6 |
+----+-------------+-------------+-------+
Now, I need material_id that satisfies all the properties. How can I do that..? Do I need to use exist statement of MySQL?
Now, for each element in your array you will want to run a statement that looks like this:
SELECT material_id FROM properties WHERE property_id = 2 AND value = 3;
Do you need help on the php code also? You could run a for each loop, but I will need to know what way you are using to communicate with your database for more specifics.
edit
foreach ($properties as $foo => $bar)
{
$sql = 'SELECT material_id FROM properties WHERE ';
foreach ($bar as $key => $value)
{
$sql .= $key .' = '. $value .' AND ';
}
$sql .= 'true';
*run your PDO code on $sql here*
}
On behalf of performance, it's not a good idea to run a query per array's value. If you have an oversized array things can get pretty slower.
So, best solution can be to build a single query including all conditions presented on $properties array:
<?php
$properties = array(['property_id'=>1,'value'=>3],['property_id'=>2,'value'=>6],['property_id'=>3,'value'=>4]);
$qCondition = [];
foreach($properties as $prop) {
$q = sprintf("(property_id = %d AND value = %d)", $prop["property_id"], $prop["value"]);
$qCondition[] = $q;
}
// assuming that your database table name is 'materials'
$sql = sprintf("SELECT * FROM materials WHERE (" . implode(" OR ", $qCondition) . ")");
echo $sql;
Result:
SELECT * FROM materials
WHERE ((property_id = 1 AND value = 3) OR (property_id = 2 AND value = 6) OR (property_id = 3 AND value = 4))
Therefore, you need to run only one single query to get all desired rows.
You can play with suggested solution here: http://ideone.com/kaE4sw
I have a function that runs and gets the labels from a lookup table for values stored in a particular table. When there is 1 value it displays correctly. However when there is multiple values it only returns the first one. For example:
Lookup table is
| Tel_No| Tel_type |
--------------------
| 1 | Info |
| 2 | Support |
| 3 | Call |
Main table is
| TelephoneCalls |
------------------
| 1,3 |
| 3 |
| 1,2,3 |
The function I have at the moment which works for matching 1 value is
function getMonitoring($monitoring){
$query = "SELECT Tel_type FROM TelephoneCalls Where Tel_no = '$monitoring'";
$result9 =mysql_query($query) or die(mysql_error());
list($Tel_type) = mysql_fetch_array($result9, MYSQL_NUM);
return $Tel_type;
}
How can I get it to list the values like below
If 1, 3 then display Info, Call
If 3 display Call
If 1, 2, 3 display Info, Support, Call
Thanks for any help!
I guess the comments touched upon it, but you really should change your schema to be more of a many-to-many relationship than using CSV values in the fields. If you can't this query should work:
SELECT telephonecalls, GROUP_CONCAT(tel_type)
FROM lookup_table
LEFT JOIN main_table ON FIND_IN_SET(tel_no , replace(TelephoneCalls,' ', '')) > 0
GROUP BY telephonecalls;
#outputs
+----------------+------------------------+
| telephonecalls | GROUP_CONCAT(tel_type) |
+----------------+------------------------+
| 1,2,3 | Info,Support,Call |
| 1,3 | Info,Call |
| 3 | Call |
+----------------+------------------------+
http://sqlfiddle.com/#!2/194fd/1/0
I have the following table structure:
+------------------------+
| id | name | category |
+------------------------+
| 1 | name_1 | cat_1 |
| 2 | name_2 | cat_2 |
| 3 | name_3 | cat_1 |
| . | . | . |
| . | . | . |
| n | name_n | cat_k |
+------------------------+
were "n" is the total rows of table and "k" is an arbitrary number. My question is, is there any way to make an SQL query that retrieve rows grouped by category? I mean it is possible to get something like this structure?
array(
"cat_1" => array(
"name_1", "1",
"name_3", "3",
),
"cat_2" => array(
"name_2", "2",
some rows ....
),
...
"cat_k" => array(
some rows....
),
)
If there is any way please give me some keywords, not entire solution please.
You can't really do this in a single query since mysql alone will not be able to yield multi-dimensional arrays, but it's almost trivial to do using PHP. Basically here is what you would do:
$cats = array();
while ($row = $result->fetch()) {
if (!isset($cats[$row->category])) {
$cats[$row->category] = array();
}
$cats[$row->category][] = $row->name;
}
The query itself will not give you that structure, but it is quite easy to read the result set into that sort of two dimensional array:
$query = "SELECT category, id, name FROM table ORDER BY category ASC, id ASC";
$result = /* use you DB query mechanism of choice here */;
$array = array();
while($row = /* use your DB row fetch mechanism of choice here */) {
$array[$row['category']][] = array($row['id'] => $row['name']);
}
I have two tables. One for orders, and for their prefs. The tables look like this:
Order:
+----------+---------------+------------+
| orderID | orderNumber | clientID |
+----------+---------------+------------+
| 1 | abc123 | 2 |
| 2 | orderX | 7 |
| 3 | Joe9 | 2 |
| 4 | Order4 | 2 |
+----------+---------------+------------+
OrderPref
+----------+----------+-------------+
| orderID | prefID | prefValue |
+----------+----------+-------------+
| 1 | 1 | $100 |
| 1 | 2 | 123 |
| 1 | 3 | $35 |
| 2 | 1 | $600 |
| 2 | 2 | 876 |
| 2 | 3 | $44 |
+----------+----------+-------------+
What I want to is for each order, get the prefValue for a specific prefID. Currently, this is what I am doing:
$orders = OrdersQuery::create()->filterByClientID(2)->find();
foreach($orders as $o){
$prefs = $o->getOrderPrefs();
foreach($prefs as $p){
if($p->getPrefID() === 2){
echo $p->getPrefValue();
break;
}
}
}
This works, but there needs to be a better way to get the one row I want for each order without looping through all the prefs.
I know this doesn't work, but is there something like this?
$orders = OrdersQuery::create()->filterByClientID(2)->find();
foreach($orders as $o){
// This obviously doesn't work, so is there a short way to do this?
echo $o->getOrderPrefs()->filterByPrefID(2)->getPrefValue();
}
I was reading the docs and found a ->search() method, but I don't know how to use it.
$orders = OrdersQuery::create()->filterByClientID(2)->find();
foreach($orders as $o){
// How can I search for the row with the prefID I want?
echo $o->getOrderPrefs()->search()->getPrefValue();
}
Looking at some old Propel stuff I've written, I'm guessing something like:
$prefValue = OrdersQuery::create()->
joinOrderPref()->
where('OrderPref.prefID = ?', $prefId)->
filterByClientID($clientId)->
select('OrderPref.prefValue')->
find()
;
The issue is that you need to get a specific column (reference).
For these chainable queries, my view is that an auto-completing editor is pretty much mandatory - remembering the syntax is nigh-on impossible without it.
$prefValues = OrdersQuery::create()
->filterByClientId(2)
->joinOrderPref()
->withColumn('OrderPref.PrefValue', 'theValue')
// row above fetches ONLY the needed column from joined table and
// gives 'theValue' alias to it
->select('theValue')
->find();
With this you don't need to do any foreaches in PHP or do it in two steps.
About the ->select() part - it's there only to not get the fully bloated/hydrated object, but actually only an array (PropelArrayCollection to be precise) with the prefValue data you need.
I didn't test this live though, some syntax issues may arise.