Grouping rows by Max column value per row - mysql

I have a many to many table which has repeating values of student_id, gradelevel_id and schoolyear_id. So my goal is to display records of the most recent schoolyear and last gradelevel taken. In other words, the last grade_level taken by student.
schoolyear_student_lt (MANY TO MANY table)
gradelevel_mt
schoolyear_mt
So is should display 1 unique student_id, 1 grade_level, 1 schoolyear per row on the result set.
I created a stored procedure.
SELECT sslt.gradelevel_id,sy.schoolyear_id, sslt.student_id,MAX(gl.grade_level)
FROM gradelevel_mt gl
INNER JOIN schoolyear_student_lt sslt ON gl.gradelevel_id = sslt.gradelevel_id
INNER JOIN schoolyear_mt sy ON sslt.schoolyear_id = sy.schoolyear_id
WHERE gl.gradelevel_id = sslt.gradelevel_id
GROUP BY sslt.student_id;
But problem is, my stored procedure returns incorrect schoolyear_id and gradelevel_id. Only the student_id and MAX(gl.gradelevel) are correct.
The correct expected result set should be
gradelevel_id | schoolyear_id | student_id | MAX(gl.gradelevel) |
302 401 20170008 1
304 404 20170009 3
For student_id: 20170008 it should be gradelevel_id: 302 (Grade 1) and schoolyear_id : 401 (2016-2017) not 402(2015-2016).
For student_id: 20170009 it should be gradelevel_id: 304 (Grade 3) and schoolyear_id : 404 (2019-2020) not 402(2015-2016).
I hope my explanation is clear. I'd appreciate any help.
Thank you.

Related

SELECT sum but with where in MySQL

I'm trying sum up the total_grand column of my orders table.
So I have this query
SELECT sum(total_grand) as total
FROM `orders`
WHERE overall_status in ("In-Transit","Not Yet Shipped","Not Yet Validated");
It works fine. But I need to add new conditional statement.
Here's my sample orders table columns with data.
total_grand
overall_status
televalidator_user_id
100
In-Transit
1
200
Not Yet Shipped
1
300
Not Yet Validated
NULL
400
Not Yet Validated
1
500
In-Transit
1
---------------------
------------------
------------------
I'm trying to sum up the total_grand but if televalidator_user_id is NULL, It should not be added to the sump
Since there is null televalidator_user_id on row 3
the output must be: 1200
SELECT sum(total_grand) as total
FROM `orders`
WHERE overall_status in ("In-Transit", "Not Yet Shipped", "Not Yet Validated")
AND televalidator_user_id is not null;

combining two select queries from the same table

I need to do something like this:
id tag status user trial Value (other columns)...
1 A Pass peter first 0
2 A Pass peter second 1
3 A Fail peter third 3
4 B Pass peter first 4
5 B Pass peter second 5
6 B Pass peter third 6
select the rows that tag equal A and status equal to Pass and find the same value for other tag ex:B
id tag status user trial Value_tag_A Value_tag_B (other columns)...
1 A Pass peter first O 4
2 A Pass peter second 1 5
I can do some processing using php to get this result, but i'm wondering if i can do it directly using sql
I've tried numerous variations and can't seem to get close to the result.
Solution: http://sqlfiddle.com/#!9/e9068d/17
I don't know why in the rows where tag=A also have Value_tag_B. I will ignore this and maybe the following query is an approach.
SELECT DISTINCT y.status, y.`user`, y.trial,
(SELECT Value FROM toto WHERE y.`user` = `user` and y.trial = trial and tag = 'A' ) AS Value_tag_A,
(SELECT Value FROM toto WHERE y.`user` = `user` and y.trial = trial and tag = 'B' ) AS Value_tag_B
FROM toto y
WHERE y.trial NOT IN (SELECT DISTINCT trial FROM toto WHERE `status` <> 'Pass')
The code has been modified.
SQL Fiddle

MySQL query to gather incorrectly stored data

