Laravel eloquent possible bug? - laravel

I want to join two tables and filter on a field in the joined table. I don't think the actual tables matter in this question, but it's a table with dates joined with a table with the event info, so there are more dates possible for 1 event.
I made this eloquent line:
Event_date::whereRaw('startdate >= curdate() OR enddate >= curdate()')->whereHas('Event', function($q){$q->where("approved",true );})->orderBy('startdate', 'asc')->orderBy('enddate', 'asc')->toSql());
the filter doesn't work though. So thats why i added the ->toSql() to the line.
I get the following back:
select * from `event_dates` where startdate >= curdate() OR enddate >= curdate() and exists (select * from `events` where `event_dates`.`event_id` = `events`.`id` and `approved` = ?) order by `startdate` asc, `enddate` asc
You see that the 'where("approved",true )' results in 'where ..... and and approved = ?)' Where does the questionmark come from??? I tried diferent things, like '1', 1, 'True', True, true, 'true'...everything comes back as a questionmark.
Any suggestions??
Thanks!
Erwin

This is expected behaviour. Laravel uses prepared statements. To get parameters that are put into placeholders, you can use
$query->getBindings();
so for example in your case you can use:
$query = Event_date::whereRaw('startdate >= curdate() OR enddate >= curdate()')->whereHas('Event', function($q){$q->where("approved",true );})->orderBy('startdate', 'asc')->orderBy('enddate', 'asc'));
and now
echo $query->toSql();
var_dump($query->getBindings());
to get both query with placeholders and values that will be put in place of placeholders.

Related

Implementing the GROUP BY oracle query causing: not a GROUP BY expression in Ruby

My RUBY code executes a oracle query in the following way, but I seem to be getting the error:
Java::JavaSql::SQLSyntaxErrorException: ORA-00979: not a GROUP BY expression
SELECT
"REQUESTS".*
FROM
"REQUESTS"
WHERE
(
customer_id = 1
AND request_method != 'OPTIONS'
AND request_time BETWEEN TO_TIMESTAMP('2021-10-29 00:00:00', 'YYYY-MM-DD HH24:MI:SS')
AND TO_TIMESTAMP(
'2021-11-05 23:59:59.000999',
'YYYY-MM-DD HH24:MI:SS.FF'
)
)
GROUP BY
"REQUESTS"."REQUEST_TIME"
Initially the code which is translated into the above mentioned select query is:
requests = Request.where("customer_id = ? AND request_method != ? AND request_time BETWEEN TO_TIMESTAMP(?,'YYYY-MM-DD HH24:MI:SS') AND TO_TIMESTAMP(?,'YYYY-MM-DD HH24:MI:SS.FF')", customer.id, 'OPTIONS', start_time, end_time).group('date(request_time'))
The
.group('date(request_time') is translated in oracle to: GROUP BY date(request_time)
but it didn't seem to work either which was the original query, and the reason is because Oracle doesn't have this functionality , so I changed it and have been trying in differnt ways but can't seem to figure out why the group by expression wont work.
select * means "select all columns".
Group by clause says group by request_time, which is only one column, and that just won't work.
You'll have to apply group by to ALL columns (specified one-by-one), or - simpler - use select distinct.
Basically, we use group by when there's an aggregation in select column list. If there's none, you don't group by.
What you'll really do depends on what you want to do, i.e. which result you expect.

Need guidance on how to build a Laravel database query

