How to implement CASE WHEN under ORDER BY using CakePHP 3 - cakephp-3.0

The SQL:
SELECT Students.name AS `Students__name`, Students.role AS
`Students__role` FROM students Students
WHERE id IN
(1053,1056,733,734,735,736,737,739,748)
AND name LIKE '%v%' ORDER BY
CASE
WHEN name LIKE '%v' THEN 1
WHEN name LIKE 'v%' THEN 2
WHEN name LIKE '%v%' THEN 3
ELSE 4
END
So far:
$SInfo = TableRegistry::get('Students')->find()
->where(function($ex) use ($sArray, $sName) {
$ex->in('id', $sArray);
$ex->like('name', '%'.$sName.'%');
return $ex;
});
->select(['name', 'role']);
order() function does not take ExpressionQuery. I have tried using $ex->addCase() under order but that didn't work either.

If you want to use a CASE statement in the order() method, you can write it like this:
$SInfo = TableRegistry::get('Students')->find()
->select(['name', 'role'])
->where(function($ex) use ($sArray, $sName) {
$ex->in('id', $sArray);
$ex->like('name', '%' . $sName . '%');
return $ex;
})
->order('(CASE WHEN name LIKE \'%v\' then 1 when name LIKE \'v%\' then 2 when name LIKE \'%v%\' then 3 else 4 END)');
Edit: As suggested in the comment of this answer (thanks #ndm) you should use corresponding CASE expressions instead:
$SInfo = TableRegistry::get('Students')->find()
->select(['name', 'role'])
->where(function($ex) use ($sArray, $sName) {
$ex->in('id', $sArray);
$ex->like('name', '%' . $sName . '%');
return $ex;
})
->order(function ($exp, $q) {
return $exp->addCase(
[
$q->newExpr()->like('name', '%v'),
$q->newExpr()->like('name', 'v%'),
$q->newExpr()->like('name', '%v%'),
],
[1, 2, 3, 4], # values matching conditions
['integer', 'integer', 'integer', 'integer'] # type of each value
);
});

Related

Why laravel select and group by return same value

I try to select count and group with Laravel query, but they are return same value with different field.
This is my code:
$kategoris = ['NUK', 'Hubkel', 'Sta_kawin'];
foreach ($kategoris as $kategori) {
$raw[] = 'count('.$kategori.') as '.$kategori;
}
$implodeRaw = implode(', ', $raw);
$desas = DB::table('arts')
->select('arts.id', 'KDKEC', 'KDDESA', DB::raw($implodeRaw))
->where(['KDKEC' => $kodeKecamatan])
->groupBy('KDDESA')
->orderBy('KDDESA', 'ASC')
->get();
Result:
results: {
0 => {
'id': 10
'NUK': 6
'Hubkel': 6
'Sta_kawin': 6
}
1 => {
'id': 13
'NUK': 1
'Hubkel': 1
'Sta_kawin': 1
}
}
So, what's wrong with this code? I want the NUK, Hubkel, Sta_kawin return different value because the source data is different.

Feathers/sequelize - how to concat 2 query for same field in 1

Let's assume there are 2 query here in my hook function
context.params.query['id'] = { '$like': '%B%' }
context.params.query['id'] = [ 'ABC', 'CDF', 'SSS', 'BBD', 'DDD', 'ASF' ]
I want to concat these 2 query in into something like
context.params.query['id'] = XXXXXXX
so that it return all record with id 'ABC' and 'BBD'

Retrive all the value that satisfy the condition of first table

I have two tables users and location. I need to join both tables
what i need is get all the area number of all the users which are present in the user table.
ie user 1 has 3 entries in the second table so i need to join the table in such a way that is,
id1 = 1
area = 2,3
area 2 is repeating so do not include it twice
i tried the join but now getting the correct way to doing it.
What i tried?
$location = User::
join('addresses','users.id1','=','addresses.id1') ->select('users.id1','addresses.area')
->get();
Expected Output
User 1 -> area ->2,3
Here are the two ways to do this.
Firstly you can use Laravel relationship:-
In your model User create relationship:-
function addresses()
{
return $this->hasMany(Address::class, 'id1', 'id1');
}
Now in your User controller you can get User addresses (areas) like this
$users = User::with('addresses')->get();
dd($users->toArray());
This will print something like this
[
{
id1: 1,
name: abaa
pwd: 12345
addresses: [
{
id2: 1,
id1: 1,
area: 2
},
{
id2: 2,
id1: 1,
area: 3
},
{
id2: 3,
id1: 1,
area: 3
}
]
},
{
...
}
]
Second you can use Laravel relationship:-
$builder = new User;
$builder->join('addresses','users.id1','=','addresses.id1')
->selectRaw("users.*, GROUP_CONCAT(DISTINCT addresses.area SEPARATOR ',') as distinct_areas")
->groupBy("users.id1")
->get();
This query will give you result something like this
[
{
id1: 1,
name: abaa,
pwd: 12345,
distinct_areas: 2,3
},
{
...
}
]
I think this will help you.

Joining table data

I have a table of:
id title type expl bubble_content onfocus req dorder label mirror
1 Fullname 1 1 Your fullname Yes 0 0 0 NULL
Then another table of:
id fieldid relid dorder
4 1 2 0
5 1 1 0
How would I join the two tables so that the result would be something like:
0 => array(
'id' => 1,
'title' => 'Fullname',
.... etc ....
'relid' => 2,
'relid' => 1),
1 => array(
.... etc ....
))
I've tried using INNER JOIN / LEFT JOIN but this produces two rows/arrays for each relid, I would really like all the data for the particular fieldid to exist within the same array, as illustrated above.
You can't have 2 keys with the same name in an array. On your example you have 2 'relid', the second one will overwrite the first.
You can code PHP so that it merges those rows into one:
$output = array();
while ($row = mysql_fetch_assoc($result))
{
// Capture all values for this row first.
// If this is the new row from the first table, store.
if (!isset($output[$row['id']]))
{
$output[$row['id']] = $row;
// Make a new array for relids.
$output[$row['id']]['relids'] = array();
}
$output[$row['id']]['relids'][] = $row['relid'];
}
Your output array will look like this:
0 => array(
'id' => 1,
'title' => 'Fullname',
.... etc ....
'relids' => array(2, 1),
1 => array(
.... etc ....
))