I have recently taken over a email campaign project and need to generate a report for the customer. However the data has been stored very strangely.
Basically the client wants a report of the subscribers first name and last name that have subscribed to a emailing list.
Example table data.
------------------------------------------------------------
id | owner_id | list_id | field_id | email_address | value
------------------------------------------------------------
1 10 1 137 me#example.com John
2 10 1 138 me#example.com Doe
So as you can see, John Doe has subscribed to mailing list 1, and field_id 137 is his first name and field_id 138 is his last name.
The client is looking for a export with the users first name and last name all is one field.
I tred the following sql query
SELECT value
FROM Table_A AS child
INNER JOIN Table_A AS parent
ON parent.email_address = child.email_address
WHERE child.owner_id = '10'
But unfortunately the query gives me the results in many rows but not appending the first name and last name into one field,
If anyone can provide some assistance that would be awesome.
Thanks.
SELECT
concat( parent.value,' ',child.value)name
FROM mytable AS child
left JOIN mytable AS parent
ON parent.email_address = child.email_address
WHERE child.owner_id = '10'
and parent.field_id=137 and child.field_id=138
Check at-http://sqlfiddle.com/#!9/199b4b/45
I think you have to use a variable to put in there everything you have to and then select the variable with the desired name of yours.
For example:
DECLARE #yourvariable VARCHAR(MAX)
SELECT #yourvariable = COALESCE(#yourvariable + " ") + value
FROM table_A
WHERE owner_id = 10
SELECT #yourvariable as FullName
Try that, it might help.
You can try this code(column name equals value in your original DB):
select a.name
from
table_a a inner join table_a b
on a.email_address = b.email_address and a.field_id <> b.field_id
where a.owner_id=10
order by a.field_id
Here is the example link:
http://sqlfiddle.com/#!9/5fbdf6/25/0
As per assumptions, first name has the field id 137 and last name has the field id 138.
You can try the following query to get the desired result.
SELECT CONCAT(SUBSTRING_INDEX(GROUP_CONCAT(`value`),",",1)," ",SUBSTRING_INDEX(GROUP_CONCAT(`value`),",",-1)) AS client_name
FROM Table_A
WHERE owner_id = 10
AND field_id IN (137, 138)
GROUP BY email_address;

Using 'AND' in SQL WHERE clause for the same filed

Here is the scenario. I have 1 table that has all the contact details. Another table that has all the list of Categories. And a 3rd table which is an associate table, that has the ID of the first table and the ID of the second table.
This is how my associate table looks like
contactdid -2 | categoryid -1
contactdid -2 | categoryid -2
contactdid -2 | categoryid -3
contactdid -3 | categoryid -1
contactdid -3 | categoryid -3
This is my SQL code below(Generated using SQLyog and i included the where clause).
SELECT
press_contacts.email
FROM
contacts_category
INNER JOIN press_category
ON (contacts_category.categoryid = press_category.id)
INNER JOIN press_contacts
ON (contacts_category.contactdid = press_contacts.id)
WHERE contacts_category.categoryid = 1 AND contacts_category.categoryid = 2 ;
I get the output when I do not have AND contacts_category.categoryid = 2inserted in the code.
Any idea how to solve this.I clearly have data.
Thanks in advance for the help.
contacts_category.categoryid can not be 1 and 2 at the same time, perhabs you mean OR instead of AND?
Use OR or IN() instead of AND.
A field can't have two values at the same time
If you only want to see those email addresses with contacts in both categories, try:
SELECT press_contacts.email
FROM contacts_category
INNER JOIN press_contacts
ON (contacts_category.contactdid = press_contacts.id)
WHERE contacts_category.categoryid in (1, 2)
GROUP BY press_contacts.email
HAVING COUNT(DISTINCT contacts_category.categoryid)=2

MySQL - What's wrong with the query?

