How do I achieve this kind of query in Laravel?
Model::query()
->select('id')
->withCount(['relation_1', 'relation_2', 'relation_3'])
->selectRaw(
'(CASE
WHEN relation_1_count < 0 THEN "relation 1 failed"
WHEN relation_1_count > 0 and relation_2_count < 0 THEN "relation 2 failed"
WHEN relation_1_count > 0 and relation_2_count > 0 and relation_3_count < 0 THEN "relation 3 failed"
ELSE "All relations passed"
END) AS model_status')
->get()
This gives the relation_1_count column that does not exist.
What is the proper approach for this kind of problem?
Your count queries are aliased subqueries so you can't use the alias directly. In MySQL however you can use the alias in another subquery e.g.:
Model::query()
->select('id')
->withCount(['relation_1', 'relation_2', 'relation_3'])
->selectRaw("CASE WHEN (SELECT relation_1_count) < 0 THEN 'relation 1 failed'
WHEN (SELECT relation_1_count) > 0 AND (SELECT relation_2_count) < 0 THEN 'relation 2 failed'
WHEN (SELECT relation_1_count) > 0 AND (SELECT relation_2_count) > 0 AND (SELECT relation_3_count) < 0 THEN 'relation 3 failed'
ELSE 'All relations passed' END AS model_status")
->get()
though in my opinion this sort of logic to craft a presentational message is best handled by the PHP view logic.
Sidenote: I've not actually tried this particular one myself so let me know if it works.
Related
I can use orderBy method in Laravel like this:
$posts = Post::orderBy('id', 'DESC')->get();
Ok, what about when there is CASE in the ORDER BY clause? Like this:
ORDER BY
CASE
WHEN id.PinRequestCount <> 0 THEN 5
WHEN id.HighCallAlertCount <> 0 THEN 4
WHEN id.HighAlertCount <> 0 THEN 3
WHEN id.MediumCallAlertCount <> 0 THEN 2
WHEN id.MediumAlertCount <> 0 THEN 1
END desc,
How can I write this ^ in Laravel?
Try this:
->orderByRaw(
"CASE WHEN <CONDITION> THEN < > ELSE < > END DESC"
)
You are to use raw, as sagi has also mentioned.
$posts = Post::select(DB::raw
('CASE
WHEN id.PinRequestCount <> 0 THEN 5
WHEN id.HighCallAlertCount <> 0 THEN 4
WHEN id.HighAlertCount <> 0 THEN 3
WHEN id.MediumCallAlertCount <> 0 THEN 2
WHEN id.MediumAlertCount <> 0 THEN 1
END desc')
)->orderBy('id', 'DESC')->get();
How to find a value based on a range stored in the database.
My friend_levels table:
and on my profile table:
When I have friend_points = 1, I will get Normal Rate, then if I had friend_points = 180 I will get Great Friend, so it's basically like this on programming
if($profile_points >= 0 && $profile_points < 50) {
return 'Normal Rate';
} else if($profile_points >= 50 && $profile_points < 100) {
return 'Friend';
} else if($profile_points >= 100 && $profile_points < 150) {
return 'Good Friend';
}....
my question too is does it possible on QUERY? or I just make it on the PHP?
EDIT1: Is there a way to get the next target value?
For ex. If I'm on the Friend rate with 68 points how to get the 100 = Good Friend ? nevermind the substraction, I just want to get the next row.
If I understood you correctly, you can use CASE EXPRESSION like this:
SELECT id,user_id,
case when friend_points between 0 and 49 then 'Normal rate'
when friend_points between 50 and 99 then 'Friend'
when friend_points between 100 and 149 then 'Good friend'
.......
end as 'Friend_Status'
FROM profile
EDIT:
Or, if this names can change dynamicly then with a join:
SELECT t.id,t.user_id,s.name
FROM profile t
INNER JOIN friend_levels s ON(t.friend_points >= s.points_needed)
WHERE s.points_needed = (select min(f.points_needed)
from friend_levels f
where t.friend_points >= f.points_needed)
next smallest point
SELECT MAX (DISTINCT points_needed)
FROM friend_levels
WHERE points_needed < =$profile_points;
next highest point
SELECT MIN (DISTINCT points_needed)
FROM friend_levels
WHERE points_needed > $profile_points;
The CASE method proposed by Sagi works, but means that you need to update your code (SQL in this case rather than PHP) if you want to change your ranges.
Safin's method is only part of a solution - in order to find the corresponding description, Safin's query needs to be embedded in a select with joins/subselects as per Sagi's update, but this is somewhat inefficient.
Personally I wouldn't use aggregation for this:
SELECT user_id,
(SELECT fl.name
FROM friends_level fl
WHERE fl.points_needed<profiles.friend_points
ORDER BY fl.point_needed DESC
LIMIT 0,1) as level
FROM profiles
i have 2 tables users_teams and events_users
users_teams has all the user data (sample here)
uid gid name
0 0 User A
1 0 User B
2 0 User C
events_users has when a user is at an event
eid uid gid
0 0 0
0 1 0
1 1 1
I'm looking to write a laravel query to select any users from the users_teams that have a specified gid, and also aren't in events_users with a specified eid.
So for gid 0 and eid 0 i should get the details of User C
I thought an anti-join would work, but keep getting empty results. Can anyone help?
$result = Users_team::where('users_teams.gid', '=', $gid)
->leftJoin('events_users', function($join) use ($gid, $eid)
{
$join->on('users_teams.uid', '=', 'events_users.uid')
->where('events_users.eid', '=', $eid);
})
->whereNull('events_users.eid')
->get();
I think this is what you need:
$users = Users_team::whereRaw("uid NOT IN (SELECT uid FROM events_users WHERE gid = ? AND eid != ?)", [$gid, $eid])->get();
I tryed with this plain SQL query
I hope this works for you.
I have this query that is executed in my php code:
SELECT ((SUM(CASE WHEN I.InCompliance=1 AND FI.Status='C' THEN 1 ELSE 0 END)*100) / (SUM(CASE WHEN FI.Status='C' THEN 1 ELSE 0 END))) as result
FROM tbl_Inspection I,tbl_Facility F,tbl_FacilityInspection FI
WHERE I.InspectionDate >= '2013-2-01'
AND I.InspectionDate < '2014-3-01'
AND I.belongsToFacility=F.FacilityID
AND I.FacInspId=FI.FacInspId
AND F.DistrictID=1
it executes just fine for me in mssql management studio but I get this error
Warning: odbc_exec(): SQL error: [unixODBC][FreeTDS][SQL Server]The cursor was not declared., SQL state 37000 in SQLExecDirect in /srv/www/htdocs/capsdev/includes/phpdbform_db_odbc.php on line 104 SELECT ((SUM(CASE WHEN I.InCompliance=1 AND FI.Status='C' THEN 1 ELSE 0 END)*100) / (SUM(CASE WHEN FI.Status='C' THEN 1 ELSE 0 END))) as result FROM tbl_Inspection I,tbl_Facility F,tbl_FacilityInspection FI WHERE I.InspectionDate >= '2013-2-01' AND I.InspectionDate < '2014-3-01' AND I.belongsToFacility=F.FacilityID AND I.FacInspId=FI.FacInspId AND F.DistrictID=1 Warning: odbc_fetch_array() expects parameter 1 to be resource, boolean given in /srv/www/htdocs/capsdev/includes/phpdbform_db_odbc.php on line 114
Any help would be much appreciated.
Thank you,
Daniel
Try using explicit rather than implicit joins.
Something like:
SELECT ((SUM(CASE WHEN I.InCompliance=1 AND FI.Status='C' THEN 1 ELSE 0 END)*100) / (SUM(CASE WHEN FI.Status='C' THEN 1 ELSE 0 END))) as result
FROM tbl_Inspection I
inner join tbl_Facility F
on I.belongsToFacility=F.FacilityID
inner join tbl_FacilityInspection FI
on I.FacInspId=FI.FacInspId
WHERE I.InspectionDate >= '2013-2-01'
AND I.InspectionDate < '2014-3-01'
AND F.DistrictID=1
Suppose I have a table:
col1, col2, col3
1 0 1.3
0 0 0
0 1 0
1 1.5 1
Now, let's say each row has a "weight" calculated as this:
(col1 > 0 ? 1 : 0) + (col2 > 0 ? 1 : 0) + (col3 > 0 ? 1 : 0)
How can I select the total weight of all rows?
With the data I have given the total weight is 2+0+1+3=6
You just need one aggregate SUM() surrounding all the conditions with no GROUP BY.
SELECT
SUM(
(CASE WHEN col1 > 0 THEN 1 ELSE 0 END)
+ (CASE WHEN col2 > 0 THEN 1 ELSE 0 END)
+ (CASE WHEN col3 > 0 THEN 1 ELSE 0 END)
) AS total_weight
FROM your_table
http://sqlfiddle.com/#!2/b0d82/1
I am using CASE WHEN... here as it is portable across any RDBMS. Since MySQL will return a boolean 0 or 1 for the conditions though, it can be simplified in MySQL as:
SELECT
SUM(
(col1 > 0) /* returns 1 or 0 */
+ (col2 > 0)
+ (col3 > 0)
) AS total_weight
FROM your_table
http://sqlfiddle.com/#!2/b0d82/2