I'm trying to compare dates in my validation. The documentation says it's possible but It's not documented.
I'm using annotations and I want one date to be later that the other.
How do I do this?
I've eventually solved it using expressions like so:
/**
* #var \Datetime
* #Assert\Type(
* type = "\DateTime",
* message = "vacancy.date.valid",
* )
* #Assert\GreaterThanOrEqual(
* value = "today",
* message = "vacancy.date.not_today"
* )
*/
private $startdate;
/**
* #var \Datetime
* #Assert\Type(
* type = "\DateTime",
* message = "vacancy.date.valid",
* )
* #Assert\GreaterThanOrEqual(
* value = "today",
* message = "vacancy.date.not_today"
* )
* #Assert\Expression(
* "this.getEnddate() >= this.getStartdate()",
* message="vacancy.date.not_more_than"
* )
*/
private $enddate;
Use strtotime
You can convert the date format to timestap and then compare them both
Related
I am attempting to convert an MS-Access query to a postgres statement so I can use it in SSRS. Seems to work great except for the IIF statement.
SELECT labor_sort_1.ncm_id
,IIf(labor_sort_1.sortby_employeeid = 3721
, ((labor_sort_1.MaxUpdatedAt - labor_sort_1.MinNCMScanTime) * 24 * 29 * labor_sort_1.number_of_ops)
, IIf(labor_sort_1.sortby_employeeid = 3722
, ((labor_sort_1.MaxUpdatedAt - labor_sort_1.MinNCMScanTime) * 24 * 24 * labor_sort_1.number_of_ops)
, IIf(labor_sort_1.sortby_employeeid = 3755, ((labor_sort_1.MaxUpdatedAt - labor_sort_1.MinNCMScanTime) * 24 * 24 * labor_sort_1.number_of_ops)
, ((labor_sort_1.MaxUpdatedAt - labor_sort_1.MinNCMScanTime) * 24 * 17 * labor_sort_1.number_of_ops)))) AS labor_cost
FROM ...
it returns the following message
function iif(boolean, interval, interval) does not exist
How would I solve this problem?
You'll need to switch the logic over to a CASE expression. CASE expression are standard for most RDBMS's so it's worth learning. In your case (pun intended) it would translate to:
CASE
WHEN labor_sort_1.sortby_employeeid = 3721
THEN (labor_sort_1.MaxUpdatedAt - labor_sort_1.MinNCMScanTime) * 24 * 29 * labor_sort_1.number_of_ops
WHEN labor_sort_1.sortby_employeeid = 3722
THEN (labor_sort_1.MaxUpdatedAt - labor_sort_1.MinNCMScanTime) * 24 * 24 * labor_sort_1.number_of_ops
WHEN labor_sort_1.sortby_employeeid = 3755
THEN (labor_sort_1.MaxUpdatedAt - labor_sort_1.MinNCMScanTime) * 24 * 24 * labor_sort_1.number_of_ops
ELSE
(labor_sort_1.MaxUpdatedAt - labor_sort_1.MinNCMScanTime) * 24 * 17 * labor_sort_1.number_of_ops)
END AS labor_cost
Which is a lot cleaner looking since you don't have to monkey with nested iif() issues and all that and should you need to add more employeeids to the list of hard-coded labor costs, it's no biggie.
You might also find it advantageous to us the IN condition instead so you only need two WHEN clauses:
CASE
WHEN labor_sort_1.sortby_employeeid = 3721
THEN (labor_sort_1.MaxUpdatedAt - labor_sort_1.MinNCMScanTime) * 24 * 29 * labor_sort_1.number_of_ops
WHEN labor_sort_1.sortby_employeeid IN (3722, 3755)
THEN (labor_sort_1.MaxUpdatedAt - labor_sort_1.MinNCMScanTime) * 24 * 24 * labor_sort_1.number_of_ops
ELSE
(labor_sort_1.MaxUpdatedAt - labor_sort_1.MinNCMScanTime) * 24 * 17 * labor_sort_1.number_of_ops)
END AS labor_cost
Also, you could move the CASE expression into the equation so the logic only needs to determine whatever number you wish to multiply by:
(labor_sort_1.MaxUpdatedAt - labor_sort_1.MinNCMScanTime)
* 24
* CASE
WHEN labor_sort_1.sortby_employeeid = 3721 THEN 29
WHEN labor_sort_1.sortby_employeeid IN (3722,3755) THEN 24
ELSE 17
END
* labor_sort_1.number_of_ops AS labor_cost
((this is a Wiki, you can edit!))
Same as #Daniel's answer, but generalizing to any datatype.
CREATE or replace FUNCTION iIF(
condition boolean, -- IF condition
true_result anyelement, -- THEN
false_result anyelement -- ELSE
) RETURNS anyelement AS $f$
SELECT CASE WHEN condition THEN true_result ELSE false_result END
$f$ LANGUAGE SQL IMMUTABLE;
SELECT iif(0=1,1,2);
SELECT iif(0=0,'Hello'::text,'Bye'); -- need to say that string is text.
Good when you are looking for a public-snippets-library.
NOTE about IMMUTABLE and "PLpgSQL vs SQL".
The IMMUTABLE clause is very important for code snippets like this, because, as said in the Guide: "allows the optimizer to pre-evaluate the function when a query calls it with constant arguments"
PLpgSQL is the preferred language, except for "pure SQL". For JIT optimizations (and sometimes for parallelism) SQL can obtain better optimizations. Is something like copy/paste small piece of code instead of use a function call.
Important conclusion: this function, after optimizations, is so fast than the #JNevill's answer; it will compile to (exactly) the same internal representation. So, although it is not standard for PostgreSQL, it can be standard for your projects, by a centralized and reusable "library of snippets", like pg_pubLib.
I know this has been sitting around for a while but another option is to create a user defined function. If you happen to stumble upon this in your internet searches, this may be a solution for you.
CREATE FUNCTION IIF(
condition boolean, true_result TEXT, false_result TEXT
) RETURNS TEXT LANGUAGE plpgsql AS $$
BEGIN
IF condition THEN
RETURN true_result;
ELSE
RETURN false_result;
END IF;
END
$$;
SELECT IIF(2=1,'dan the man','false foobar');
Should text not tickle your fancy then try function overloading
Im executing this query:
$query = "
Select * From table1 Where id = 1;
Select * From table2 Where name = 'test';
";
With \Zend\Db\Adapter\Adapter:
$stmt = $this->dbAdapter->query($query);
$rawResult = $stmt->execute();
How can I access the second result?
$rawResult->next() only returns values from first query.
Use two different queries.
/*
* First Query
*/
$query = "
Select * From table1 Where id = 1
";
$stmt = $this->dbAdapter->query($query);
$rawResult = $stmt->execute();
/*
* Second Query
*/
$query = "
Select * From table2 Where name = 'test'
";
$stmt = $this->dbAdapter->query($query);
$rawResult = $stmt->execute();
I don't believe it works the way you had it to where two queries in a row are sent this way.
To avoid code duplication you can wrap the duplicated code into a method.
$rawResult1 = $this->getResults("Select * From table1 Where id = 1");
$rawResult2 = $this->getResults("Select * From table2 Where name = 'test'");
function getResults(string $query)
{
$stmt = $this->dbAdapter->query($query);
return $stmt->execute();
}
I'm currently using symfony2, doctrine 2.3 and PostgreSQL 9. I've been searching for a couple of hours now to see HOW on earth do I do a ILIKE select with QueryBuilder.
It seems they only have LIKE. In my situation, though, I'm searching case-insensitive.
How on earth is it done?
// -- this is the "like";
$search = 'user';
$query = $this->createQueryBuilder('users');
$query->where($query->expr()->like('users.username', $query->expr()->literal('%:username%')))->setParameter(':username', $search);
// -- this is where I get "[Syntax Error] line 0, col 86: Error: Expected =, <, <=, <>, >, >=, !=, got 'ILIKE'
$search = 'user';
$query = $this->createQueryBuilder('users');
$query->where('users.username ILIKE :username')->setParameter(':username', $search);
I don't know about Symfony, but you can substitute
a ILIKE b
with
lower(a) LIKE lower(b)
You could also try the operator ~~*, which is a synonym for ILIKE
It has slightly lower operator precedence, so you might need parenthesis for concatenated strings where you wouldn't with ILIKE
a ILIKE b || c
becomes
a ~~* (b || c)
The manual about pattern matching, starting with LIKE / ILIKE.
I think this guy had the same problem and got an answer:
http://forum.symfony-project.org/viewtopic.php?f=23&t=40424
Obviously, you can extend Symfony2 with SQL vendor specific functions:
http://docs.doctrine-project.org/projects/doctrine-orm/en/2.1/cookbook/dql-user-defined-functions.html
I am not a fan of ORMs and frameworks butchering the rich functionality of Postgres just to stay "portable" (which hardly ever works).
This works for me (Symfony2 + Doctrine 2)
$qq = 'SELECT x FROM MyBundle:X x WHERE LOWER(x.y) LIKE :y';
$q = $em->createQuery($qq)->setParameter(':y', strtolower('%' . $filter . '%'));
$result = $q->getResult();
Unfortunately, we still do not have the ability to create custom comparison operators...
But we can create a custom function in which we implement the comparison.
Our DQL query well look like this:
SELECT q FROM App\Entity\Customer q WHERE ILIKE(q.name, :name) = true
The class describing the ILIKE function will look like this:
class ILike extends FunctionNode
{
/** #var Node */
protected $field;
/** #var Node */
protected $query;
/**
* #param Parser $parser
*
* #throws \Doctrine\ORM\Query\QueryException
*/
public function parse(Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->field = $parser->StringExpression();
$parser->match(Lexer::T_COMMA);
$this->query = $parser->StringExpression();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
/**
* #param SqlWalker $sqlWalker
*
* #return string
* #throws \Doctrine\ORM\Query\AST\ASTException
*/
public function getSql(SqlWalker $sqlWalker)
{
return '(' . $this->field->dispatch($sqlWalker) . ' ILIKE ' . $this->query->dispatch($sqlWalker) . ')';
}
}
The resulting SQL will look like this:
SELECT c0_.id AS id_0,
c0_.name AS name_1,
FROM customer c0_
WHERE (c0_.name ILIKE 'paramvalue') = true
From what I am aware, search queries in Symfony2 (at least when using Doctrine) are case in-sensitive. As noted in the Doctrine QL docs:
DQL is case in-sensitive, except for namespace, class and field names, which are case sensitive.
I want to use joins in zend. Below is my query
$select = $this->_db->select()
->from(array('evaluationcriteria' => 'procurement_tbltenderevaluationcriteria'),
array('ScoringCriteriaID','ScoringCriteriaWeight'))
->join(array('scoringcriteria' => 'procurement_tbltenderscoringcriteria'),
'scoringcriteria. TenderId=evaluationcriteria.TenderId')
->join(array('tenderapplications' => 'procurement_tbltenderapplications','tendersupplier' => 'tblsupplier'),
'tenderapplications. TenderInvitationContractorID=tendersupplier.UserID');
I have UserID in tendersupplier table. but its giving following error :-
Column not found: 1054 Unknown column 'tendersupplier.UserID' in 'on clause
I think its not the right way to include more than one tale in same array of a join.
Try code like this..
->from(array('evaluationcriteria' => 'procurement_tbltenderevaluationcriteria'),
array('ScoringCriteriaID','ScoringCriteriaWeight'))
->join(array('scoringcriteria' => 'procurement_tbltenderscoringcriteria'),
'scoringcriteria. TenderId=evaluationcriteria.TenderId')
'scoringcriteria. TenderId=evaluationcriteria.TenderId')
->join(array('tenderapplications' => 'procurement_tbltenderapplications'),
'tenderapplications.TenderInvitationContractorID=tblsupplier.UserID');
I am not sure whether you are planning to join values from tblsupplier table also.
The where condition is not written the way you did .
I dount that tblsupplier is a table then it should be in an array
This code is not tested!
$select = $this->_db->select()
->from(array('evaluationcriteria' => 'procurement_tbltenderevaluationcriteria'),
array('ScoringCriteriaID','ScoringCriteriaWeight'))
->join(array('scoringcriteria' => 'procurement_tbltenderscoringcriteria'),
'scoringcriteria. TenderId=evaluationcriteria.TenderId')
->join(array('tenderapplications' => 'procurement_tbltenderapplications'), array('tendersupplier' => 'tblsupplier'))
->where('tenderapplications. TenderInvitationContractorID=tendersupplier.UserID');
Looks like you are trying to join 2 tables in one ->join, I don't think you can do that.
join code from Zend_Db_Select()
/**
* Adds a JOIN table and columns to the query.
*
* The $name and $cols parameters follow the same logic
* as described in the from() method.
*
* #param array|string|Zend_Db_Expr $name The table name.
* #param string $cond Join on this condition.
* #param array|string $cols The columns to select from the joined table.
* #param string $schema The database name to specify, if any.
* #return Zend_Db_Select This Zend_Db_Select object.
*/
public function join($name, $cond, $cols = self::SQL_WILDCARD, $schema = null)
{
return $this->joinInner($name, $cond, $cols, $schema);
}
Here is the comment block from from()
/**
* Adds a FROM table and optional columns to the query.
*
* The first parameter $name can be a simple string, in which case the
* correlation name is generated automatically. If you want to specify
* the correlation name, the first parameter must be an associative
* array in which the key is the correlation name, and the value is
* the physical table name. For example, array('alias' => 'table').
* The correlation name is prepended to all columns fetched for this
* table.
*
* The second parameter can be a single string or Zend_Db_Expr object,
* or else an array of strings or Zend_Db_Expr objects.
*
* The first parameter can be null or an empty string, in which case
* no correlation name is generated or prepended to the columns named
* in the second parameter.
*
* #param array|string|Zend_Db_Expr $name The table name or an associative array
* relating correlation name to table name.
* #param array|string|Zend_Db_Expr $cols The columns to select from this table.
* #param string $schema The schema name to specify, if any.
* #return Zend_Db_Select This Zend_Db_Select object.
*/
Maybe try something like this instead:
$select = $this->_db->select()
//FROM table procurement_tbltenderevaluationcriteria AS evaluationcriteria, SELECT FROM
//COLUMNS ScoringCriteriaID and ScoringCriteriaWeight
->from(array('evaluationcriteria' => 'procurement_tbltenderevaluationcriteria'),
array('ScoringCriteriaID','ScoringCriteriaWeight'))
//JOIN TABLE procurement_tbltenderscoringcriteria AS scoringcriteria WHERE
//TenderId FROM TABLE scoringcriteria == TenderId FROM TABLE evaluationcriteria
->join(array('scoringcriteria' => 'procurement_tbltenderscoringcriteria'),
'scoringcriteria.TenderId=evaluationcriteria.TenderId')
//JOIN TABLE procurement_tbltenderapplications AS tenderapplications
->join(array('tenderapplications' => 'procurement_tbltenderapplications'))
//JOIN TABLE tblsupplier AS tendersupplier WHERE TenderInvitationContractorID FROM TABLE
// tenderapplications == UserID FROM TABLE tendersupplier
->join(array('tendersupplier' => 'tblsupplier'),
'tenderapplications.TenderInvitationContractorID=tendersupplier.UserID');
you may also need to alter your select() definition to allow joins:
//this will lock the tables to prevent data corruption
$this->_db->select(Zend_Db_Table::SELECT_WITHOUT_FROM_PART)->setIntegrityCheck(FALSE);
I hope I'm reading your intent correctly, this should get you closer if not all the way there. (one hint, use shorter aliases...)
I'm confused as to why Zend_DB doesn't accept an array of WHERE clauses - or am I incorrect? I have made the following work around:
$all = new ORM_Model_DbTable_Asset();
$wheres = array('id > 0', 'enabled' => 1);
$all = $all->fetchAll(implode(' AND ', $wheres))->toArray();
for what I hoped would be:
$all = new ORM_Model_DbTable_Asset();
$wheres = array('id > 0', 'enabled' => 1);
$all = $all->fetchAll($wheres)->toArray();
Slightly disappointing, am I missing something?
From Zend_Db_Table_Abstract
/**
* Fetches all rows.
*
* Honors the Zend_Db_Adapter fetch mode.
*
* #param string|array|Zend_Db_Table_Select $where OPTIONAL An SQL WHERE clause or Zend_Db_Table_Select object.
* #param string|array $order OPTIONAL An SQL ORDER clause.
* #param int $count OPTIONAL An SQL LIMIT count.
* #param int $offset OPTIONAL An SQL LIMIT offset.
* #return Zend_Db_Table_Rowset_Abstract The row results per the Zend_Db_Adapter fetch mode.
*/
public function fetchAll($where = null, $order = null, $count = null, $offset = null)
So you are incorrect, fetchAll() does accept an array of where clauses.
Your array should look like this (based on the definition in Zend_Db_Select)
$where = array(
'id > 0',
'enabled = ?' => 1
);
First we will look at your original code:
$wheres = array('id > 0', 'enabled' => 1);
Remember that => is an assignment operator. In your array above you start out with string automatically assigned to key 0. The next element is the number 1 assigned to the key 'enabled'. The solution proposed in answer 1 assigns the number 1 to key 'enabled = ?'.
Try this:
$all = new ORM_Model_DbTable_Asset();
$where = array();
$where[] = 'id > 0';
$where[] = $all->quote_into('enabled >= ?', 1, 'INTEGER'); // 1 could be a variable
$result = $all->fetchAll($where);