I am trying to query a database to find the following.
If a customer searches for a hotel in a city between dates A and B, find and return the hotels in which rooms are free between the two dates.
There will be more than one room in each room type (i.e. 5 Rooms in type A, 10 rooms in Type B, etc.) and we have to query the database to find only those hotels in which there is at least one room free in at least one type.
This is my table structure:
**Structure for table 'reservations'**
reservation_id
hotel_id
room_id
customer_id
payment_id
no_of_rooms
check_in_date
check_out_date
reservation_date
**Structure for table 'hotels'**
hotel_id
hotel_name
hotel_description
hotel_address
hotel_location
hotel_country
hotel_city
hotel_type
hotel_stars
hotel_image
hotel_deleted
**Structure for table 'rooms'**
room_id
hotel_id
room_name
max_persons
total_rooms
room_price
room_image
agent_commision
room_facilities
service_tax
vat
city_tax
room_description
room_deleted
And this is my query:
$city_search = '15';
$check_in_date = '29-03-2010';
$check_out_date = '31-03-2010';
$dateFormat_check_in = "DATE_FORMAT('$reservations.check_in_date','%d-%m-%Y')";
$dateFormat_check_out = "DATE_FORMAT('$reservations.check_out_date','%d-%m-%Y')";
$dateCheck = "$dateFormat_check_in >= '$check_in_date' AND $dateFormat_check_out <= '$check_out_date'";
$query = "SELECT $rooms.room_id,
$rooms.room_name,
$rooms.max_persons,
$rooms.room_price,
$hotels.hotel_id,
$hotels.hotel_name,
$hotels.hotel_stars,
$hotels.hotel_type
FROM $hotels,$rooms,$reservations
WHERE $hotels.hotel_city = '$city_search'
AND $hotels.hotel_id = $rooms.hotel_id
AND $hotels.hotel_deleted = '0'
AND $rooms.room_deleted = '0'
AND $rooms.total_rooms - (SELECT SUM($reservations.no_of_rooms) as tot
FROM $reservations
WHERE $dateCheck
GROUP BY $reservations.room_id) > '0'";
The number of rooms already reserved in each room type in each hotel will be stored in the reservations table.
The thing is the query doesn't return any result at all. Even though it should if I calculate it myself manually.
I tried running the sub-query alone and I don't get any result. And I have lost quite some amount of hair trying to de-bug this query from yesterday. What's wrong with this? Or is there a better way to do what I mentioned above?
Edit: Code edited to remove a bug. Thanks to Mark Byers.
Sample Data in reservation table
1 1 1 2 1 3 2010-03-29 2010-03-31 2010-03-17
2 1 2 3 3 8 2010-03-29 2010-03-31 2010-03-18
5 1 1 5 5 4 2010-03-29 2010-03-31 2010-03-12
The sub-query should return
Room ID : 1 Rooms Booked : 7
Room ID : 2 Rooms Booked : 8
But it does not return any value at all.... If i remove the dateCheck condition it returns
Room ID : 2 Rooms Booked : 8
Your problem is here:
$rooms.total_rooms - (SELECT SUM($reservations.no_of_rooms) as tot,
$rooms.room_id as id
FROM $reservations,$rooms
WHERE $dateCheck
GROUP BY $reservations.room_id) > '0'"
You are doing a subtraction total_rooms - (tot, id) where the first operand is a scalar value and the second is a table with two columns. Remove one of the columns in the result set and make sure you only return only one row.
You also should use the JOIN keyword to make joins instead of separating the tables with commas. That way you won't forget to add the join condition.
You probably want something along these lines:
SELECT column1, column2, etc...
FROM $hotels
JOIN $rooms
ON $hotels.hotel_id = $rooms.hotel_id
JOIN (
SELECT SUM($reservations.no_of_rooms) as tot,
$rooms.room_id as id
FROM $reservations
JOIN $rooms
ON ??? /* Aren't you missing something here? */
WHERE $dateCheck
GROUP BY $reservations.room_id
) AS T1
ON T1.id = room_id
WHERE $hotels.hotel_city = '$city_search'
AND $hotels.hotel_deleted = '0'
AND $rooms.room_deleted = '0'
AND $rooms.total_rooms - T1.tot > '0'