I want to delete the rows with null values in the column
How can i delete it?
SELECT employee.Name,
`department`.NUM,
SALARY
FROM employee
LEFT JOIN `department` ON employee.ID = `department`.ID
ORDER BY NUM;
+--------------------+-------+----------+
| Name | NUM | SALARY |
+--------------------+-------+----------+
| Gallegos | NULL | NULL |
| Lara | NULL | NULL |
| Kent | NULL | NULL |
| Lena | NULL | NULL |
| Flores | NULL | NULL |
| Alexandra | NULL | NULL |
| Hodge | 8001 | 973.45 |
+--------------------+-------+----------+
Should be like this
+--------------------+-------+----------+
| Name | NUM | SALARY |
+--------------------+-------+----------+
| | | |
| Hodge | 8001 | 973.45 |
+--------------------+-------+----------+
You are asking to delete, but to me it seems more like removing nulls from the result of select statement, if so use:
SELECT employee.Name,
`department`.NUM,
SALARY
FROM employee
LEFT JOIN `department` ON employee.ID = `department`.ID
WHERE (`department`.NUM IS NOT NULL AND SALARY IS NOT NULL)
ORDER BY NUM;
Note: The parentheses are not required but it’s good practice to enclose grouped comparators for better readability.
The above query will exclude the even if the NUM column is not null and the SALARY column is null and vice versa
If by deleting you mean that you don't want to see rows with null values in your table, you can use INNER JOIN instead of LEFT JOIN.
You use INNER JOIN when you want to return only records having pair on both sides, and you'll use LEFT JOIN when you need all records from the “left” table, no matter if they have pair in the “right” table or not.
You can learn more here.
I have three tables:
CREATE TABLE `Agreement` (
`AID` bigint(20) NOT NULL AUTO_INCREMENT,
`FLAGS` bigint(20) NOT NULL DEFAULT '0',
PRIMARY KEY (`AID`)
);
CREATE TABLE `Assessment` (
`ASMID` bigint(20) NOT NULL AUTO_INCREMENT,
`AID` bigint(20) NOT NULL DEFAULT '0',
`Amount` decimal(19,4) NOT NULL DEFAULT '0.0000',
`Description` text,
PRIMARY KEY (`ASMID`)
);
CREATE TABLE `Payment` (
`RID` bigint(20) NOT NULL AUTO_INCREMENT,
`AID` bigint(20) NOT NULL DEFAULT '0',
`ASMID` bigint(20) NOT NULL DEFAULT '0',
`Amount` decimal(19,4) NOT NULL DEFAULT '0.0000',
`Description` text,
PRIMARY KEY (`RID`)
);
And I'm inserting one Agreement, three Assessment, five Payment rows mentioned as below:
INSERT INTO Agreement(FLAGS) VALUES(0);
INSERT INTO Assessment(AID, Amount, Description) VALUES (1, 1200, "Rent");
INSERT INTO Assessment(AID, Amount, Description) VALUES (1, 20, "Damage - car break");
INSERT INTO Assessment(AID, Amount, Description) VALUES (1, 500, "Damage - vehicle");
INSERT INTO Payment(AID, ASMID, Amount, Description) VALUES(1, 1, 500, "Rent Fee");
INSERT INTO Payment(AID, ASMID, Amount, Description) VALUES(1, 1, 600, "Rent Fee");
INSERT INTO Payment(AID, ASMID, Amount, Description) VALUES(1, 2, 20, "Damage Fee");
INSERT INTO Payment(AID, Amount, Description) VALUES(1, 600, "Deposit Fee");
INSERT INTO Payment(AID, Amount, Description) VALUES(1, 50, "Application Fee");
and When I see the data, so it should look like this:
mysql> SELECT * FROM Agreement;
+-----+-------+
| AID | FLAGS |
+-----+-------+
| 1 | 0 |
+-----+-------+
1 row in set (0.00 sec)
mysql> SELECT * FROM Assessment;
+-------+-----+-----------+--------------------+
| ASMID | AID | Amount | Description |
+-------+-----+-----------+--------------------+
| 1 | 1 | 1200.0000 | Rent |
| 2 | 1 | 20.0000 | Damage - car break |
| 3 | 1 | 500.0000 | Damage - vehicle |
+-------+-----+-----------+--------------------+
3 rows in set (0.00 sec)
mysql> SELECT * FROM Payment;
+-----+-----+-------+----------+-----------------+
| RID | AID | ASMID | Amount | Description |
+-----+-----+-------+----------+-----------------+
| 1 | 1 | 1 | 500.0000 | Rent Fee |
| 2 | 1 | 1 | 600.0000 | Rent Fee |
| 3 | 1 | 2 | 20.0000 | Damage Fee |
| 4 | 1 | 0 | 600.0000 | Deposit Fee |
| 5 | 1 | 0 | 50.0000 | Application Fee |
+-----+-----+-------+----------+-----------------+
5 rows in set (0.00 sec)
So, any Agreement has multiple Assessments all need to be paid in near future. It may have multiple Payments which might be associated with Assessment (i.e., Rent Fee) or might be not (i.e., Application Fee).
Now, in reality, there are multiple Agreements which have multiple Assessments and multiple Payments.
Now I want the result that covers all of the rows from both tables Assessment and Payment associated with Agreement GROUPED BY first Agreement, second Assessment. Additionally, I need to aggregate AMOUNT as PaymentsApplied from the table Payment table for each Assessment so that we can compare it with Amount from the table Assessment as AmountDue. Plus if any Payment is not associated with any Assessment then don't do aggregation. The result would look like this:
+-----+-------+-----------+-----------------+--------------------+-----------------+
| AID | ASMID | AmountDue | PaymentsApplied | ASM-Descr | PMT-Description |
+-----+-------+-----------+-----------------+--------------------+-----------------+
| 1 | 1 | 1200.0000 | 1100.0000 | Rent | Rent Fee |
| 1 | 2 | 20.0000 | 20.0000 | Damage - car break | Damange Fee |
| 1 | 3 | 500.0000 | NULL | Damage - vehicle | NULL |
| 1 | 0 | NULL | 600.0000 | NULL | Deposit Fee |
| 1 | 0 | NULL | 50.0000 | NULL | Application Fee |
+-----+-------+-----------+-----------------+--------------------+-----------------+
5 Rows
I tried my best to explain the situation. Actually, in my application query has joins over 10 tables like Agreement!
Any Help would be most welcome!!
UPDATE 1
I've started from this query,
(SELECT DISTINCT
Payment.RID, Payment.Amount as PaymentsApplied, Payment.ASMID as PMT_ASMID, null as AmountDue, null AS ASMID
FROM Payment
LEFT JOIN Assessment ON Assessment.ASMID=Payment.ASMID)
UNION
(SELECT DISTINCT
null, null, null, Assessment.Amount, Assessment.ASMID
FROM Assessment
LEFT JOIN Payment ON Payment.ASMID=Assessment.ASMID)
ORDER BY ASMID, PMT_ASMID;
which gives me result,
+------+-----------------+-----------+-----------+-------+
| RID | PaymentsApplied | PMT_ASMID | AmountDue | ASMID |
+------+-----------------+-----------+-----------+-------+
| NULL | NULL | NULL | 1200.0000 | 1 |
| NULL | NULL | NULL | 20.0000 | 2 |
| NULL | NULL | NULL | 500.0000 | 3 |
| 1 | 500.0000 | 1 | NULL | NULL |
| 2 | 600.0000 | 1 | NULL | NULL |
| 3 | 20.0000 | 2 | NULL | NULL |
| 4 | 600.0000 | 0 | NULL | NULL |
| 5 | 50.0000 | 0 | NULL | NULL |
+------+-----------------+-----------+-----------+-------+
8 rows in set (0.01 sec)
Now, from this point, IDK how to aggregate Payment rows by Assessment ID (ASMID) and do join with Agreement table also?
UPDATE 2
I've made sqlfiddle link just in case someone wants to try it.
I've added conditional aggregation in my query,
(SELECT DISTINCT
null as AmountDue,
null AS ASMID,
null as ASM_Descr,
Payment.Description as PMT_Descr,
(CASE WHEN Payment.ASMID > 0 THEN SUM(Payment.Amount) ELSE Payment.Amount END) as PaymentsApplied,
(CASE WHEN Payment.ASMID > 0 THEN GROUP_CONCAT(Payment.RID) ELSE Payment.RID END) as PaymentList,
Payment.ASMID as PMT_ASMID
FROM Payment
LEFT JOIN Assessment ON Assessment.ASMID=Payment.ASMID
GROUP BY Assessment.ASMID)
UNION ALL
(SELECT DISTINCT
Assessment.Amount,
Assessment.ASMID,
Assessment.Description,
null,
null,
null,
null
FROM Assessment
LEFT JOIN Payment ON Payment.ASMID=Assessment.ASMID
GROUP BY Assessment.ASMID)
ORDER BY ASMID, PMT_ASMID;
which gives me,
+-----------+-------+--------------------+-------------+-----------------+-------------+-----------+
| AmountDue | ASMID | ASM_Descr | PMT_Descr | PaymentsApplied | PaymentList | PMT_ASMID |
+-----------+-------+--------------------+-------------+-----------------+-------------+-----------+
| NULL | NULL | NULL | Deposit Fee | 600.0000 | 4 | 0 |
| NULL | NULL | NULL | Rent Fee | 1100.0000 | 1,2 | 1 |
| NULL | NULL | NULL | Damage Fee | 20.0000 | 3 | 2 |
| 1200.0000 | 1 | Rent | NULL | NULL | NULL | NULL |
| 20.0000 | 2 | Damage - car break | NULL | NULL | NULL | NULL |
| 500.0000 | 3 | Damage - vehicle | NULL | NULL | NULL | NULL |
+-----------+-------+--------------------+-------------+-----------------+-------------+-----------+
But, this one is still missing one row from Payment row (RID: 5) and I'm not getting the expected result.
I'd first collect all assessments, left join them to the payments and then union all payments without assessments:
# Assessments with payments
SELECT asm.AID,
asm.ASMID,
min(asm.Amount) AS AmountDue,
SUM(pam.Amount) AS PaymentsApplied,
asm.Description AS `ASM-Descr`,
pam.Description AS `PMT-Descr`,
agr.FLAGS
FROM Assessment asm
LEFT JOIN Payment pam ON pam.ASMID = asm.ASMID
JOIN Agreement agr ON agr.AID = asm.AID
GROUP BY asm.AID,
asm.ASMID
UNION # Payments without assessments
SELECT pam.AID,
pam.ASMID,
NULL AS AmountDue,
SUM(pam.Amount) AS PaymentsApplied,
NULL AS `ASM-Descr`,
pam.Description AS `PMT-Descr`,
agr.FLAGS
FROM Payment pam
LEFT JOIN Assessment asm ON pam.ASMID = asm.ASMID
JOIN Agreement agr ON agr.AID = pam.AID
WHERE asm.ASMID IS NULL
GROUP BY pam.AID, pam.RID;
If you want to add more information you could wrap this result, give it a name and join more tables to the temporary result:
SELECT payment_overview.*,
p.name
FROM
( # Assessments with payments
SELECT asm.AID,
asm.ASMID,
min(asm.Amount) AS AmountDue,
SUM(pam.Amount) AS PaymentsApplied,
asm.Description AS `ASM-Descr`,
pam.Description AS `PMT-Descr`,
agr.FLAGS
FROM Assessment asm
LEFT JOIN Payment pam ON pam.ASMID = asm.ASMID
JOIN Agreement agr ON agr.AID = asm.AID
GROUP BY asm.AID,
asm.ASMID
UNION # Payments without assessments
SELECT pam.AID,
pam.ASMID,
NULL AS AmountDue,
SUM(pam.Amount) AS PaymentsApplied,
NULL AS `ASM-Descr`,
pam.Description AS `PMT-Descr`,
agr.FLAGS
FROM Payment pam
LEFT JOIN Assessment asm ON pam.ASMID = asm.ASMID
JOIN Agreement agr ON agr.AID = pam.AID
WHERE asm.ASMID IS NULL
GROUP BY pam.AID,
pam.RID ) AS payment_overview
JOIN Payor p ON p.AID = payment_overview.AID ;
It seems you want a result row per AID + ASMID + PMT-Description. So:
Select from payments and aggregate.
Select from assessments.
Full outer join the two, as there can be payments without accessments and accessments without payments.
MySQL lacks FULL OUTER JOIN. So write the same query twice, once with LEFT OUTER JOIN, once with RIGHT OUTER JOIN, and use UNION on the two result sets.
select
p.aid,
p.asmid,
a.amount as amount_due,
p.payments_applied,
a.description as asm_description,
p.description as pmt_description
from
(
select aid, asmid, description, sum(amount) as payments_applied
from payment
group by aid, asmid, description
) p
left join assessment a on a.aid = p.aid and a.asmid = p.asmid
union
select
p.aid,
p.asmid,
a.amount as amount_due,
p.payments_applied,
a.description as asm_description,
p.description as pmt_description
from
(
select aid, asmid, description, sum(amount) as payments_applied
from payment
group by aid, asmid, description
) p
right join assessment a on a.aid = p.aid and a.asmid = p.asmid
order by aid, asmid, pmt_description;
Once MySQL features FULL OUTER JOIN you can cut this query in half.
Here's the columns for table users.
+--------+-----------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------+-----------------+------+-----+---------+----------------+
| uid | int(6) unsigned | YES | | NULL | |
| score | decimal(6,2) | YES | | NULL | |
| status | text | YES | | NULL | |
| date | datetime | YES | | NULL | |
| cid | int(7) unsigned | NO | PRI | NULL | auto_increment |
+--------+-----------------+------+-----+---------+----------------+
I want the difference between a user's most current score and earliest score. I tried:
select co1.uid, co1.score, co1.date from users as co1, (select uid, score, min(date) from users group by uid) as co2 where co2.uid = co1.uid;
This does not work. I also tried
select co1.uid, co1.score, co1.date from users as co1, (select uid, score, max(date) - min(date) from users group by uid) as co2 where co2.uid = co1.uid;
Result I get:http://pastebin.com/seR81WbE
Result I want:
uid max(score)-min(score)
1 40
2 -60
3 23
etc
I think the simplest solution is two joins:
select u.uid, umin.score, umax.score
from (select uid, min(date) as mind, max(date) as maxd
from users
group by uid
) u join
users umin
on u.uid = umin.uid and umin.date = u.mind join
users umax
on u.uid = umax.uid and umax.date = u.maxd;
I should note: if you know the scores are only increasing, you can do the much simpler:
select uid, min(score), max(score)
from users
group by uid;
Given these tables:
+---------------+---------+
| Field | Type |
+---------------+---------+
| group_id | int(10) |
| subscriber_id | int(10) |
+---------------+---------+
+---------------+--------------+
| Field | Type |
+---------------+--------------+
| subscriber_id | int(10) |
| firstname | varchar(50) |
| lastname | varchar(50) |
| company | varchar(120) |
| position | varchar(50) |
| email | text |
| lettertype | varchar(5) |
| status | varchar(20) |
+---------------+--------------+
I used the following query to get a subset of subscribers:
SELECT *
FROM newsletter_subscribe AS a, newsletter_subscriber AS b
WHERE (a.group_id = 1 or a.group_id = 4)AND (a.subscriber_id = b.subscriber_id)
What I'd like to do is exclude from the subset if a row exists in newsletter_subscribe where group_id = 3 then the newsletter_subscribe from that row is excluded from the result.
My thought was to make a temporary table to replace a, but I'm not certain how to go about it.
SELECT *
FROM newsletter_subscribe AS a, newsletter_subscriber AS b
WHERE (a.group_id = 1 or a.group_id = 4) AND (a.subscriber_id = b.subscriber_id) AND (b.subscriber_id NOT IN (SELECT subscriber_id FROM newsletter_subscribe WHERE group_id = 3))
As it stands now, you'll never get group_id=3, because you only allow groups 1 and 4 in the first term of your where clause. If you want ALL groups EXCEPT 3, then use
WHERE (a.group_id <> 3) AND (a.subscriber_id = b.subscriber_id)
or perhaps
WHERE 3 NOT IN (a.group_id, b.group_id) AND (a.subscriber_id = b.subscriber_id)
to exclude it from both tables.
For a homework assignment, I have to write a MySQL query to calculate the GPA of every student in the database table. I broke the problem down into 3 parts: (1) calculating the number of grade points earned by each student, (2) calculating the number of credits taken, and then (3) dividing grade points by credits. Here are the queries I've written for steps 1 and 2:
Calculate grade points earned:
SELECT ID, SUM( credits ) AS credits_taken
FROM takes
NATURAL JOIN course
GROUP BY ID
2 Find grade points earned:
SELECT ID, SUM( credits * ( SELECT points FROM gradepoint WHERE letter = grade ) ) AS tot_grade_points
FROM takes NATURAL JOIN course
GROUP BY ID
I manually evaluated each query and they return the correct results. But I can't figure out how to return (credits_taken / tot_grade_points) for each student. Here is what I have tried:
SELECT ID, GPA
FROM student AS S NATURAL JOIN
(SELECT ID,( 'credits_taken' / SUM( credits * ( SELECT points FROM gradepoint WHERE letter = grade ) )) AS GPA
FROM takes AS T1 NATURAL JOIN course
WHERE S.ID = T1.ID
AND EXISTS (
SELECT ID, SUM( credits ) AS 'credits_taken'
FROM takes AS T2 NATURAL JOIN course
WHERE S.ID = T2.ID
GROUP BY ID
)
GROUP BY ID) Z
GROUP BY ID
But this gives me the error " Unknown column 'S.ID' in 'where clause'". From what I've read, you can't reference the alias of a table from a subquery in a join operation. Does anyone have another way of doing the calculation of these two subqueries and returning them bound to the student ID?
The 'takes' table maps student IDs to information about the courses they've taken, most importantly the course_id and grade. The 'course' table contains the 'credits' field, the number of credits the course is worth.
EDIT
Here are the relevant table structures:
takes:
Field | Type | Null | Key | Default | Extra |
+-----------+--------------+------+-----+---------+-------+
| ID | varchar(5) | NO | PRI | | |
| course_id | varchar(8) | NO | PRI | | |
| sec_id | varchar(8) | NO | PRI | | |
| semester | varchar(6) | NO | PRI | | |
| year | decimal(4,0) | NO | PRI | 0 | |
| grade | varchar(2) | YES | | NULL | |
+-----------+--------------+------+-----+---------+-------+
course:
+-----------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------+--------------+------+-----+---------+-------+
| course_id | varchar(8) | NO | PRI | | |
| title | varchar(50) | YES | | NULL | |
| dept_name | varchar(20) | YES | MUL | NULL | |
| credits | decimal(2,0) | YES | | NULL | |
+-----------+--------------+------+-----+---------+-------+
I would try:
SELECT takes.sec_id,
SUM( course.credits * gradepoint.points ) / SUM( course.credits ) AS GPA
FROM takes
JOIN gradepoint ON takes.grade = gradepoint.letter
JOIN course ON takes.course_id = course.course_id
GROUP BY takes.sec_id
Since your table structure description is incomplete I had to guess gradepoint schema and I assumed sec_id identifies a student in takes table, if there is another column for that just replace it in the query in both SELECT and GROUP BY parts. Maybe it is ID, but a column name like that is usually used for primary keys. Or maybe there are no primary keys defined at all, which is a bad practise anyway. Also you would need to join student table if you wanted any student info other than id, like name and so on.
I would also recommend using JOIN ... ON ... syntax instead of NATURAL JOIN, not only it is more readable, it also gives you more flexibility, for example see how gradepoint is joined instead of using costly dependent subquery.