PDO - Update And Set Query (2 arrays)

So I have two arrays that I need to update and set with in MySQL. item_id [1,2,3] and item_order[2,1,3]
Here is the items table before the array insert:
item_id item_order
1 1 //should become 2
2 2 // should become 1
3 3 // should become 3
The arrays should be in pairs for the insert, 1-2, 2-1, 3-3.
How can I do this with a prepared statement efficiently and how can I test if the array items are indeed numbers?
Assuming you have input like this:
$item_id = array(1, 2, 3);
$item_order = array(2, 1, 3);
// and a PDO connection named $pdo
You can try something like this. (I'm also assuming you have PDO configured to throw exceptions when problems arise).
function all_numbers($input) {
foreach($input as $o) {
if(!is_numeric($o)) {
return false;
}
}
return true;
}
if(count($item_id) != count($item_order)) {
throw new Exception("Input size mismatch!");
}
if(!all_numbers($item_id) || !all_numbers($item_order)) {
throw new Exception("Invalid input format!");
}
$pairs = array_combine($item_id, $item_order);
// now $pairs will be an array(1 => 2, 2 => 1, 3 => 3);
if($pdo->beginTransaction()) {
try {
$stmt = $pdo->prepare('UPDATE `items` SET `item_order` = :order WHERE `item_id` = :id');
foreach($pairs as $id => $order) {
$stmt->execute(array(
':id' => $id,
':order' => $order,
));
}
$pdo->commit();
} catch (Exception $E) {
$tx->rollback();
throw $E;
}
} else {
throw new Exception("PDO transaction failed: " . print_r($pdo->errorInfo(), true));
}
But it might be better to redesign your input - only pass the item_ids in the desired order and compute their item_order values automatically.
Here is an example:
UPDATE mytable
SET myfield = CASE other_field
WHEN 1 THEN 'value'
WHEN 2 THEN 'value'
WHEN 3 THEN 'value'
END
WHERE id IN (1,2,3)