How can I dot that in CakePHP?
I try everything I know, but doesn't work:
select
card_type
,sum (case when used = 'Y' then (select amount from auth a1 where a1.origid = a.pnref and trxtype = 'D') else amount end) as total
from auth a
where
add_date between '$this->date1' and '$this->date2'
and (trxtype = 'S' or trxtype = 'F')
and user_num = $this->user_num
and pnref not in (select origid
from auth a
where add_date between '$this->date1' and '$this->date2'
and trxtype = 'V')
group by card_type
order by 1
Sub-query in fields
Sub-query in where
[I try this]:
$conditionsSubQuery['"Auth2"."add_date BETWEEN ? AND ?"'] = array($inicial_date, $final_date);
$conditionsSubQuery['"Auth2"."trxtype"'] = 'V';
$db = $this->User->getDataSource();
$subQuery = $db->buildStatement(
array(
'fields' => array('"Auth2"."origid"'),
'table' => 'auth',
'alias' => 'Auth2',
'limit' => null,
'offset' => null,
'joins' => array(),
'conditions' => $conditionsSubQuery,
'order' => null,
'group' => null
),
$this->Auth
);
$subQuery = ' "Auth"."pnref" NOT IN (' . $subQuery . ') ';
$subQueryExpression = $db->expression($subQuery);
$conditions[] = $subQueryExpression;
$conditions[] = array(
'Auth.date BETWEEN ? and ?' => array($inicial_date, $final_date),
'OR' => array(
'Auth.trxtype' => 'S',
'Auth.trxtype' => 'F'
),
'Auth.user_num' => $user_num
);
$fields = array(
'Auth.card_type',
"sum (case when Auth.used = 'Y' then (select Auth2.amount from auth Auth2 where Auth2.origid = Auth.pnref and Auth.trxtype = 'D') else Auth.amount end) as Auth.total"
);
$group = array('Auth.card_type');
$order = array(1);
return $this->Auth->find('all', compact('fields', 'conditions', 'group', 'order'));
[ERROR]
Database Error
Error: SQLSTATE[42601]: Syntax error: 7 ERRO: erro de sintaxe em ou próximo a "." LINE 1: ... Auth.trxtype = 'D') else Auth.amount end) as Auth.total, "U... ^
SQL Query: SELECT "Auth"."card_type" AS "Auth__card_type", sum (case when Auth.used = 'Y' then (select Auth2.amount from auth Auth2 where Auth2.origid = Auth.pnref and Auth.trxtype = 'D') else Auth.amount end) as Auth.total, "User"."user_num" AS "User__user_num" FROM "public"."system_users" AS "User" WHERE "Auth"."pnref" NOT IN (SELECT "Auth2"."origid" FROM auth AS "Auth2" WHERE "Auth2"."add_date BETWEEN '2013/02/19 06:00:00' AND '2013/02/22 10:34:17'" AND "Auth2"."trxtype" = 'V' ) AND (("Auth"."date" BETWEEN '2013/02/19 06:00:00' and '2013/02/22 10:34:17') AND ("Auth"."trxtype" = 'F') AND ("Auth"."user_num" = 68)) GROUP BY "Auth"."card_type" ORDER BY "1" ASC
Notice: If you want to customize this error message, create app\View\Errors\pdo_error.ctp
Anyway, thanks.
Like #Chris Traveres comment, is just a syntax error.
The problem in the query is pretty obvious that the identifier is
being incorrectly associated. the relevant clause of the error
message's query is "Auth2"."add_date BETWEEN '2013/02/19 06:00:00' AND
'2013/02/22 10:34:17'" and I doubt you have a boolean column named
"add_date BETWEEN '2013/02/19 06:00:00' AND '2013/02/22 10:34:17'" so
the question really should be limited to CakePHP syntax
Problem solved!
Thanks guys.
Related
SELECT
CONCAT(us.user_id,' ', us.name),
UPPER(sc.so_number) Order_no ,
sh.upc UPC,re.label Error,
(SELECT count(*) FROM order_checker_scan scan WHERE scan.so_number =sh.so_number and scan.upc=sh.upc and scan.user_id!=0
and DATE_FORMAT(scan_time,'%Y-%m-%d') >= '2015-11-01' ) AS
prev_data,
(select CONCAT(u.user_id,' ', u.name) from users u,picklist_history p where u.user_id=p.user_id and
p.so_number=sh.so_number limit 1) as picker,
sh.item_key Times,
DATE_FORMAT(sc.date_started,'%b%d %Y %h:%i%p') datetime,sh.qty_required QTY
FROM
order_checker_short sh,
order_checker_header
sc,order_checker_short_reason re,
users us
WHERE sh.so_number=sc.so_number AND
sh.reason_id=re.reason_id AND
sc.created_by=us.user_id And
sc.created_by!=0 AND
DATE_FORMAT(date_started,'%Y-%m-%d') between '2015-11-16' and '2015-11-17' AND
sh.reason_id !=0 AND
sh.upc !=1
GROUP BY sc.so_number,sh.upc
ORDER BY sc.date_started DESC, sc.so_number DESC , sh.upc ASC
Please test the following:
// 1st subselect
$prevDataSelect = $db->select()
->from(array('scan' => 'order_checker_scan'), array('count(*)'))
->where('scan.so_number = sh.so_number')
->where('scan.upc = sh.upc')
->where('scan.user_id != 0')
->where("DATE_FORMAT(scan_time,'%Y-%m-%d') >= '2015-11-01'");
// 2nd subselect
$pickerSelect = $db->select()
->from(array('u' => 'users', 'p' => 'picklist_history'), array("CONCAT(u.user_id,' ', u.name)"))
->where('u.user_id = p.user_id')
->where('p.so_number = sh.so_number')
->limit(1);
// Main selection
$mainSelect = $db->select()
->from(
// tables
array(
'sh' => 'order_checker_short',
'sc' => 'order_checker_header',
're' => 'order_checker_short_reason',
'us' => 'users',
),
// columns
array(
'SomeName' => "CONCAT(us.user_id, ' ', us.name)",
'Order_no' => 'UPPER(sc.so_number)',
'UPC' => 'sh.upc',
'Error' => 're.label',
'prev_data' => new Zend_Db_Expr('(' . $prevDataSelect . ')'),
'picker' => new Zend_Db_Expr('(' . $pickerSelect . ')'),
'Times' => 'sh.item_key',
'datetime' => "DATE_FORMAT(sc.date_started,'%b%d %Y %h:%i%p')",
'QTY' => 'sh.qty_required',
)
)
// AND WHERE clauses
->where('sh.so_number = sc.so_number')
->where('sh.reason_id = re.reason_id')
->where('sc.created_by = us.user_id')
->where('sc.created_by != 0')
->where("DATE_FORMAT(date_started, '%Y-%m-%d') between '2015-11-16' and '2015-11-17'")
->where('sh.reason_id != 0')
->where('sh.upc != 1')
// GROUP BY clause
->group(array('sc.so_number', 'sh.upc'))
->order(array('sc.date_started DESC', 'sc.so_number DESC', 'sh.upc ASC'));
If doesn't work please tell me what's the output of $mainSelect->assemble()
$phql = 'SELECT id,username,email FROM Users WHERE active = :active: LIMIT :offset:, :limit:';
$users = $this->modelsManager->executeQuery($phql, array('active' => 'Y', 'offset' => 100, 'limit' => 10));
//But Generates the error SQL statement
//SELECT `users`.`id` AS `id`, `users`.`username` AS `username`, `users`.`email` AS `email` FROM `users` WHERE `users`.`active` = 'Y' LIMIT '10' OFFSET '100'
ANY one help me ? just using $this->modelsManager...,whith $phql to bind numeric parameters.
I haven't had the chance to test it out, but from the PHQL, modelsManager, and Query documentation, it seems that you can enforce it by creating a query rather than executing it straight away, and then executing it with the specific types you want:
// Create the query
$phql = 'SELECT id,username,email FROM Users WHERE active = :active: LIMIT :offset:, :limit:';
$query = $this->modelsManager->createQuery($phql);
// Setup the values to bind
$values = array(
'active' => 'Y',
'offset' => 100,
'limit' => 10
);
// Setup the type for each value
$types = array(
'active' => Phalcon\Db\Column::BIND_PARAM_STR,
'offset' => Phalcon\Db\Column::BIND_PARAM_INT,
'limit' => Phalcon\Db\Column::BIND_PARAM_INT
);
// Execute the query
$users = $query->execute($values, $types);
Cakephp 2.6
I have a Model, Temps, which has many tickets. In the index view of Temps I want to return for each record, the ticket with the date closest to the current date.
In mySQL it can be done as
'SELECT expiry_date FROM uploads WHERE expiry_date > CURDATE() ORDER BY expiry_date ASC LIMIT 1'
But I don't know how to run this as a sub query. My Current query to generate my results is as follows: (bearing in mind this has been configured for datatables) Tickets is an alias for the Upload Model
public function getAjaxIndexData($data) {
$tokens = explode(" ", $data['searchString']);
$conditions = array(
$this->alias . '.deleted' => false,
'OR' => array(
'CONCAT(' . $this->alias . '.first_name," ",' . $this->alias . '.last_name) LIKE' => '%' . implode(' ', $tokens) . '%',
),
$data['columnsFilter']
);
$fields = array(
'id',
'full_name',
'pps_number',
'mobile',
'email',
'start_date',
'time_served'
);
$order = array(
$data['orderField'] => $data['order']
);
$contain = array(
'LocalOffice.name',
);
$options = array(
'conditions' => $conditions,
'fields' => $fields,
'order' => $order,
'contain' => $contain,
'limit' => $data['limit'],
'offset' => $data['start']
);
$optionsNoFields = array(
'conditions' => $conditions,
'contain' => $contain,
);
$result['draw'] = $data['draw'];
$result['recordsTotal'] = $recordTotal = $this->find('count');
$result['recordsFiltered'] = $this->find('count', $optionsNoFields);
$result['data'] = $this->find('all', $options); //standard search
$result['data'] = $this->formatTable($result['data']);
return json_encode($result);
}
Within this query I would like to add a field that shows the nearest expiry date for each Temp.
How would I construct this?
Dynamically create a virtual field:
$this->virtualFields['nearest'] = '(SELECT expiry_date FROM uploads WHERE expiry_date > CURDATE() AND uploads.owner_id = '.$this->alias.'.ticket_id ORDER BY expiry_date ASC LIMIT 1')';
Then adjust your fields array
$fields = array(
'id',
'full_name',
'pps_number',
'mobile',
'email',
'start_date',
'time_served',
'nearest'
);
Also, the query could be rewritten as ("temp" needs to be replaced with the model alias)
SELECT MIN(expiry_date)
FROM uploads
WHERE expiry_date > CURDATE()
AND uploads.owner_id = temp.ticket_id;
Which means that a potentially better performing query would be to move that subquery out of the columns of the SELECT statement to a JOIN. For example:
SELECT *
FROM temp
LEFT JOIN (SELECT MIN(expiry_date) AS expiry,owner_id
FROM uploads
WHERE expiry_date > CURDATE())
GROUP BY owner_id) AS next_dates
ON next_dates.owner_id = temp.ticket_id;
There is join, and I need to include value from it in 'where'. Is there any way to do this? In other words, I want to apply 'where' clause only to that values, which being joined. I'm really got confused with it, and may be this task can be solved more easily.
$this->table = "CoolTable";
$sql = new Sql($this->getAdapter());
$select = $sql->select()
->columns(array(/*some expressions...*/))
->from($this->table)
->join(
array('ct' => 'CoolTable'),
new Expression('
ct.a = CoolTable.a AND
ct.b = CoolTable.b
'),
array()
)
/*another joins...*/
->where(array(
'CoolTable.a' => $someExternalVar,
'CoolTable.b = ?' => '$ct.a',
))
What about my tries:
'CoolTable.b = ?' => '$ct.a'
'CoolTable.b' => 'ct.a'
'CoolTable.b' => new Expression('ct.a') /*it's a really pity, yes*/
new Predicate\PredicateSet(
array(
new Operator(
'CoolTable.b',
Operator::OPERATOR_EQUAL_TO,
'ct.a'
),
),
Predicate\PredicateSet::TYPE_VALUE
),
How can I transform the SQL statement into the CakePHP Code? I am able to get the group by result. But how can I add the inner Select Count(*) statement?
I've updated the code under "Revised" However, I am getting this error. Parse error: syntax error, unexpected 'INCOMPLETE' (T_STRING), expecting ')'. I am sure I check my open and close brackets.
SQL Statement below
SELECT
`id` ,
`mtpToken` ,
`mtpCreator_id` ,
`school_id` ,
`user_id` ,
`mtpStatus` ,
`created` ,
`modified` ,
(
(SELECT COUNT( * ) FROM mtpScreenings
WHERE (mtpStatus = 'INCOMPLETE' OR mtpStatus = 'HALFWAY') AND mtpToken = `mtpToken` )
) AS `mainStatus`
FROM `mtpScreenings` WHERE `mtpScreenings`.`school_id` = 15 GROUP BY `mtpToken`
CakePHP Code below
$setting = $this->paginate = array(
conditions' => array('MtpScreening.school_id' => 15),
'recursive' => -1,
'fields' => array('MtpScreening.field1'),
'group' => array('MtpScreening.mtpToken'),
'limit' => 1000
);
Revised
$setting = $this->paginate = array(
conditions' => array('MtpScreening.school_id' => 15),
'recursive' => -1,
'fields' => array('SELECT COUNT(*) FROM mtpScreenings
WHERE (mtpStatus = "INCOMPLETE" OR mtpStatus = "HALFWAY") AND mtpToken = `mtpToken`
) AS mainStatus'),
'group' => array('MtpScreening.mtpToken'),
'limit' => 1000
);
Virtual Field
Code example of virtual field:
public $virtualFields = array(
'count' => "SELECT COUNT( * ) FROM MtpScreening
WHERE (MtpScreening.mtpStatus = 'INCOMPLETE' OR MtpScreening.mtpStatus = 'HALFWAY') AND MtpScreening.mtpToken = 'mtpToken'"
);
This code will produce virtual field:
$this->find('all', array(
'fields'=>array(
'MtpScreening.id',
'MtpScreening.mtpToken',
'MtpScreening.mtpCreator_id',
'MtpScreening.school_id',
'MtpScreening.count'/*virtual field*/
)
)
);
Pagination and virtual fields
Since virtual fields behave much like regular fields when doing
find’s, Controller::paginate() will be
able to sort by virtual fields too.