using raw query in where methods makes error in query generation - laravel-5

I have an eloquent query as
Role::where("(company_id = Auth::user()->company_id or name = 'admin')and id in(2,3)")->pluck('name');
According to my eloquent the sql should be as
select `name` from `roles` where ( company_id = 1 or name = admin ) and id IN (2, 3) and `roles`.`deleted_at` is null
But it executes as
select `name` from `roles` where ( company_id = 1 or name = admin ) and id IN (2, 3) is null and `roles`.`deleted_at` is null
Can anyone help me concluding why extra is null condition is applied in the query?
Note: I am using soft deletes

You should use whereRaw instead of where
Role::whereRaw("(company_id = Auth::user()->company_id or name = 'admin')and id in(2,3)")->pluck('name');

Related

Laravel Eloquent Query With OR WHERE Condition

I am using Laravel 6 & mysql 7
I have below query
$tasks = Task::where('deleted_at', null)->where('company_id',$company_id);
$tasks = $tasks->where('created_by',$user_id);
$tasks = $tasks->orWhereIn('id',$task_ids);
It generates below raw query when i print it
SELECT * FROM `tasks` WHERE `deleted_at` IS NULL AND `company_id` = 25 AND `created_by` = 20 OR
`id` IN(112,...215) ORDER BY `id` DESC
Now Id 112 is deleted but still showing in result, although i have where('deleted_at', null) condition but it is not working
I want to apply all other conditions on $task_ids as well
How this can be achieved with optimized query?
UPDATED: Here is complete scenario
I want to select all records which is created by me or assigned to me. Here is my complete code.
$tasks = Task::where('deleted_at', null)->where('company_id',$company_id);
$tasks = $tasks->where('created_by',$user_id);
$task_ids = TaskUser::where('user_id',$user_id)->pluck('task_id')->all();
$tasks = $tasks->orWhereIn('id',$task_ids);
This is because the AND operator has a higher precedence than OR, which basically means that AND "sticks" together more than OR does. You query basically is interpredeted like this:
SELECT * FROM `tasks`
WHERE
(`deleted_at` IS NULL AND `company_id` = 25 AND `created_by` = 20)
OR
( `id` IN(112,...215) )
I am not entirly sure wheter you actually want to OR anything. If you really want to apply all conditions, you just need to change the orWhereIn to a whereIn.
In case you want all not-deleted tasks, that EITHER belong to a company and a auser OR whose id is in the list, you would need to update your query like this:
$tasks = Task::where('deleted_at', null);
$tasks = $tasks->where(function($q) use ($user_id, $task_ids){
$q->where(function($q2) use ($user_id, $task_ids) {
$q2->where('created_by',$user_id)
->where('company_id',$company_id);
})
->orWhereIn('id',$task_ids);
});
which should result in this query:
SELECT * FROM `tasks`
WHERE `deleted_at` IS NULL AND (
( `company_id` = 25 AND `created_by` = 20 )
OR
`id` IN(112,...215)
)
There is actually a chapter about parameter grouping in the excellent laravel documentation as well.

How to make Multiple sub query in Laravel

I am new in Laravel.
Here below i mention my code how to make this in laravel query builder.
Using tables are ab,cd,ef,gh,ij
SELECT ab.* FROM ab
WHERE ab.id IN (
SELECT ab_id FROM cd
WHERE ef_id = 1 AND status = 1
AND deleted_at IS NULL
AND ab_id IN (
SELECT ab_id FROM gh
WHERE ij_id IN (
SELECT id FROM ij
WHERE ef_id = 1 AND deleted_at IS NULL
) AND deleted_at IS NULL
) AND ab_id IN (
SELECT id FROM ab
WHERE deleted_at IS NULL AND usertest != 1
)
)AND ab.deleted_at IS NULL
GROUP BY ab.id
ORDER BY ab.created_at DESC;
You can pass a closure to a where condition and query another table.
From the Laravel docs:
DB::table('users')
->whereExists(function ($query) {
$query->select(DB::raw(1))
->from('orders')
->whereRaw('orders.user_id = users.id');
})
->get();

Update unique values into Postgres Array

I have a situation where I update a Postgres table column which is of type bigint[]. This array should have unique numbers inside it whenever an update query is fired.
The query is as given below
UPDATE book_shelf
SET book_id = book_id || array[CAST(:bookID AS BIGINT)], updated_at = now()
WHERE user_id = :userID AND shelf_name = :shelfName
When the above query is fired, it simply adds the number into the array which I don't want to happen. It should hold only unique values. Please help me.
You can check if it exists in the array before adding it:
UPDATE book_shelf
SET book_id = CASE WHEN CAST(:bookID AS BIGINT) = ANY(book_id) THEN book_id ELSE ARRAY_APPEND(book_id, CAST(:bookID AS BIGINT)) END, updated_at = now()
WHERE user_id = :userID AND shelf_name = :shelfName
Of course if updated_at should only be set if book_id is actually updated, then put the check in the WHERE clause so it's not updated unnecessarily:
UPDATE book_shelf
SET book_id = ARRAY_APPEND(book_id, CAST(:bookID AS BIGINT)), updated_at = now()
WHERE user_id = :userID
AND shelf_name = :shelfName
AND NOT CAST(:bookID AS BIGINT) = ANY(book_id)

