I'm a new in Zend.
In my model Default_Model_ApplicationMapper, I wanna use a db-table Application_Model_DbTable_Application to run a query like that
"Select * from application as a, category as c, user as u where a.user_id = u.id and a.category_id = c.id";
I tried this:
$table = new Application_Model_DbTable_Application();
$select = $table->select()->from(array('a' => 'application'))
->from(array('c' => 'category'))
->from(array('u' => 'user'))
->where('a.user_id = u.id and a.category_id = c.id');
Of course this thing does not work.
Can you help me with this?
Instead of using from(array('a' => 'table')) three times, try using from(array('a' => 'table1', 'b' => 'table2', 'c' => 'table3')).
Related
I'm trying to write one query for joining 3 tables without link, I was trying with UNION SQL command like this:
SELECT *
FROM
(SELECT
a.id AS field_aa, a.column2 AS field_ab, a.column3 AS field_ac
FROM tableA a
UNION
SELECT
b.id AS field_ba, b.column2 AS field_bb, b.column3 AS field_bc
FROM tableB b
UNION
SELECT
c.id AS field_ca, c.column2 AS field_cb, c.column3 AS field_cc
FROM tableC c) abc
WHERE 1;
And after i want to fill 3 arrays for each table
while( ($arr = $_opDB->fetch_assoc($result)) != FALSE ) {
$array_one = array(
'field_id' => $arr['field_aa'],
'field_one' => $arr['field_ab'],
'field_two' => $arr['field_ac'],
) ;
$array_two = array(
'field_id' => $arr['field_ba'],
'field_one' => $arr['field_bb'],
'field_two' => $arr['field_bc'],
) ;
$row_three = array(
...
) ;
$global_array['firstSelect'][] = $array_one ;
$global_array['secondSelect'][] = $array_two ;
$global_array['thirdSelect'][] = $array_three ;
}
All my entries are added in $global_array['firstSelect'], others are empty
You could add a field indicating from which table a row is coming:
SELECT a.id AS field_id,
a.column2 AS field_2,
a.column3 AS field_3,
'firstSelect' as select_name
FROM tableA a
UNION
SELECT b.id AS field_id,
b.column2 AS field_2,
b.column3 AS field_3,
'secondSelect' as select_name
FROM tableB b
UNION
SELECT c.id AS field_id,
c.column2 AS field_2,
c.column3 AS field_3,
'thirdSelect' as select_name
FROM tableC c
And here is the PHP to process the result:
while(($row = $_opDB->fetch_assoc($result)) {
$select = $row['select_name'];
$global_array[$select][] = ['field_id' => $row['field_id'],
'field_one' => $row['field_2'],
'field_two' => $row['field_3']];
}
As CBroe rightly commented: If the tables are indeed identical you should make them into one table.
I trying to join table using ONE query into sub array with column name => column value..
Short table(1) "users" structure with data:
user_id email ...
1 xxx#xx.xx ...
2 yyy#yy.yy ...
Short table(2) "users_permissions" structure with data:
user_id plugin_enter offers_view ...
1 1 0 ...
2 1 1 ...
If i use classic method - join left
SELECT `uperms`.*, `u`.*
FROM (`users` as u)
LEFT JOIN `users_permissions` as uperms ON `u`.`user_id` = `uperms`.`user_id`
I get classic output
[0] = array(
'user_id' => 1,
'email' => xxx#xx.xx,
'plugin_enter' => 1,
'offers_view' => 0
),
[1] = array(
'user_id' => 2,
'email' => yyy#yy.yy,
'plugin_enter' => 1,
'offers_view' => 1,
...
),
All i need is output into subarray as this:
[0] = array(
'user_id' => 1,
'email' => xxx#xx.xx,
'permissions => array(
'plugin_enter' => 1,
'offers_view' => 0
),
),
...
Is this possible to do with ONE query?
Table2 (permissions) contains about 60 columns. Is possible to CONCAT column's names with column value, if is joined to Table1 only one row?
MySQL doesn't have arrays or nested structures, so it's not possible to do this in SQL.
Change your query so you give all the fields from users_permissions a consistent naming style. Then you can use a PHP loop to collect all the array elements whose keys match that pattern into the permissions array.
Query:
SELECT u.*, up.plugin_enter AS perm_plugin_enter, up.offers_view AS perm_offers_view, ...
FROM users AS u
JOIN users_permissions AS up ON u.user_id = up.user_id
PHP:
foreach ($all_results as &$row) {
$permissions = array();
foreach ($row as $key => $value) {
if (strpos($key, 'perm_') === 0) {
$permission[substr($key, 5)] = $value;
unset($row[$key]);
}
}
$row['permissions'] = $permissions;
}
You could do it by concatenating all the column names and values in the table:
SELECT u.*, CONCAT_WS(',', CONCAT('plugin_enter:', plugin_enter), CONCAT('offers_view:', offers_view), ...) AS permissions
FROM users AS u
JOIN users_permissions AS up ON u.user_id = up.user_id
Then your PHP code can use explode() to split $row['permissions'] into array of name:value pairs, and then convert those to key=>value in the PHP array.
Another solution is to redesign your users_permissions table:
user_id permission_type value
1 plugin_enter 1
1 offers_view 0
...
2 plugin_enter 1
2 offers_view 1
...
Then you can query:
SELECT u.*, GROUP_CONCAT(permission_type, ':', value) AS permission
FROM users AS u
JOIN users_permissions AS up on u.user_id = up.user_id
Another possible sollution is to add prefixes to query.
Inspired by post: https://stackoverflow.com/a/9926134/2795923
SELECT `u`.*, ':prefix_start:', `uperms`.*, ':prefix_end:'
FROM (`users` as u)
LEFT JOIN `users_permissions` as uperms ON `u`.`user_id` = `uperms`.`user_id`
Output array looks like this:
[0] => array(
'user_id' => 1
'email' => xxx#xx.xx,
'prefix_start' =>
'plugin_enter' => 1,
'offers_view' => 0
'prefix_end' =>
)
...
Then easy PHP script to add all array data between prefix_start and prefix_end into own subarray.
I have a SQL query that has alias in it. The problem is, when I try to get the values of columns it doesn't show the correct values:
$sql = "SELECT p.ID, p.ProfileID, p.ModuleID, p.View, p.Add, p.Edit, p.Delete, m.Name, m.ID FROM permission AS p, module AS m WHERE p.ModuleID = m.ID ORDER BY p.ProfileID ASC, m.Name ASC";
$result = array();
$i = 0;
foreach ($this->dbconnect->query($sql) as $row)
{
$result[$i] = array(
'ID' => $row['p.ID'],
'ProfileID' => $row['p.ProfileID'],
'ModuleID' => $row['p.ModuleID'],
'View' => $row['p.View'],
'Add' => $row['p.Add'],
'Edit' => $row['p.Edit'],
'Delete' => $row['p.Delete']);
$i += 1;
}
Running shows no value when in the database it's actually 10.
If I change the above code to the following:
$sql = "SELECT p.ID, p.ProfileID, p.ModuleID, p.View, p.Add, p.Edit, p.Delete, m.Name, m.ID FROM permission AS p, module AS m WHERE p.ModuleID = m.ID ORDER BY p.ProfileID ASC, m.Name ASC";
$result = array();
$i = 0;
foreach ($this->dbconnect->query($sql) as $row)
{
$result[$i] = array(
'ID' => $row['ID'],
'ProfileID' => $row['ProfileID'],
'ModuleID' => $row['ModuleID'],
'View' => $row['View'],
'Add' => $row['Add'],
'Edit' => $row['Edit'],
'Delete' => $row['Delete']);
$i += 1;
}
Miraculously, running shows the value of m.ID instead of p.ID. It is strange why the first example is incorrect. Am I missing something here?
You should something like this...
SELECT p.ID as p_ID, ...
And
'ID' => $row['p_ID'],
Use aliases in SELECT to each column, which are same:
$sql = "SELECT p.ID AS permission_id, p.ProfileID, p.ModuleID, p.View, p.Add, p.Edit, p.Delete, m.Name, m.ID AS module_id FROM permission AS p, module AS m WHERE p.ModuleID = m.ID ORDER BY p.ProfileID ASC, m.Name ASC";
then:
foreach(...)
{
$result[$i] = array(
'Perm_ID' => $row['permission_id'],
'Module_ID' => $row['module_id'],
...
}
I'm trying to get nested arrays for my Cakephp custom query below:
$this->query("
SELECT *
FROM group_buys GroupBuy
LEFT JOIN products Product
ON Product.id = GroupBuy.product_id
LEFT JOIN group_buy_users GroupBuysUser
ON GroupBuysUser.group_buy_id = GroupBuy.id
LEFT JOIN group_buy_images GroupBuyImage
ON GroupBuyImage.group_buy_id = GroupBuy.id
LEFT JOIN product_details ProductDetail
ON ProductDetail.product_id = Product.id
LEFT JOIN specifications Specification
ON Specification.id = ProductDetail.specification_id
LEFT JOIN specification_categories SpecificationCategory
ON SpecificationCategory.id = Specification.specification_category_id
WHERE GroupBuy.id = {$id}
");
Problem with this is that it comes up with redundant data obviously with GroupBuy table row values repeating which I don't want.
Is there a way we can have nested arrays if LEFT JOINED table has more rows than the former table with Cake's custom query?
I know this can be done with find recursive = 2 but would like to achieve this with custom query.
Have you tried using containable?
$this->GroupBuy->Behaviors->attach('Containable');
$this->GroupBuy->find('all', array(
'conditions' => array('GroupBuy.id' => $id),
'contain' => array(
'Product' => array(
'ProductDetail' => array(
'Specification' => array(
'SpecificationCategory'
)
)
),
'GroupBuysUser',
'GroupBuyImage'
),
));
Anyone knows a good way to make UNION query in CakePHP? I would like to avoid using $this->query();.
With two tables t1, t2:
SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
UNION
SELECT * FROM t1
RIGHT JOIN t2 ON t1.id = t2.id
With three tables t1, t2, t3:
SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
LEFT JOIN t3 ON t2.id = t3.id
UNION
SELECT * FROM t1
RIGHT JOIN t2 ON t1.id = t2.id
LEFT JOIN t3 ON t2.id = t3.id
UNION
SELECT * FROM t1
RIGHT JOIN t2 ON t1.id = t2.id
RIGHT JOIN t3 ON t2.id = t3.id
Too many coders try to limit themselves to the functionality of a framework. DON'T. Use what the framework provides. If it does not have the functionality you seek, then either:
Code the functionality you need into a class extension
or
Custom spin the code within the framework to suit your needs.
Often, developers try to hammer a square peg into a round hole and wind up doing way too much extra work that really only makes the code complicated. Take a step back and ask why you are using the framework to begin with. It brings structure to an unstructured language. It provides solid reusable foundation to build your application on. It is not intended to be a box to put yourself in and be limited.
UPDATE: I took a minute to read Complex Find Conditions and found your answer:
$joins = array(
array(
'table' => 'test_twos',
'alias' => 'TestTwo',
'type' => 'LEFT',
'conditions' => array(
'TestTwo.id = TestOne.id',
)
),
array(
'table' => 'test_threes',
'alias' => 'TestThree',
'type' => 'LEFT',
'conditions' => array(
'TestThree.id = TestOne.id',
)
)
);
$dbo = $this->getDataSource();
$subQuery = $dbo->buildStatement(
array(
'fields' => array('*'),
'table' => $dbo->fullTableName($this),
'alias' => 'TestOne',
'limit' => null,
'offset' => null,
'joins' => $joins,
'conditions' => null,
'order' => null,
'group' => null
),
$this->TestOne
);
$query = $subQuery;
$query .= ' UNION ';
$joins = array(
array(
'table' => 'test_twos',
'alias' => 'TestTwo',
'type' => 'LEFT',
'conditions' => array(
'TestTwo.id = TestOne.id',
)
),
array(
'table' => 'test_threes',
'alias' => 'TestThree',
'type' => 'RIGHT',
'conditions' => array(
'TestThree.id = TestOne.id',
)
)
);
$dbo = $this->getDataSource();
$subQuery = $dbo->buildStatement(
array(
'fields' => array('*'),
'table' => $dbo->fullTableName($this),
'alias' => 'TestOne',
'limit' => null,
'offset' => null,
'joins' => $joins,
'conditions' => null,
'order' => null,
'group' => null
),
$this->TestOne
);
$query .= $subQuery;
pr($query);
A simple way to do this, which we currently use, is to create a view in MySQL or whatever database you use. Then, instead of using a table in your model, you use your view. You can read about view creation syntax here: http://dev.mysql.com/doc/refman/5.6/en/create-view.html. You could also use software like HeidiSQL to help you with view creation.
You would then have something like this in your model :
class Contenu extends AppModel {
public $useTable = 'v_contenu';
This allows you to still use the find() method in CakePHP, which is really nice to have.
To get the best performance with views you should update MySQL to at least version 5.6.
Use a view, then select from that:
create view my_union as
SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
LEFT JOIN t3 ON t2.id = t3.id
UNION
SELECT * FROM t1
RIGHT JOIN t2 ON t1.id = t2.id
LEFT JOIN t3 ON t2.id = t3.id
UNION
SELECT * FROM t1
RIGHT JOIN t2 ON t1.id = t2.id
RIGHT JOIN t3 ON t2.id = t3.id
In your code:
select * from my_union
use a code like this :
$friendsPosts= $this->Posts->find('all')
->contain(['Users', 'Languages', 'PostStates'])
->innerJoinWith('Users.Dusers', function ($q) {
return $q->where(['Dusers.id' => $this->Auth->user('id')]);
});
$posts= $this->Posts->find('all')
->where(['Posts.post_state_id' => 3])
->contain(['Users', 'Languages', 'PostStates']);
$posts->union($friendsPosts);