I want to build (for example) the following sql query where the position field of the matched data rows should be incremented by one:
UPDATE images SET position = position + 1 WHERE (position > 2 AND position <= 4)
I've tried to build the query with CakePHP 3's query builder:
$query->update()
->set(['position' => 'position + 1'])
->where(['position >' => 2])
->andWhere(['position <=' => 4])
->execute();
Due to the fact that position is an integer, CakePHP converts the expression 'position + 1' to 0 and don't pass 'position + 1' to the sql query.
Is there a way to build this query with the CakePHP query builder or must I use a raw sql statement for this?
the correct way to do it should be
$expression = new QueryExpression('position = position + 1');
$query->update()
->set([$expression])
->where(['position >' => 2])
->andWhere(['position <=' => 4])
->execute();
but I guess you could simply do
set(['position = position + 1']);
see the manual
Related
What's the most terse way I can express an UPDATE...SET...FROM SQL statement using knex? This is what I've got currently:
const query =
knex('user_subscriptions').update(subscription).toQuery() +
knex.raw(
' from plans p where customer_id = ? and p.id = us.plan_id ' +
'returning us.*, p.name',
[customer_id]
);
The reason I'm doing this is that I want to efficiently return a field from a related table (JOIN style) without needing a separate query.
As instructed in the official site: knexjs.org/#Builder-update
knex('user_subscriptions')
.returning(['us.*', 'plans.name', 'customer_id'])
.where({
customer_id: '?',
plans.id: us.plan_id
})
.update({
subscription : '?
})
Does:
update `user_subscriptions` set `subscription ` = '?' where `customer_id` = '?' and 'plans.id' = 'us.plan_id'
Returns:
[ us.*: ..., plans.name: ..., customer_id: ... ]
I'm working with a legacy Oracle database that has a column on a table which stores boolean values as 'Y' or 'N' characters.
I have mapped/converted this column out like so:
MappingSchema.Default.SetConverter<char, bool>(ConvertToBoolean);
MappingSchema.Default.SetConverter<bool, char>(ConvertToChar);
ConvertToBoolean & ConvertToChar are simply functions that map between the types.
Here's the field:
private char hasDog;
[Column("HAS_DOG")]
public bool HasDog
{
get => ConvertToBoolean(hasDog);
set => hasDog = ConvertToChar(value);
}
This has worked well for simply retrieving data, however, it seems the translation of the following:
var humanQuery = (from human in database.Humans
join vetVisit in database.VetVisits on human.Identifier equals vetVisit.Identifier
select new HumanModel(
human.Identifier
human.Name,
human.HasDog,
vetVisit.Date,
vetVisit.Year,
vetVisit.PaymentDue
));
// humanQuery is filtered by year here
var query = from vetVisits in database.VetVisits
select new VetPaymentModel(
(humanQuery).First().Year,
(humanQuery).Where(q => q.HasDog).Sum(q => q.PaymentDue), -- These 2 lines aren't correctly translated to Y/N
(humanQuery).Where(q => !q.HasDog).Sum(q => q.PaymentDue)
);
As pointed out above, the .Where clause here doesn't translate the boolean comparison of HasDog being true/false to the relevant Y/N values, but instead a 0/1 and results in the error
ORA-01722: invalid number
Is there any way to handle this case? I'd like the generated SQL to check that HAS_DOG = 'Y' for instance with the specified Where clause :)
Notes
I'm not using EntityFramework here, the application module that this query exists in doesn't use EF/EFCore
You can define new mapping schema for your particular DataConnection:
var ms = new MappingSchema();
builder = ms.GetFluentMappingBuilder();
builder.Entity<Human>()
.Property(e => e.HasDog)
.HasConversion(v => v ? 'Y' : 'N', p => p == 'Y');
Create this schema ONCE and use when creating DataConnection
Iam trying to update 'sortOrder' column based on a given list of ids.
For example, if the given IDs are:
$orderList = ['id' =>'1','id' =>'5','id' =>'3']
ID of '1' => 'sortOrder column' = 1
ID of '5' => 'sortOrder column' = 2
ID of '3' => 'sortOrder column' = 3
Query statement:
$ids_array = array_pluck($orderList, 'id');
$ids_string = implode(',', $ids_array);
DB::statement(DB::raw('set #rownum=0'));
$result = DB::table('requirements')
->join('sections', 'sections.id', '=', 'requirements.section_id')
->whereIn('id', $ids_array)
->orderByRaw("FIELD(requirements.id, {$ids_string})")
->update([
'requirements.sortOrder' => DB::raw('#rownum := #rownum + 1'),
]);
But when I try to update using this query, I am getting an error:
SQLSTATE[HY000]: General error: 1221 Incorrect usage of UPDATE and ORDER BY
Hello This is my first post here
I'm facing some issue with EF , I have tried the following code in VS 2010 with EF 5 and 6.
I have table called MYTABLE and field ReveivedTime which varchar(255) but this has Datetime values like "4/29/2014 12:00:00 AM".
Note : I can not change the DataType and I can not write SP to Convert , I do have limitations, So I do have option to work with LAMBDA
I have tired the following code in LINQPad 4 itis working fine but the same is not working in VS2010 with EF 5/6.
getting error
LINQ to Entities does not recognize the method 'System.DateTime ToDateTime(System.String)' method, and this method cannot be translated into a store expression.
Convert.ToDateTime(si.ReceivedTime) is causing the problem
MYTable
.Where (
si =>
((Convert.ToDateTime(si.ReceivedTime) >= DateTime.Now.AddDays(-10)) &&
(Convert.ToDateTime (si.ReceivedTime) <= DateTime.Now)
)
)
.GroupBy (g => new
{
Day = Convert.ToDateTime(g.ReceivedTime).Day,
Month = Convert.ToDateTime(g.ReceivedTime).Month,
Year = Convert.ToDateTime(g.ReceivedTime).Year,
City = g.City,
})
.Select (
g =>
new
{
Count = g.Count(),
g.Key.Day,
g.Key.Month,
g.Key.Year,
g.Key.City,
Date = Convert.ToDateTime(g.Key.Year + "/" + g.Key.Month + "/" + g.Key.Day),
}
)
.OrderBy(x => x.Count)
Really appreciate your solution and advanced thanks too.
Instead of Convert.ToDateTime (si.ReceivedTime) <= DateTime.Now try SqlFunctions.DateDiff("s", si.ReceivedTime, DateTime.Now) > 0
Here's some ZF1 code for an update query:
$this->getAdapter()->update(
'users', $data, $this->getAdapter()->quoteInto('node_id = ?', $user->nodeId)
);
Here's the same query with ZF2:
$param = $this->getAdapter()->platform->quoteValue($user->nodeId);
$sqlOj = new Sql($this->getAdapter());
$update = $sqlOj->update('users')->set($data)->where('node_id = ' . $param);
$updateString = $sqlOj->getSqlStringForSqlObject($update);
$this->getAdapter()->query($updateString, Adapter::QUERY_MODE_EXECUTE);
As you can see, one line of ZF1 code has become 5 lines of ZF2 code, (actually without the fluent interface it would be 7 lines...)
Am I missing something? Or is ZF2's DB component just more verbose that ZF1?
BTW, I have found the same scenario with select and insert queries too...
I managed to limit it to 3 lines.
use \Zend\Db\Sql\Sql;
$sql = new Sql ($adapter);
$update = $sql->update ('users')->set ($data)->where (['id = ?' => 1]);
$adapter->query ($sql->getSqlStringForSqlObject ($update), $db::QUERY_MODE_EXECUTE);
The problem is they didn't expect you to run your updates like that. Instead, you are expected to use a table gateway.
This way it becomes one line again:
$this->tableGateway->update($data, array('id' => $id));