Want to get maximum records which have common rows in related table in Laravel

I have three tables in laravel, one is a middle table :
CREATE TABLE orders( id INT(10) PRIMARY KEY NOT NULL AUTO_INCREMENT, order_number VARCHAR(100) NOT NULL );
CREATE TABLE products( id INT(10) PRIMARY KEY NOT NULL AUTO_INCREMENT, title VARCHAR(100) NOT NULL );
CREATE TABLE orders_products ( order_id INT(10) NOT NULL, product_id INT(10) NOT NULL );
I want to retrive the top two orders which have common products, the higher number is irrelevant here,
What counts is that orderC which has 5 orders, 1,3,4,5,7 and orderF which have also 1,2,3,4,5,6,8 so they have 1,3,4,5 in common, this is what I want to have, even if others have one 2,7,9,12,13,15,17,23 and other 2,4,6,8,9,11,12,14,15,16,17 that is not what I want, but the ones have the most products in common
Many Thanks
This is giving inaccurate results:
$orders =
DB::table('orders')
->select('orders.id as ordid', 'orders.order_number as order_number',
DB::raw('COUNT(orders_products.product_id) as counter' ) )
->join('orders_products', 'orders.id', '=', 'orders_products.order_id')
->join('products as prod1', 'prod1.id', '=',
'orders_products.product_id')
->join('products as prod2', 'prod1.id', '=', 'prod2.id')
->groupBy( 'orders.order_number')
->orderByRaw('MAX(orders_products.product_id) DESC')
->limit(2)
->get();
To get the orders with the highest amount of products, you need to use HAVING clause and a subquery to get desired results.
The query below works like this:
First, a subquery (with a nested subquery) finds the highest amount of products in a single order - the highest_amount value
Then a wrapping query finds all orders, that have as many products in order as the highest amount from a subquery.
It would look something like this:
SELECT
orders.id as ordid,
orders.order_number as order_number,
COUNT(orders_products.product_id) as counter
FROM orders
JOIN orders_products ON orders.id = orders_products.order_id
JOIN products ON products.id = orders_products.product_id
GROUP BY orders.order_number
HAVING COUNT(orders_products.product_id) >= (
SELECT MAX(products_in_order) as highest_amount FROM (
SELECT COUNT(orders_products.product_id) as products_in_order
FROM orders
JOIN orders_products ON orders.id = orders_products.order_id
JOIN products ON products.id = orders_products.product_id
GROUP BY orders.order_number
) top_amounts
)
I tested it in this SQL fiddle - it works as expected (you get all orders with the most products - 3 in this case)

Problems updating query with inner join

Can anyone please assist in getting this one query to work. I am trying to update status of a column in a table having joined to other tables
Here is the query
update
(select I.account_id, I.sts, I.name_id, CI.CRM_TYPE, I.comments
from PPInters I
inner join DW.CUST CT
on I.account_id = CT.account_id
where
I.sts is null
AND I.comments IS NOT NULL
AND CT.CUSTTYPe = 'INTNL') T
SET T.STS = 'D'
WHERE T.account_id IN (2000208927,380166014,190180447,166078041,105029075 )
I am getting "ORA-01779: cannot modify a column which maps to a non key-preserved table" error
What I am trying to do here is to set I.STS = 'D' for some 700 records pulled up using this query
select I.account_id, I.sts, I.name_id, CI.CRM_TYPE, I.comments
from PPInters I
inner join DW.CUST CT
on I.account_id = CT.account_id
where
I.sts is null
AND I.comments IS NOT NULL
AND CT.CUSTTYPe = 'INTNL'
I appreciate it
Assumming that account_id is a primary key kolumn in table PPInters,
that is it's value uniquely identifies records in this table:
UPDATE PPInters
SET STS = 'D'
WHERE account_id IN (
select I.account_id
/*, I.sts, I.name_id, CI.CRM_TYPE, I.comments */
from PPInters I
inner join DW.CUST CT
on I.account_id = CT.account_id
where
I.sts is null
AND I.comments IS NOT NULL
AND CT.CUSTTYPe = 'INTNL'
)
AND account_id IN (2000208927,380166014,190180447,166078041,105029075 )

Resources