Laravel 'join on' where two values are within 'x' of each other - laravel-5

I have a MySQL query where I join on two values when they are +/- '3' of each other:
...
inner join
on ABS(i.direction - i2.MWD) < 3
and ABS(i.direction - i2.MWD) < 3
(I'm not entirely sure why the 'and' statement is exactly the same, but that's what made it work)
I've tried converting this to Eloquent using both
$join->on('i.direction', '-', 'i2.MWD', '<' 3)
and
$join->on('i.direction', '=', 'i2.MWD')
->where('i.direction', '-', 'i2.MWD', '<' 3)
The above two examples give me an empty result. If I change the '<' to '>' in either example, I get all the joined data from both tables.
I've also tried using DB::raw as a workaround:
$join->on(DB::raw('ABS(input.direction - i2.MWD) < 3
and ABS(input.direction - i2.MWD) < 3'));
which gives me the below error:
SQLSTATE[42S22]: Column not found: 1054 Unknown column '' in 'on clause'
(SQL: select count(*) as aggregate
from (select * from `input`
inner join
(select MWD, SWH, SWP, BUOY,Time from stations order by Time desc limit 4)
as i2 on ABS(input.direction - i2.MWD) < 3
and ABS(input.direction - i2.MWD) < 3 = ``) count_row_table)
(the trailing = '' which is being inserted after the 'i2.MWD) < 3' is confusing me).
I'd be very grateful if someone could help me come up with a solution for joining on the two values i.direction & i2.MWD (plus or minus 3) using Eloquent.

What you was trying to do here:
->where('i.direction', '-', 'i2.MWD', '<' 3)
you have to change for a raw where like this:
->whereRaw('i.direction - i2.MWD < ?', [3])
This should helps.

Related

Laravel Eloquent: how to use “where” with WithCount to select Models whose count is larger than a number

Suppose I have two tables: posts and tags. I want to eager load all the tags with posts whose post count is larger than 10. How would I do it?
I tried the following but not work:
Tag::withCount('posts')
->where('posts_count', '>' , 10)
->get();
It gives me the following error:
Column not found: 1054 Unknown column 'posts_count' in 'where clause' (SQL: select `tags`.*, (select count(*) from `posts` inner join `post_tag` on `posts`.`id` = `post_tag`.`post_id` where `tags`.`id` = `post_tag`.`tag_id`) as `posts_count` from `tags` where `posts_count` > 1 order by `posts_count` desc)
try this:
Tag::withCount('posts')->having('posts_count', '>' , 10)->get();
If you want to filter on aggregates, you need to use having.

Laravel query using group by and where does not work

This is a query that I have in raw sql.
DB::select('SELECT bldgs.name as building , floors.name as floor, areas.name as area, locations.area_id ,count(reqs.location_id) as occupied FROM `reqs` '
. 'JOIN locations ON locations.id = location_id '
. 'JOIN areas ON areas.id = area_id '
. 'JOIN floors ON floors.id = areas.floor_id'
. ' JOIN bldgs ON bldgs.id = bldg_id '
. 'WHERE `status`=2 and (DATE_FORMAT(start_date,"%Y-%m")<= "'.$dateFrom.'" AND DATE_FORMAT(end_date,"%Y-%m")>="'.$dateTo.'") group by locations.area_id, areas.name, floors.name, bldgs.name' );
And this is one of many attempts to make it work in Laravel elequent instead of raw.
Req::select('bldgs.name as building',DB::raw('count(location_id) as count_occupied'))
->join('locations','locations.id','=','location_id')
->join('areas','areas.id','=','locations.area_id')
->join('floors','floors.id','=','areas.floor_id')
->join('bldgs as bl','bl.id','=','floors.bldg_id')
->where('reqs.status','=', '2')
->where('start_date','<=', $date)
->where('end_date','>=', $date)
->groupBy('bldgs.name')
I need to understand why the second way gives mysql error and refuses to run the query above. Is is a mistake in my code or is this normally not possible in using eloguent to group by like this except in raw mysql string?
This is the error I get.
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'bldgs.name' in 'field list' (SQL: select `bldgs`.`name` as `building`, count(location_id) as count_occupied from `reqs` inner join `locations` on `locations`.`id` = `location_id` inner join `areas` on `areas`.`id` = `locations`.`area_id` inner join `floors` on `floors`.`id` = `areas`.`floor_id` inner join `bldgs` as `bl` on `bl`.`id` = `floors`.`bldg_id` where `reqs`.`status` = 2 and `start_date` <= 2018-10 and `end_date` >= 2018-10 group by `bldgs`.`name`)
As the error states, you don't have a bldgs.name column. You named the bldgs table bl when you joined it.
Rename your references from bldgs.name to bl.name.

Laravel eloquent possible bug?

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.

Convert Oracle (Cross Join?) to Netezza when using comma separated table list instead of JOIN keywords

Below is is some Oracle PL/SQL code to join tables without using actual JOIN keywords. This looks like a cross join? How would I convert to Netezza SQL code? That's where I'm stuck.
SELECT COUNT(*)
FROM TABLE_A A, TABLE_A B
WHERE A.X = 'Y' AND A.PATH LIKE '/A/A/A'
AND B.X = 'Z' AND B.PATH LIKE '/B/B/B';
Oracle Cross Join:
http://www.sqlguides.com/sql_cross_join.php
Here's what I tried so far:
SELECT *
from TABLE_A A
cross join (
select * from TABLE_A
) B
WHERE
A.X = 'Y' AND A.PATH LIKE '/A/A/A'
AND B.X = 'Z' AND B.PATH LIKE '/B/B/B';
EDIT:
a_horse_with_no_name:
When I use either syntax in Netezza for the COUNT(*) in the very beginning, it works and returns a count of 60, which matches the first query above when running in Oracle. Without the WHERE clause in Netezza returns 125316 results, which matches the first query above when running in Oracle. When I use either syntax in Netezza for the SELECT * in the very beginning, I get error
ERROR [HY000] ERROR: Record size 70418 exceeds internal limit of 65535 bytes'
Had to use explicit columns in Netezza when doing a CROSS JOIN. Using SELECT * throws the error as indicated in my question EDIT. Also had to escape the '%' character by escaping nothing. Thank you a_horse_with_no_name. Cheers! "Where everybody knows your name." ;-)
select A.CODE, B.CODE, LOWER(A.DIM), LOWER(B.DIM)
FROM TABLE_A A
cross join TABLE_A B
WHERE A.PATH LIKE '\A\A\A%' ESCAPE '' AND A.X = 'Y'
AND B.PATH LIKE '\B\B\B%' ESCAPE '' AND B.X = 'Y'

How to match column data to another column in a different table

I have a table called txn_detail which has the primary key txn_id and an Advance Queue table called hlr_pre_qt that has the Primary Key of txn_detail inside a column called user_data with several other values separated by commas. I need to filter them out and make a mapping between the two tables using these two columns (txn_detail.txn_id and hlr_pre_qt.user_data). How can i do this?
You can use like to do the join
i.e.
SELECT *
FROM txn_detail A
JOIN hlr_pre_qt B on B.user_data.txn_id = A.txn_id
OR
SELECT *
FROM txn_detail A
JOIN hlr_pre_qt B on b.USER_DATA LIKE '%' || TO_CHAR(A.txn_id) || '%'
OR
You can strip the TXN_ID from user_data....
SELECT *
FROM txn_detail A
JOIN hlr_pre_qt B on
SUBSTR(b.USER_DATA, INSTR(b.USER_DATA, '(') +1, INSTR(b.USER_DATA, ',') - INSTR(b.USER_DATA, '(') - 1) = TO_CHAR(A.txn_id)
In both cases, no index will be used to do the join, so performance will be poor.
Hope that helps

Resources