How can I do this in Laravel ORM?
SELECT
s.id,
s.name AS NAME,
COALESCE(su.cnt, 0) AS SUBJECTs,
COALESCE(e.marks, 0) AS MARKS
FROM student s
LEFT JOIN
(
SELECT student_id, COUNT(*) AS cnt
FROM subject
GROUP BY student_id
) su
ON s.id = su.student_id
LEFT JOIN
(
SELECT student_id, SUM(mark) AS marks
FROM exam
GROUP BY student_id
) e
ON s.id = e.student_id;
I want to join between STUDENT and SUBJECT, STUDENT and EXAM. The problem is happening when I join the third table, it duplicates the results.
This is
DB::table('student as su')->selectRaw("
su.id,
su.name,
COALESCE(su.cnt, 0) as SUBJECTS,
COALESCE(e.marks, 0) as MARKS
")->leftJoin(DB::raw("(
SELECT student_id, COUNT(*) AS cnt
FROM subject
GROUP BY student_id
) su"), 's.id', '=', 'su.student_id')
->leftJoin(DB::raw("(
SELECT student_id, SUM(mark) AS marks
FROM exam
GROUP BY student_id
) e"), 's.id', '=', 'e.student_id')
Related
I can not execute this code on Oracle, the error shows:
"ORA-00979: not a GROUP BY expression"
However, I was able to run it successfully on MySQL.
How does this happen?
SELECT CONCAT(i.lname, i.fname) AS inst_name,
CONCAT(s.lname, s.fname) AS stu_name,
t.avg_grade AS stu_avg_grade
FROM(
SELECT instructor_id, student_id, AVG(grade) as avg_grade, RANK() OVER(PARTITION BY instructor_id ORDER BY grade DESC) AS rk
FROM grade
GROUP BY 1,2) t
JOIN instructor i
ON t.instructor_id = i.instructor_id
JOIN student s
ON s.student_id = t.student_id
WHERE t.rk = 1
ORDER BY 3 DESC
You can't use ordinals like GROUP BY 1,2 in Oracle. In addition, the ORDER BY grade clause inside your RANK() function has a problem. Keep in mind that analytic functions evaluate after the GROUP BY aggregation, so grade is no longer available. Here is a version which should work without error:
SELECT CONCAT(i.lname, i.fname) AS inst_name,
CONCAT(s.lname, s.fname) AS stu_name,
t.avg_grade AS stu_avg_grade
FROM
(
SELECT instructor_id, student_id, AVG(grade) AS avg_grade,
RANK() OVER (PARTITION BY instructor_id ORDER BY AVG(grade) DESC) AS rk
FROM grade
GROUP BY instructor_id, student_id
) t
INNER JOIN instructor i
ON t.instructor_id = i.instructor_id
INNER JOIN student s
ON s.student_id = t.student_id
WHERE t.rk = 1
ORDER BY t.avg_grade DESC;
I have 2 sub queries which are repeated and are very long so I want to give it a name and then refer that name in the query as mentioned in https://stackoverflow.com/a/3058938/6700081.
I have a Customers table with ID, Name, OrderID
I have the Orders table with ID (this is the order ID so it is also the Foreign key), Price, Order_Date
This is my original query which is working fine:
SELECT CUSTOMERS.name, ORDERS.price FROM
CUSTOMERS INNER JOIN ORDERS
ON (CUSTOMERS.ORDER_ID = ORDERS.ID)
WHERE ORDERS.PRICE = (SELECT MAX(ORDERS.PRICE) from ORDERS where ORDERS.ORDER_DATE <= (SELECT ADD_MONTHS((SELECT MIN(ORDER_DATE) FROM ORDERS), 12*10) from ORDERS WHERE ROWNUM = 1))
AND ORDERS.ORDER_DATE <= (SELECT ADD_MONTHS((SELECT MIN(ORDER_DATE) FROM ORDERS), 12*10) from ORDERS WHERE ROWNUM = 1);
I tried to change it to a named query as below:
WITH MAX_ORDER_DATE as (SELECT ADD_MONTHS((SELECT MIN(ORDER_DATE) FROM ORDERS), 12*10) from ORDERS WHERE ROWNUM = 1),
WITH MAX_ORDER_PRICE as (SELECT MAX(ORDERS.PRICE) from ORDERS where ORDERS.ORDER_DATE <= (MAX_ORDER_DATE))
SELECT CUSTOMERS.name, ORDERS.price FROM
CUSTOMERS INNER JOIN ORDERS
ON (CUSTOMERS.ORDER_ID = ORDERS.ID)
WHERE ORDERS.PRICE = (MAX_ORDER_PRICE)
AND ORDERS.ORDER_DATE <= (MAX_ORDER_DATE);
But I get an error related to invalid table name. What is wrong with this query?
Your corrected query:
WITH MAX_ORDER_DATE AS (
SELECT ADD_MONTHS((SELECT MIN(ORDER_DATE) FROM ORDERS), 12*10) AS max_date
FROM ORDERS
WHERE ROWNUM = 1
),
MAX_ORDER_PRICE AS (
SELECT MAX(ORDERS.PRICE) AS max_price
FROM ORDERS
WHERE ORDERS.ORDER_DATE <= (SELECT max_date FROM MAX_ORDER_DATE)
)
SELECT c.name, o.price
FROM CUSTOMERS c
INNER JOIN ORDERS o
ON c.ORDER_ID = o.ID
WHERE
o.PRICE = (SELECT max_price FROM MAX_ORDER_PRICE) AND
o.ORDER_DATE <= (SELECT max_date FROM MAX_ORDER_DATE);
The main issues I noticed with your syntax were that you repeated WITH for each common table expression, when you only need to state it once at the beginning of the definitions. Also, if you want to use the single values you define in the two CTEs, you should use a subquery against those CTEs. Finally, I added aliases to the columns you select in the CTEs.
$users = SELECT users.id,
users.name,
cd.title,
cd.updated_at,
profiles.avatar
FROM `users`
JOIN (SELECT Max(id) max_id,
user_id
FROM book
GROUP BY user_id) c_max
ON ( c_max.user_id = users.id )
JOIN book cd
ON ( cd.id = c_max.user_id )
JOIN profiles
ON ( profiles.user_id = users.id )
ORDER BY cd.updated_at DESC
i am using this to get data in laravel query
$users = DB::select(DB::raw('SELECT users.id, users.name, cd.title, cd.updated_at, profiles.avatar FROM users JOIN ( SELECT MAX(id) max_id, user_id FROM book GROUP BY user_id )
c_max ON (c_max.user_id = users.id) JOIN book cd ON (cd.id = c_max.user_id) JOIN profiles ON (profiles.user_id = users.id) ORDER by cd.updated_at DESC limit 24 offset 0'));
Write a query to find the name of the student(s) who has scored maximum mark in Software Engineering. Sort the result based on name.
This is what I tried.
select s.student_name
from student s,mark m,subject su
where s.student_id=m.student_id and su.subject_id=m.subject_id and max(m.value)in
(select value from mark where lower(su.subject_name)='software engineering')
order by s.student_name;
I am not getting the proper result.
Apart from the fact that you're using outdated implicit comma syntax for joins, you are also combining columns of the tables in the wrong way in the sub query.
subject_name is a column of subject which has nothing to do with the student's relation to marks. So, mark may be joined separately with subject while determining the student_ids with highest mark. We can then obtain the name of the student using those student_ids
So, In Oracle 12c and above, you could do
SELECT s.student_name
FROM student s
WHERE s.student_id IN ( SELECT m.student_id
FROM mark m JOIN subject su
ON su.subject_id = m.subject_id
WHERE lower(su.subject_name) = 'software engineering'
ORDER BY m.value DESC
FETCH FIRST 1 ROWS WITH TIES ) order by 1;
For previous versions, you may use dense_rank or rank
SELECT s.student_name
FROM student s
WHERE s.student_id IN ( SELECT student_id
FROM ( SELECT m.*,DENSE_RANK() OVER(
ORDER BY m.value DESC
) AS rnk
FROM mark m JOIN subject su
ON su.subject_id = m.subject_id
WHERE lower(su.subject_name) = 'software engineering'
) WHERE rnk = 1
) order by 1;
you need to add the max function in the subquery instead of the main query.
select s.student_name
from student s, mark m, subject su
where s.student_id = m.student_id
and su.subject_id = m.subject_id
and m.value in
(select max(value)
from mark
where lower(su.subject_name) = 'software engineering')
order by s.student_name;
You can try this code. It must work perfectly :
select s.student_name
from student s
join mark m
on s.student_id=m.student_id
join subject s1
on s1.subject_id=m.subject_id
where m.value=(select max(m1.value) from mark m1
join subject s2
on s2.subject_id=m1.subject_id
where lower(s2.subject_name)='software engineering'
group by s2.subject_id)
group by s.student_name
order by s.student_name;
select student_name
from student join mark using(student_id) join subject using(subject_id)
where subject_name = 'Software Engineering'
and value = (select max(value)
from mark join subject using (subject_id)
where subject_name = 'Software Engineering')
order by student_name;
This is very self-explanatory solution.
select student_name
from student s join mark m on s.student_id=m.student_id
join subject sub on m.subject_id=sub.subject_id
where lower(sub.subject_name)='software engineering' and
m.value = (select max(m1.value)
from mark m1 join subject sub1 on m1.subject_id=sub1.subject_id
where lower(sub1.subject_name)='software engineering')
order by student_name;
select student_name
from stundent
where student_id in(
select student_id
from mark
where value=(select max(value) from mark
where subject_id=(
select subject_id
from subject
where lower(subject_name)='software engineering'
)
)
)
)
order by student_name;
select student_name
from student
where student_id in
(select student_id
from subject join mark using(subject_id)
where value in
(select max(value)
from mark
group by student_id
having initcap(subject_name) = 'Software Engineering'))
order by student_name;
I looked at the other questions related to this but it did not work. I even played around with Dense_Rank and still couldn't get the right answer.
Using the Oracle Student Scheme Data. I am trying to find the highest 3 grades for each section based on two tables ( NOT the top 3 rows for each sections. )
This is based off the Student and the Grade table from the Student Scheme
I am using the Oracle Developer 10 and it does not look like it takes the LIMIT function. Cause it gives me the error
missing right parenthesis
select
g.SECTION_ID,g.NUMERIC_GRADE, s.First_Name,s.Last_Name
from GRADE g Join Student s
On g.student_ID = s.student_ID
and Grade_Type_Code='MT'
Where numeric_grade in(Select distinct numeric_grade
from grade
order by numeric_grade desc limit 3);
You can use ROWNUM in Oracle:
SELECT g.SECTION_ID,
g.NUMERIC_GRADE,
s.First_Name,
s.Last_Name
FROM grade g
JOIN Student s
ON g.student_ID = s.student_ID
AND Grade_Type_Code='MT'
WHERE numeric_grade in (SELECT numeric_grade
FROM (SELECT DISTINCT numeric_grade
FROM grade
ORDER BY numeric_grade desc)
WHERE ROWNUM <=3);
Solution with dense_rank:
select section_id, numeric_grade, first_name, last_name
from (
select g.section_id, g.numeric_grade, s.First_Name,s.Last_Name,
dense_rank() over (partition by g.section_id
order by g.numeric_grade desc) rnk
from GRADE g
join Student s on g.student_ID = s.student_ID
and Grade_Type_Code='MT' )
where rnk < 4
order by section_id, numeric_grade desc
SQLFiddle demo