Is Yii1 has any native methods to get the raw SQL with variables built?
I try to get a complex query built on a few subqueries using CDbExpression and CommandBuilder. I got this as a result:
SELECT * FROM `news` `t` WHERE id IN (:ycp0, :ycp1, :ycp2, :ycp3, :ycp4) LIMIT 5
The dump of the criteria content:
CDbCriteria Object (
[select] => *
[condition] => id IN (:ycp0, :ycp1, :ycp2, :ycp3, :ycp4)
...
[params] => Array(
[:ycp0] => CDbExpression Object(
[expression] => SELECT id FROM `news` `t` WHERE (rubric=:rb1) AND (:im2 & `im`=:im2) LIMIT 1
[params] => Array(
[:rb1] => 1
[:im2] => 2
)
)
...
)
)
I expected for compiled query string like this:
SELECT * FROM .. WHERE id IN(
(SELECT id FROM .. WHERE .. ORDER BY .. LIMIT 1),
(SELECT id FROM .. WHERE .. ORDER BY .. LIMIT 1)
) ORDER BY .. LIMIT 5
This is what I do in my code
$criteria = new CDbCriteria( ... );
$sql = $this->commandBuilder->createFindCommand($tableName, $criteria)->getText();
$queries[] = new CDbExpression($sql, $criteria->params);
Then I try to combine subqueries to one complex query
$criteria = new CDbCriteria( ... );
$criteria->addInCondition('id', $queries);
And finally, I try to get the result as SQL-query
$sql = $this->commandBuilder->createFindCommand($tableName, $criteria)->getText();
You get the SQL with params, as you have
$sql = $this->commandBuilder->createFindCommand($tableName, $criteria)->getText();
Then get the params enclosed in quotes:
$params = array_map(function($param) { return '"' . $param . '"'; }, $criteria->params);
Finally, replace the pairs:
echo strtr($sql, $params);
You can use enableParamLogging in your db config (boolean). You can set it up so it's used conditionally -- make sure to not use it in production.
'db' => [
'connectionString' => 'mysql:host=' . $dbhost . ';port=' . $dbport . ';dbname=' . $dbname,
'emulatePrepare' => true,
'username' => $db_user,
'password' => $db_pass,
'schemaCachingDuration' => 3600,
'charset' => 'utf8',
'enableProfiling' => $db_profile,
'enableParamLogging' => $db_params,
],
Then you can add 'class'=>'CWebLogRoute' to your log routes if you want to see all the output in your browser. docs
I think you want to do something like this:
$criteria = ...;
$command = $builder->createFindCommand($schema->getTable('name_of_table'), $criteria);
$results = $command->text;
There are few other options to perform the same thing but i will suggest you
should use the following
$results = MyModel::model()->findAllBySql("...");
Or you can prefer the following :
Sub-queries ActiveRecord Yii
Related
When I select a column in SQL Server and then print it, 3 becomes 3.0.
This is my connection:
$sql = new PDO("sqlsrv:Driver=$driver;server=$server,$port;Database=$database;ConnectionPooling=0", $uid, $pwd,
array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
)
);
This is my SELECT:
$sth = $sql->prepare("SELECT column FROM table
WHERE column2 = :value2");
$params = array(':value2' => $_POST['value2']);
$sth->execute($params);
$result = $sth->fetchAll(\PDO::FETCH_ASSOC);
echo json_encode($result);
In SQL Server database: 3
In echo: 3.0
What can be the reason for adding .0?
I am trying to pass table name and column name from String to the sql query, but for some reason it doesnt work.
This is an example of what am trying to do from symfony 4.4 documentation :
This is how I am trying to do it :
$sql = "SELECT
:col,
COUNT(*) AS `cnt`
FROM
:tab
GROUP BY
:col
";
$stmt = $conn->prepare($sql);
$stmt->execute([ 'col' => $col , 'tab' => $tab ]);
return $stmt->fetchAllAssociative();
output :
meanwhile, it works like this :
$sql = "SELECT
typeCl,
COUNT(*) AS `cnt`
FROM
client
GROUP BY
typeCl
";
$stmt = $conn->prepare($sql);
$stmt->execute([ 'col' => $col , 'tab' => $tab ]);
return $stmt->fetchAllAssociative();
And I still want to make my table and column parametrable .. is there anyway to do that ??
(It is not about my String values I used dump and die and make sure nothign wrong with that)
This is how i made it work :
$sql = "SELECT ".$col.",
COUNT(*) AS `cnt`
FROM
".$tab."
GROUP BY
".$col."
";
$stmt = $conn->prepare($sql);
$stmt->execute([ 'col' => $col , 'tab' => $tab ]);
return $stmt->fetchAllAssociative();
I dont get it ... I tested a lot but dont get why a SQL error appears ...
In my case I use a function to generate a mysql-query to get all extra-field items from the database (K2 - Component).
It is used like this:
public static function readExtraFields ($fields, $as = 'array') {
if (!is_array($fields)) $fields = json_decode($fields);
$result = array();
$whereId = array();
$allFieldValues = array();
foreach ($fields as $field) {
$whereId[] = "`id`='".$field->id."'";
$allFieldValues[$field->id] = $field->value;
}
$query = "SELECT * FROM `#__k2_extra_fields` WHERE " . implode(" OR ", $whereId);
$queryResult = self::execQuery($query);
[...]
In this method a query will be generated like this (I printed it out)
SELECT * FROM `#__k2_extra_fields` WHERE `id`='1' OR `id`='2'
This is fine. When I execute the methode execQuery with the given query this error appears:
1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1 SQL=SELECT * FROM `j7req_k2_extra_fields` WHERE
Thats all ... I dont get it. My method to execute my mysql-query:
public static function execQuery ($query) {
$db = JFactory::getDbo();
$db->setQuery($query);
$result = $db->loadObjectList();
return $result;
}
For testing I printed out the Query (the above) and set $query to the printed query and this runs without any problems like the way it should work ... So the query which is given is right ... what can be the problem ?
Edit 1
In my execQuery method I printed the $db out. This reuslt is given (you can find the query at the bottom of this object)
JDatabaseDriverMysqli Object
(
[name] => mysqli
[nameQuote:protected] => `
[nullDate:protected] => 0000-00-00 00:00:00
[_database:JDatabaseDriver:private] => podopraxis
[connection:protected] => mysqli Object
(
[affected_rows] => 1
[client_info] => mysqlnd 5.0.11-dev - 20120503 - $Id: bf9ad53b11c9a57efdb1057292d73b928b8c5c77 $
[client_version] => 50011
[connect_errno] => 0
[connect_error] =>
[errno] => 0
[error] =>
[error_list] => Array
(
)
[field_count] => 1
[host_info] => localhost via TCP/IP
[info] =>
[insert_id] => 0
[server_info] => 5.6.16
[server_version] => 50616
[stat] => Uptime: 48979 Threads: 1 Questions: 6461 Slow queries: 0 Opens: 163 Flush tables: 1 Open tables: 155 Queries per second avg: 0.131
[sqlstate] => 00000
[protocol_version] => 10
[thread_id] => 203
[warning_count] => 0
)
[count:protected] => 45
[cursor:protected] =>
[debug:protected] =>
[limit:protected] => 0
[log:protected] => Array
(
)
[timings:protected] => Array
(
)
[callStacks:protected] => Array
(
)
[offset:protected] => 0
[options:protected] => Array
(
[driver] => mysqli
[host] => localhost
[user] => root
[password] =>
[database] => podopraxis
[prefix] => j7req_
[select] => 1
[port] => 3306
[socket] =>
)
[sql:protected] => SELECT * FROM `#__k2_extra_fields` WHERE `id`='1' OR `id`='2'
[tablePrefix:protected] => j7req_
[utf:protected] => 1
[errorNum:protected] => 0
[errorMsg:protected] =>
[transactionDepth:protected] => 0
[disconnectHandlers:protected] => Array
(
)
)
It looks like your query fired in execQuery() function is missing the condition statement after "WHERE" clause of query.
Please make sure below part of condition comes in your query:
`id`='1' OR `id`='2'
let me know if I am not getting well about your question?
Also try to post here whole $db object by printing as below:
echo "<pre />";print_r($db);exit;
Is there a way to execute a SQL String as a query in Zend Framework 2?
I have a string like that:
$sql = "SELECT * FROM testTable WHERE myColumn = 5"
now I want to execute this string directly.
Just pass the sql string to your db adapter like this:
$resultSet = $adapter->query($sql, \Zend\Db\Adapter\Adapter::QUERY_MODE_EXECUTE);
And if you want to pass parameters:
$sql = "SELECT * FROM testTable WHERE myColumn = ?";
$resultSet = $adapter->query($sql, array(5));
EDIT: Please note that the query method does not always returns a resultset. When its a resultset producing query(SELECT) it returns a \Zend\Db\ResultSet\ResultSet otherwise(INSERT, UPDATE, DELETE, ...) it will return a \Zend\Db\Adapter\Driver\ResultInterface.
And when you leave the second Parameter empty you will get a \Zend\Db\Adapter\Driver\StatementInterface which you can execute.
use Zend\Db\Sql\Sql;
use Zend\Db\Adapter\Adapter;
$dbAdapterConfig = array(
'driver' => 'Mysqli',
'database' => 'dbname',
'username' => 'dbusername',
'password' => 'dbuserpassword'
);
$dbAdapter = new Adapter($dbAdapterConfig);
$sql = new Sql($dbAdapter);
$select = $sql->select();
$select->from('testTable');
$select->where(array('myColumn' => 5));
$statement = $sql->prepareStatementForSqlObject($select);
$result = $statement->execute();
S. docu: Zend\Db → Zend\Db\Sql
If you are using tableGateway, you can run your raw SQL query using this statement,
$this->tableGateway->getAdapter()->driver->getConnection()->execute($sql);
where $sql pertains to your raw query. This can be useful for queries that do not have native ZF2 counterpart like TRUNCATE / INSERT SELECT statements.
If you have EntityManager $em on your hands, you can do something like this:
$select = $em->getConnection()->executeQuery("
SELECT a.id, a.title, a.announcement, asvc.service_id, COUNT(*) AS cnt,
GROUP_CONCAT(asvc.service_id SEPARATOR \", \") AS svc_ids
FROM article AS a
JOIN articles_services AS asvc ON asvc.article_id = a.id
WHERE
asvc.service_id IN (
SELECT tsvc.service_id
FROM tender AS t
JOIN tenders_services AS tsvc ON tsvc.tender_id = t.id
WHERE t.id = :tenderId
)
GROUP BY a.id
ORDER BY cnt DESC, a.id DESC
LIMIT :articlesCount
", [
'articlesCount' => 5,
'tenderId' => $tenderId,
], [
'articlesCount' => \PDO::PARAM_INT,
]);
$result = $select->fetchAll(); // <-- here are array of wanted rows
I think this way to execute complex queries is best for Zend. But may be I'm not very smart in Zend still. Will glad to see if it helps to someone.
public function getInterests($userID) {
$result = $this->tableGateway->select(function (Select $select) use ($userID) {
$select->join('interests', 'users_interests.interest_id = interests.interest_id', array('*'), 'left');
$where = new Where();
$where->equalTo('user_id', $userID);
$select->where($where);
});
return $result;
}
Here is my method. It simply selects all records from users_interests with user_id = $userID and joins the 'interests' table. So far, so good, but when trying to display the fetched results, the fields from the joined table just do not exist. Here is the dump of the $result:
Zend\Db\ResultSet\ResultSet Object
(
[allowedReturnTypes:protected] => Array
(
[0] => arrayobject
[1] => array
)
[arrayObjectPrototype:protected] => Object\Model\UsersInterests Object
(
[settings_id] =>
[user_id] =>
[interest_id] =>
)
[returnType:protected] => arrayobject
[buffer:protected] =>
[count:protected] => 2
[dataSource:protected] => Zend\Db\Adapter\Driver\Pdo\Result Object
(
[statementMode:protected] => forward
[resource:protected] => PDOStatement Object
(
[queryString] => SELECT `users_interests`.*, `interests`.* FROM `users_interests` LEFT JOIN `interests` ON `users_interests`.`interest_id` = `interests`.`interest_id` WHERE `user_id` = :where1
)
[options:protected] =>
[currentComplete:protected] =>
[currentData:protected] =>
[position:protected] => -1
[generatedValue:protected] => 0
[rowCount:protected] => 2
)
[fieldCount:protected] => 6
[position:protected] =>
)
I badly need help on this because I am supposed to finish my project until Sunday. Thanks in advance.
You can use the following to apply left join. $select::JOIN_LEFT instead of 'left'.
public function getInterests($userID) {
$result = $this->tableGateway->select(function (Select $select) use ($userID) {
$select->join('interests', 'users_interests.interest_id = interests.interest_id', array('*'), $select::JOIN_LEFT);
$where = new Where();
$where->equalTo('user_id', $userID);
$select->where($where);
});
return $result;
}
It seems you have a problem in the WHERE clause of the join. This also shows in the error here:
[queryString] => SELECT `users_interests`.*, `interests`.* FROM `users_interests` LEFT JOIN .
`interests` ON `users_interests`.`interest_id` = `interests`.`interest_id`
WHERE `user_id` = :where1
Try this:
$select->from($this->table)
->join('interests', 'users_interests.interest_id = interests.interest_id',
array('*'), 'left');
$where = new Where();
$where->equalTo('user_id', $userID) ;
$select->where($where);
I can not follow your code completely, like here:
$this->tableGateway->select(function (Select $select) use ($userID) {
But, here is a very nice article on this. I think, you can simplify your code a little.
Have you iterated over the resultset? You can see there's two matching rows:
[rowCount:protected] => 2
You have a ResultSet object, but it will not load any of the rows until requested, they are "lazy loaded" when you iterate over the object.
You can force the resultset to get them all for you:
var_dump($resultSet->toArray()); // force load all rows
or iterate over the ResultSet:
foreach($resultset as $row) {
var_dump($row); // each row loaded on request
}
I have written about this before and maybe it will help you as well.
TableGateway with multiple FROM tables