In Laravel 6.18 I'm trying to figure out how to recreate the following Postgres query.
with data as (
select date_trunc('month', purchase_date) as x_month, date_trunc('year', purchase_date) AS x_year,
sum (retail_value) AS "retail_value_sum"
from coins
where user_email = 'user#email.com' and sold = 0
group by x_month, x_year
order by x_month asc, x_year asc
)
select x_month, x_year, sum (retail_value_sum) over (order by x_month asc, x_year asc rows between unbounded preceding and current row)
from data
I know how to build the main part of the query
$value_of_all_purchases_not_sold = DB::table('coins')
->select(DB::raw('date_trunc(\'month\', purchase_date) AS x_month, date_trunc(\'year\', purchase_date) AS x_year, sum(retail_value) as purchase_price_sum'))
->where('user_email', '=', auth()->user()->email)
->where('sold', '=', 0)
->groupBy('x_month', 'x_year')
->orderBy('x_month', 'asc')
->orderBy('x_year', 'asc')
->get();
but how do you build out the with data as ( and the second select?
I need the data to be cumulative and I'd rather do the calculation in the DB than in PHP.
Laravel doesn't have built-in method(s) for common table expression. You may use a third party package such as this - it has a very good documentation. If you don't want to use an external library, then you need use query builder's select method with bindings such as
$results = DB::select('your-query', ['your', 'bindings']);
return Coin::hydrate($results); // if you want them as collection of Coin instance.

Subquery returning multiple rows during update

I have two tables T_SUBJECTS (subject_id, date_of_birth) and T_ADMISSIONS (visit_id, subject_id, date_of_admission, age). I want to update the age column with the age at time of admission. I wrote the update query and get the "single row sub-query returns more than one row". I understand the error but thought the where exists clause will solve the problem. Below is the query.
UPDATE
t_admissions
SET
t_admissions.age =
(
SELECT
TRUNC(months_between(t_admissions.date_of_admission,
t_subjects.date_of_birth)/12)
FROM
t_admissions,
t_subjects
WHERE
t_admissions.subject_id = t_subjects.subject_id
AND t_admissions.age = 0
AND t_admissions.date_of_admission IS NOT NULL
AND t_subjects.date_of_birth IS NOT NULL
)
WHERE
EXISTS
(
SELECT
1
FROM
t_admissions, t_subjects
WHERE
t_admissions.subject_id = t_subjects.subject_id
);
The problem is that your subquery in the SET clause returns multiple rows.
Having a WHERE clause will only filter which records get updated and nothing else.
In addition, your where clause will either always return true or always return false.
You should look into how to properly do a correlated update:
https://stackoverflow.com/a/7031405/477563
A correlated update is what I need as suggested in the above link. See answer below.
UPDATE
(
SELECT
t_admissions.visit_id,
t_admissions.date_of_admission doa,
t_admissions.age age,
t_subjects.date_of_birth dob
FROM
t_admissions,
t_subjects
WHERE
t_admissions.subject_id = t_subjects.subject_id
AND t_admissions.age = 0
AND t_admissions.date_of_admission IS NOT NULL
AND t_subjects.date_of_birth IS NOT NULL
)
SET
age = TRUNC(months_between(doa,dob)/12);

Subqueries in Doctrine 1.2 DQL as FROM

Ok so the big deal is to get the rows in a mysql table that have another related row in the same table given some conditions. This table is like an activity log, so i want to notify someone that "some guy" leaved his group, but i only want do the notification when that guy joined the group before a given date, so what i do is the next sql:
SELECT ua.*, ua2.*
FROM user_activities AS ua
INNER JOIN (SELECT ua2.* FROM user_activities AS ua2
WHERE ua2.activity = "join-group"
ORDER BY ua2.created_at)
AS ua2 ON ua2.group_name = ua.group_name AND ua2.user_id = ua.user_id
WHERE ua.activity = "unjoin-group";
I omitted the date conditions due to clarity reasons.
So i need to know how to convert this to DQL (for doctrine 1.2), is it possible? or I better do it programatically?
What im trying now is this:
$q = Doctrine_Query::create()
->from('UserActivity ua, ua.User u ')
->where('ua.created_at > ?', $min_date)
->andWhere('ua.activity = ?', "unjoin-group")
->andWhereIn('u.status', array(STATUS_HOT, STATUS_ACTIVE))
->andWhere('ua.user_id IN ( SELECT
uaa.id
FROM
UserActivity uaa
WHERE
uaa.activity = ? AND
uaa.created_at < ? AND
uaa.created_at > ? AND
uaa.group_name = ua.group_name
LIMIT 1',
array("join-group", $min_date, $max_date));
But i get this error:
fatal error maximum function nesting level of '100' reached aborting
So i can't keep foward

rails postgreSQL cannot get this query to work (SUM, Group Order)

This query work when I try it in SQLite:
Transaction.where(:paid => true).select("created_at, SUM(amount) amount").group("DATE(created_at)").order('created_at')
But when I run it with postgreSQL it doesn'y work.
Heres the error message:
ActiveRecord::StatementInvalid: PGError: ERROR: column "transactions.created_at" must appear in the GROUP BY clause or be used in an aggregate function : SELECT created_at, SUM(amount) as amount FROM "transactions" WHERE ("transactions"."paid" = 't') GROUP BY DATE(created_at) ORDER BY created_at
Anyone who can help me?
Thanks in advance
You have to either use DATE(created_at) in the select clause, or use created_at in the group by clause.
You're selecting created_at, sum(amount), ordering by created_at, but are grouping by date(created_at). The latter will disallow the use of anything but the grouped by fields and aggregates except in the join/where clause.
To fix, either group by created_at, or select and order by date(created_at) instead of created_at.

Resources