SQL using two subqueries - mysql

I am learning about SQL subqueries. Here is the subquery I am using from the book:
SELECT account_id, product_cd, cust_id
FROM account
WHERE open_branch_id = (
SELECT branch_id
FROM branch
WHERE name = 'Woburn Branch'
) AND open_emp_id IN (
SELECT emp_id
FROM employee
WHERE title = 'Teller' OR title = 'Head Teller'
);
Result:
+------------+------------+---------+
| account_id | product_cd | cust_id |
+------------+------------+---------+
| 1 | CHK | 1 |
| 2 | SAV | 1 |
| 3 | CD | 1 |
| 4 | CHK | 2 |
| 5 | SAV | 2 |
| 17 | CD | 7 |
| 27 | BUS | 11 |
+------------+------------+---------+
I have looked over this query trying to interpret it and understand it as well as the reasoning behind it's clauses but, I fail to understand the reason for the last AND clause AND open_emp_id IN...
I noticed that with just
SELECT account_id, product_cd, cust_id
FROM account
WHERE open_branch_id = (
SELECT branch_id
FROM branch
WHERE name = 'Woburn Branch'
)
You get the same result as above. Can anyone explain to me the reasoning behind the last AND open_emp_id IN clause and how omitting it would affect the final result?
Tables used in subquery:
Account table
+------------+------------+---------+------------+------------+--------------------+--------+----------------+-------------+---------------+-----------------+
| account_id | product_cd | cust_id | open_date | close_date | last_activity_date | status | open_branch_id | open_emp_id | avail_balance | pending_balance |
+------------+------------+---------+------------+------------+--------------------+--------+----------------+-------------+---------------+-----------------+
| 1 | CHK | 1 | 2000-01-15 | NULL | 2005-01-04 | ACTIVE | 2 | 10 | 1057.75 | 1057.75 |
| 2 | SAV | 1 | 2000-01-15 | NULL | 2004-12-19 | ACTIVE | 2 | 10 | 500.00 | 500.00 |
| 3 | CD | 1 | 2004-06-30 | NULL | 2004-06-30 | ACTIVE | 2 | 10 | 3000.00 | 3000.00 |
| 4 | CHK | 2 | 2001-03-12 | NULL | 2004-12-27 | ACTIVE | 2 | 10 | 2258.02 | 2258.02 |
| 5 | SAV | 2 | 2001-03-12 | NULL | 2004-12-11 | ACTIVE | 2 | 10 | 200.00 | 200.00 |
| 7 | CHK | 3 | 2002-11-23 | NULL | 2004-11-30 | ACTIVE | 3 | 13 | 1057.75 | 1057.75 |
| 8 | MM | 3 | 2002-12-15 | NULL | 2004-12-05 | ACTIVE | 3 | 13 | 2212.50 | 2212.50 |
| 10 | CHK | 4 | 2003-09-12 | NULL | 2005-01-03 | ACTIVE | 1 | 1 | 534.12 | 534.12 |
| 11 | SAV | 4 | 2000-01-15 | NULL | 2004-10-24 | ACTIVE | 1 | 1 | 767.77 | 767.77 |
| 12 | MM | 4 | 2004-09-30 | NULL | 2004-11-11 | ACTIVE | 1 | 1 | 5487.09 | 5487.09 |
| 13 | CHK | 5 | 2004-01-27 | NULL | 2005-01-05 | ACTIVE | 4 | 16 | 2237.97 | 2897.97 |
| 14 | CHK | 6 | 2002-08-24 | NULL | 2004-11-29 | ACTIVE | 1 | 1 | 122.37 | 122.37 |
| 15 | CD | 6 | 2004-12-28 | NULL | 2004-12-28 | ACTIVE | 1 | 1 | 10000.00 | 10000.00 |
| 17 | CD | 7 | 2004-01-12 | NULL | 2004-01-12 | ACTIVE | 2 | 10 | 5000.00 | 5000.00 |
| 18 | CHK | 8 | 2001-05-23 | NULL | 2005-01-03 | ACTIVE | 4 | 16 | 3487.19 | 3487.19 |
| 19 | SAV | 8 | 2001-05-23 | NULL | 2004-10-12 | ACTIVE | 4 | 16 | 387.99 | 387.99 |
| 21 | CHK | 9 | 2003-07-30 | NULL | 2004-12-15 | ACTIVE | 1 | 1 | 125.67 | 125.67 |
| 22 | MM | 9 | 2004-10-28 | NULL | 2004-10-28 | ACTIVE | 1 | 1 | 9345.55 | 9845.55 |
| 23 | CD | 9 | 2004-06-30 | NULL | 2004-06-30 | ACTIVE | 1 | 1 | 1500.00 | 1500.00 |
| 24 | CHK | 10 | 2002-09-30 | NULL | 2004-12-15 | ACTIVE | 4 | 16 | 23575.12 | 23575.12 |
| 25 | BUS | 10 | 2002-10-01 | NULL | 2004-08-28 | ACTIVE | 4 | 16 | 0.00 | 0.00 |
| 27 | BUS | 11 | 2004-03-22 | NULL | 2004-11-14 | ACTIVE | 2 | 10 | 9345.55 | 9345.55 |
| 28 | CHK | 12 | 2003-07-30 | NULL | 2004-12-15 | ACTIVE | 4 | 16 | 38552.05 | 38552.05 |
| 29 | SBL | 13 | 2004-02-22 | NULL | 2004-12-17 | ACTIVE | 3 | 13 | 50000.00 | 50000.00 |
+------------+------------+---------+------------+------------+--------------------+--------+----------------+-------------+---------------+-----------------+
Branch table:
+-----------+---------------+----------------------+---------+-------+-------+
| branch_id | name | address | city | state | zip |
+-----------+---------------+----------------------+---------+-------+-------+
| 1 | Headquarters | 3882 Main St. | Waltham | MA | 02451 |
| 2 | Woburn Branch | 422 Maple St. | Woburn | MA | 01801 |
| 3 | Quincy Branch | 125 Presidential Way | Quincy | MA | 02169 |
| 4 | So. NH Branch | 378 Maynard Ln. | Salem | NH | 03079 |
+-----------+---------------+----------------------+---------+-------+-------+
Employee table:
+--------+----------+-----------+------------+----------+-----------------+---------+--------------------+--------------------+
| emp_id | fname | lname | start_date | end_date | superior_emp_id | dept_id | title | assigned_branch_id |
+--------+----------+-----------+------------+----------+-----------------+---------+--------------------+--------------------+
| 1 | Michael | Smith | 2005-06-22 | NULL | NULL | 3 | President | 1 |
| 2 | Susan | Barker | 2006-09-12 | NULL | 1 | 3 | Vice President | 1 |
| 3 | Robert | Tyler | 2005-02-09 | NULL | 1 | 3 | Treasurer | 1 |
| 4 | Susan | Hawthorne | 2006-04-24 | NULL | 3 | 1 | Operations Manager | 1 |
| 5 | John | Gooding | 2007-11-14 | NULL | 4 | 2 | Loan Manager | 1 |
| 6 | Helen | Fleming | 2008-03-17 | NULL | 4 | 1 | Head Teller | 1 |
| 7 | Chris | Tucker | 2008-09-15 | NULL | 6 | 1 | Teller | 1 |
| 8 | Sarah | Parker | 2006-12-02 | NULL | 6 | 1 | Teller | 1 |
| 9 | Jane | Grossman | 2006-05-03 | NULL | 6 | 1 | Teller | 1 |
| 10 | Paula | Roberts | 2006-07-27 | NULL | 4 | 1 | Head Teller | 2 |
| 11 | Thomas | Ziegler | 2004-10-23 | NULL | 10 | 1 | Teller | 2 |
| 12 | Samantha | Jameson | 2007-01-08 | NULL | 10 | 1 | Teller | 2 |
| 13 | John | Blake | 2004-05-11 | NULL | 4 | 1 | Head Teller | 3 |
| 14 | Cindy | Mason | 2006-08-09 | NULL | 13 | 1 | Teller | 3 |
| 15 | Frank | Portman | 2007-04-01 | NULL | 13 | 1 | Teller | 3 |
| 16 | Theresa | Markham | 2005-03-15 | NULL | 4 | 1 | Head Teller | 4 |
| 17 | Beth | Fowler | 2006-06-29 | NULL | 16 | 1 | Teller | 4 |
| 18 | Rick | Tulman | 2006-12-12 | NULL | 16 | 1 | Teller | 4 |
+--------+----------+-----------+------------+----------+-----------------+---------+--------------------+--------------------+

The AND open_emp_id IN clause is selecting only the employee ids whose title is 'Teller' or 'Head Teller'. In your case the result is not different because you are looking for branch with the name 'Woburn Branch', and it is just a coincidence that all the employees there are of title 'Teller' or 'Head Teller' only.
| 10 | Paula | Roberts | 2006-07-27 | NULL | 4 | 1 | Head Teller | 2 |
| 11 | Thomas | Ziegler | 2004-10-23 | NULL | 10 | 1 | Teller | 2 |
| 12 | Samantha | Jameson | 2007-01-08 | NULL | 10 | 1 | Teller | 2 |
Change the branch name to 'Headquarters' in the first query, and you will see the difference that the subquery makes. Any employees at the 'Headquarters' who do not have title 'Teller' or 'Head Teller' will get excluded.

The last AND narrows the selection criteria to include only accounts that were open by a Teller or Head Teller. If the Loan Manager or Operations Manager had opened the account it would be excluded.

Related

SQL NOT IN JOIN equivalent

Table:
+--------+----------+-----------+------------+----------+-----------------+---------+--------------------+--------------------+
| emp_id | fname | lname | start_date | end_date | superior_emp_id | dept_id | title | assigned_branch_id |
+--------+----------+-----------+------------+----------+-----------------+---------+--------------------+--------------------+
| 1 | Michael | Smith | 2005-06-22 | NULL | NULL | 3 | President | 1 |
| 2 | Susan | Barker | 2006-09-12 | NULL | 1 | 3 | Vice President | 1 |
| 3 | Robert | Tyler | 2005-02-09 | NULL | 1 | 3 | Treasurer | 1 |
| 4 | Susan | Hawthorne | 2006-04-24 | NULL | 3 | 1 | Operations Manager | 1 |
| 5 | John | Gooding | 2007-11-14 | NULL | 4 | 2 | Loan Manager | 1 |
| 6 | Helen | Fleming | 2008-03-17 | NULL | 4 | 1 | Head Teller | 1 |
| 7 | Chris | Tucker | 2008-09-15 | NULL | 6 | 1 | Teller | 1 |
| 8 | Sarah | Parker | 2006-12-02 | NULL | 6 | 1 | Teller | 1 |
| 9 | Jane | Grossman | 2006-05-03 | NULL | 6 | 1 | Teller | 1 |
| 10 | Paula | Roberts | 2006-07-27 | NULL | 4 | 1 | Head Teller | 2 |
| 11 | Thomas | Ziegler | 2004-10-23 | NULL | 10 | 1 | Teller | 2 |
| 12 | Samantha | Jameson | 2007-01-08 | NULL | 10 | 1 | Teller | 2 |
| 13 | John | Blake | 2004-05-11 | NULL | 4 | 1 | Head Teller | 3 |
| 14 | Cindy | Mason | 2006-08-09 | NULL | 13 | 1 | Teller | 3 |
| 15 | Frank | Portman | 2007-04-01 | NULL | 13 | 1 | Teller | 3 |
| 16 | Theresa | Markham | 2005-03-15 | NULL | 4 | 1 | Head Teller | 4 |
| 17 | Beth | Fowler | 2006-06-29 | NULL | 16 | 1 | Teller | 4 |
| 18 | Rick | Tulman | 2006-12-12 | NULL | 16 | 1 | Teller | 4 |
+--------+----------+-----------+------------+----------+-----------------+---------+--------------------+--------------------
Query using subquery:
-- Select employees that do not manage others
SELECT
emp_id,
fname,
lname,
title
FROM
employee
WHERE
emp_id NOT IN (
SELECT
superior_emp_id
FROM
employee
WHERE
superior_emp_id IS NOT NUll
);
Result:
+--------+----------+----------+----------------+
| emp_id | fname | lname | title |
+--------+----------+----------+----------------+
| 2 | Susan | Barker | Vice President |
| 5 | John | Gooding | Loan Manager |
| 7 | Chris | Tucker | Teller |
| 8 | Sarah | Parker | Teller |
| 9 | Jane | Grossman | Teller |
| 11 | Thomas | Ziegler | Teller |
| 12 | Samantha | Jameson | Teller |
| 14 | Cindy | Mason | Teller |
| 15 | Frank | Portman | Teller |
| 17 | Beth | Fowler | Teller |
| 18 | Rick | Tulman | Teller |
+--------+----------+----------+----------------+
The above query works fine but I am curious as to how to accomplish the same result using a join.
So far here is what I have but does not return the same results:
SELECT
e1.emp_id,
e1.fname,
e1.lname,
e1.title
FROM
employee e1
JOIN
employee e2 ON e1.emp_id != e2.superior_emp_id
GROUP BY
e1.emp_id;
Results:
+--------+----------+-----------+--------------------+
| emp_id | fname | lname | title |
+--------+----------+-----------+--------------------+
| 1 | Michael | Smith | President |
| 2 | Susan | Barker | Vice President |
| 3 | Robert | Tyler | Treasurer |
| 4 | Susan | Hawthorne | Operations Manager |
| 5 | John | Gooding | Loan Manager |
| 6 | Helen | Fleming | Head Teller |
| 7 | Chris | Tucker | Teller |
| 8 | Sarah | Parker | Teller |
| 9 | Jane | Grossman | Teller |
| 10 | Paula | Roberts | Head Teller |
| 11 | Thomas | Ziegler | Teller |
| 12 | Samantha | Jameson | Teller |
| 13 | John | Blake | Head Teller |
| 14 | Cindy | Mason | Teller |
| 15 | Frank | Portman | Teller |
| 16 | Theresa | Markham | Head Teller |
| 17 | Beth | Fowler | Teller |
| 18 | Rick | Tulman | Teller |
+--------+----------+-----------+--------------------+
The equivalent query uses a left join and where:
SELECT e.*
FROM employee e LEFT JOIN
employee es
ON es.superior_emp_id = e.id
WHERE es.id IS NULL;
This looks for a match on the superior_emp_id. However, you specifically don't want a match -- hence the LEFT JOIN and the WHERE which filters out any matches.
This would normally have better performance than your version. A comparable version would use NOT EXISTS.

SQL Where SUM() Between two values

I am trying to find account info for which the sum of available_balance is between two values. I tried to the following but it is not working as expected:
SELECT sum(a.avail_balance) `sum`
FROM account a
WHERE `sum` BETWEEN 5000 AND 10000
Result:ERROR 1054 (42S22): Unknown column 'sum' in 'where clause'
How can I accomplish my intended result?
My table:
+------------+------------+---------+------------+------------+--------------------+--------+----------------+-------------+---------------+-----------------+
| account_id | product_cd | cust_id | open_date | close_date | last_activity_date | status | open_branch_id | open_emp_id | avail_balance | pending_balance |
+------------+------------+---------+------------+------------+--------------------+--------+----------------+-------------+---------------+-----------------+
| 1 | CHK | 1 | 2000-01-15 | NULL | 2005-01-04 | ACTIVE | 2 | 10 | 1057.75 | 1057.75 |
| 2 | SAV | 1 | 2000-01-15 | NULL | 2004-12-19 | ACTIVE | 2 | 10 | 500.00 | 500.00 |
| 3 | CD | 1 | 2004-06-30 | NULL | 2004-06-30 | ACTIVE | 2 | 10 | 3000.00 | 3000.00 |
| 4 | CHK | 2 | 2001-03-12 | NULL | 2004-12-27 | ACTIVE | 2 | 10 | 2258.02 | 2258.02 |
| 5 | SAV | 2 | 2001-03-12 | NULL | 2004-12-11 | ACTIVE | 2 | 10 | 200.00 | 200.00 |
| 7 | CHK | 3 | 2002-11-23 | NULL | 2004-11-30 | ACTIVE | 3 | 13 | 1057.75 | 1057.75 |
| 8 | MM | 3 | 2002-12-15 | NULL | 2004-12-05 | ACTIVE | 3 | 13 | 2212.50 | 2212.50 |
| 10 | CHK | 4 | 2003-09-12 | NULL | 2005-01-03 | ACTIVE | 1 | 1 | 534.12 | 534.12 |
| 11 | SAV | 4 | 2000-01-15 | NULL | 2004-10-24 | ACTIVE | 1 | 1 | 767.77 | 767.77 |
| 12 | MM | 4 | 2004-09-30 | NULL | 2004-11-11 | ACTIVE | 1 | 1 | 5487.09 | 5487.09 |
| 13 | CHK | 5 | 2004-01-27 | NULL | 2005-01-05 | ACTIVE | 4 | 16 | 2237.97 | 2897.97 |
| 14 | CHK | 6 | 2002-08-24 | NULL | 2004-11-29 | ACTIVE | 1 | 1 | 122.37 | 122.37 |
| 15 | CD | 6 | 2004-12-28 | NULL | 2004-12-28 | ACTIVE | 1 | 1 | 10000.00 | 10000.00 |
| 17 | CD | 7 | 2004-01-12 | NULL | 2004-01-12 | ACTIVE | 2 | 10 | 5000.00 | 5000.00 |
| 18 | CHK | 8 | 2001-05-23 | NULL | 2005-01-03 | ACTIVE | 4 | 16 | 3487.19 | 3487.19 |
| 19 | SAV | 8 | 2001-05-23 | NULL | 2004-10-12 | ACTIVE | 4 | 16 | 387.99 | 387.99 |
| 21 | CHK | 9 | 2003-07-30 | NULL | 2004-12-15 | ACTIVE | 1 | 1 | 125.67 | 125.67 |
| 22 | MM | 9 | 2004-10-28 | NULL | 2004-10-28 | ACTIVE | 1 | 1 | 9345.55 | 9845.55 |
| 23 | CD | 9 | 2004-06-30 | NULL | 2004-06-30 | ACTIVE | 1 | 1 | 1500.00 | 1500.00 |
| 24 | CHK | 10 | 2002-09-30 | NULL | 2004-12-15 | ACTIVE | 4 | 16 | 23575.12 | 23575.12 |
| 25 | BUS | 10 | 2002-10-01 | NULL | 2004-08-28 | ACTIVE | 4 | 16 | 0.00 | 0.00 |
| 27 | BUS | 11 | 2004-03-22 | NULL | 2004-11-14 | ACTIVE | 2 | 10 | 9345.55 | 9345.55 |
| 28 | CHK | 12 | 2003-07-30 | NULL | 2004-12-15 | ACTIVE | 4 | 16 | 38552.05 | 38552.05 |
| 29 | SBL | 13 | 2004-02-22 | NULL | 2004-12-17 | ACTIVE | 3 | 13 | 50000.00 | 50000.00 |
+------------+------------+---------+------------+------------+--------------------+--------+----------------+-------------+---------------+-----------------+
You can only use aggregates for comparison in the HAVING clause:
GROUP BY ...
HAVING SUM(avail_balance) BETWEEN 5000 AND 10000
The HAVING clause requires you to define a GROUP BY clause.
Assuming, you want to SUM the balance for each cust_id, you need something like
SELECT sum(a.avail_balance) `sum`
FROM account a
GROUP BY `cust_id`
HAVING SUM(a.avail_balance) BETWEEN 5000 AND 10000
SELECT sum(a.avail_balance)'sum'
FROM account a
WHERE a.avail_balance between 5000 and 10000
Aggregate functions(AVG,COUNT,MIN,MAX,SUM) for comparison can be achieved by using the "HAVING" clause which requires "GROUP BY" clause(relevant category column depending on the requirement).
As rightly pointed by Pankaj Gadge, cust_id is the most suitable for the requirement of the problem statement
SELECT SUM(a.avail_balance) 'Sum'
FROM account a
GROUP BY cust_id
HAVING SUM(a.avail_balance) BETWEEN 5000 AND 10000;
aggregate may not appear in the WHERE clause unless it is in a subquery contained in a HAVING clause
ex: group by column_name
having sum(avail_balance) between 5000 and 10000

IN operator caluse having a NULL value seems to work

I have an employee table:
+--------+----------+-----------+------------+----------+-----------------+---------+--------------------+--------------------+
| emp_id | fname | lname | start_date | end_date | superior_emp_id | dept_id | title | assigned_branch_id |
+--------+----------+-----------+------------+----------+-----------------+---------+--------------------+--------------------+
| 1 | Michael | Smith | 2005-06-22 | NULL | NULL | 3 | President | 1 |
| 2 | Susan | Barker | 2006-09-12 | NULL | 1 | 3 | Vice President | 1 |
| 3 | Robert | Tyler | 2005-02-09 | NULL | 1 | 3 | Treasurer | 1 |
| 4 | Susan | Hawthorne | 2006-04-24 | NULL | 3 | 1 | Operations Manager | 1 |
| 5 | John | Gooding | 2007-11-14 | NULL | 4 | 2 | Loan Manager | 1 |
| 6 | Helen | Fleming | 2008-03-17 | NULL | 4 | 1 | Head Teller | 1 |
| 7 | Chris | Tucker | 2008-09-15 | NULL | 6 | 1 | Teller | 1 |
| 8 | Sarah | Parker | 2006-12-02 | NULL | 6 | 1 | Teller | 1 |
| 9 | Jane | Grossman | 2006-05-03 | NULL | 6 | 1 | Teller | 1 |
| 10 | Paula | Roberts | 2006-07-27 | NULL | 4 | 1 | Head Teller | 2 |
| 11 | Thomas | Ziegler | 2004-10-23 | NULL | 10 | 1 | Teller | 2 |
| 12 | Samantha | Jameson | 2007-01-08 | NULL | 10 | 1 | Teller | 2 |
| 13 | John | Blake | 2004-05-11 | NULL | 4 | 1 | Head Teller | 3 |
| 14 | Cindy | Mason | 2006-08-09 | NULL | 13 | 1 | Teller | 3 |
| 15 | Frank | Portman | 2007-04-01 | NULL | 13 | 1 | Teller | 3 |
| 16 | Theresa | Markham | 2005-03-15 | NULL | 4 | 1 | Head Teller | 4 |
| 17 | Beth | Fowler | 2006-06-29 | NULL | 16 | 1 | Teller | 4 |
| 18 | Rick | Tulman | 2006-12-12 | NULL | 16 | 1 | Teller | 4 |
+--------+----------+-----------+------------+----------+-----------------+---------+--------------------+--------------------+
If I do
SELECT emp_id, fname, lname, title
FROM employee
WHERE emp_id IN (
SELECT superior_emp_id
FROM employee
);
I get:
+--------+---------+-----------+--------------------+
| emp_id | fname | lname | title |
+--------+---------+-----------+--------------------+
| 1 | Michael | Smith | President |
| 3 | Robert | Tyler | Treasurer |
| 4 | Susan | Hawthorne | Operations Manager |
| 6 | Helen | Fleming | Head Teller |
| 10 | Paula | Roberts | Head Teller |
| 13 | John | Blake | Head Teller |
| 16 | Theresa | Markham | Head Teller |
+--------+---------+-----------+--------------------+
There is a NULL value in the superior_emp_id column.
If the IN operator is equivalent to field=val1 OR field=val2 OR field=val3 OR field=null why does this query not fail or give some error?
It works just fine. You may be confusing in and not in.
If you run not in, then you will get no results. Why? Well, consider 1 not in (2, 3). That evaluates to true. No-brainer.
Then 2 not in (2, 3). That evaluates to false. Just as it should.
But . . . what about these two:
2 not in (2, 3, NULL)
1 not in (2, 3, NULL)
The first is false, because "2" is indeed in the list. The second is . . . well, NULL is not a value. It means "unknown". So, it could be "1" or something else. Hence, it evaluates to NULL. And NULL is treated the same as false in a where.
You can work it out, but this does not occur with in. For instance, in your case, NULL or 1=1 evaluates to true.
For this reason, I strongly recommend always using not exists rather than not in with a subquery. A corollary is that I recommend exists rather than in, but just so the habit of using exists is engrained.
x=NULL predicate evaluates to UNKNOWN
With regards to the OR operator:
TRUE OR UNKNOWN = TRUE
FALSE OR UNKNOWN = UNKNOWN (which is treated as a FALSE in the WHERE clause)
see: https://en.wikipedia.org/wiki/Three-valued_logic

MYSQL GROUP BY HAVING clause unsing MIN and MAX for a range

The query:
SELECT product_cd, SUM(avail_balance) prod_balance
FROM account
WHERE status = 'ACTIVE'
GROUP BY product_cd
HAVING MIN(avail_balance) >= 1000
AND MAX(avail_balance) <= 10000;
The table:
+------------+------------+---------+------------+------------+--------------------+--------+----------------+-------------+---------------+-----------------+
| account_id | product_cd | cust_id | open_date | close_date | last_activity_date | status | open_branch_id | open_emp_id | avail_balance | pending_balance |
+------------+------------+---------+------------+------------+--------------------+--------+----------------+-------------+---------------+-----------------+
| 1 | CHK | 1 | 2000-01-15 | NULL | 2005-01-04 | ACTIVE | 2 | 10 | 1057.75 | 1057.75 |
| 2 | SAV | 1 | 2000-01-15 | NULL | 2004-12-19 | ACTIVE | 2 | 10 | 500.00 | 500.00 |
| 3 | CD | 1 | 2004-06-30 | NULL | 2004-06-30 | ACTIVE | 2 | 10 | 3000.00 | 3000.00 |
| 4 | CHK | 2 | 2001-03-12 | NULL | 2004-12-27 | ACTIVE | 2 | 10 | 2258.02 | 2258.02 |
| 5 | SAV | 2 | 2001-03-12 | NULL | 2004-12-11 | ACTIVE | 2 | 10 | 200.00 | 200.00 |
| 7 | CHK | 3 | 2002-11-23 | NULL | 2004-11-30 | ACTIVE | 3 | 13 | 1057.75 | 1057.75 |
| 8 | MM | 3 | 2002-12-15 | NULL | 2004-12-05 | ACTIVE | 3 | 13 | 2212.50 | 2212.50 |
| 10 | CHK | 4 | 2003-09-12 | NULL | 2005-01-03 | ACTIVE | 1 | 1 | 534.12 | 534.12 |
| 11 | SAV | 4 | 2000-01-15 | NULL | 2004-10-24 | ACTIVE | 1 | 1 | 767.77 | 767.77 |
| 12 | MM | 4 | 2004-09-30 | NULL | 2004-11-11 | ACTIVE | 1 | 1 | 5487.09 | 5487.09 |
| 13 | CHK | 5 | 2004-01-27 | NULL | 2005-01-05 | ACTIVE | 4 | 16 | 2237.97 | 2897.97 |
| 14 | CHK | 6 | 2002-08-24 | NULL | 2004-11-29 | ACTIVE | 1 | 1 | 122.37 | 122.37 |
| 15 | CD | 6 | 2004-12-28 | NULL | 2004-12-28 | ACTIVE | 1 | 1 | 10000.00 | 10000.00 |
| 17 | CD | 7 | 2004-01-12 | NULL | 2004-01-12 | ACTIVE | 2 | 10 | 5000.00 | 5000.00 |
| 18 | CHK | 8 | 2001-05-23 | NULL | 2005-01-03 | ACTIVE | 4 | 16 | 3487.19 | 3487.19 |
| 19 | SAV | 8 | 2001-05-23 | NULL | 2004-10-12 | ACTIVE | 4 | 16 | 387.99 | 387.99 |
| 21 | CHK | 9 | 2003-07-30 | NULL | 2004-12-15 | ACTIVE | 1 | 1 | 125.67 | 125.67 |
| 22 | MM | 9 | 2004-10-28 | NULL | 2004-10-28 | ACTIVE | 1 | 1 | 9345.55 | 9845.55 |
| 23 | CD | 9 | 2004-06-30 | NULL | 2004-06-30 | ACTIVE | 1 | 1 | 1500.00 | 1500.00 |
| 24 | CHK | 10 | 2002-09-30 | NULL | 2004-12-15 | ACTIVE | 4 | 16 | 23575.12 | 23575.12 |
| 25 | BUS | 10 | 2002-10-01 | NULL | 2004-08-28 | ACTIVE | 4 | 16 | 0.00 | 0.00 |
| 27 | BUS | 11 | 2004-03-22 | NULL | 2004-11-14 | ACTIVE | 2 | 10 | 9345.55 | 9345.55 |
| 28 | CHK | 12 | 2003-07-30 | NULL | 2004-12-15 | ACTIVE | 4 | 16 | 38552.05 | 38552.05 |
| 29 | SBL | 13 | 2004-02-22 | NULL | 2004-12-17 | ACTIVE | 3 | 13 | 50000.00 | 50000.00 |
+------------+------------+---------+------------+------------+--------------------+--------+----------------+-------------+---------------+-----------------+
Result:
+------------+--------------+
| product_cd | prod_balance |
+------------+--------------+
| CD | 19500.00 |
| MM | 17045.14 |
+------------+--------------+
My understanding goes as far as this, from the query above:
SELECT product_cd, SUM(avail_balance) prod_balance
FROM account
WHERE status = 'ACTIVE'
GROUP BY product_cd
Which results in:
+------------+--------------+
| product_cd | prod_balance |
+------------+--------------+
| BUS | 9345.55 |
| CD | 19500.00 |
| CHK | 73008.01 |
| MM | 17045.14 |
| SAV | 1855.76 |
| SBL | 50000.00 |
+------------+--------------+
My confusion is with:
HAVING MIN(avail_balance) >= 1000
AND MAX(avail_balance) <= 10000;
Which I interpret as: "Include only the ones having a balance that is greater than or equal to 1,000 and lesser than or equal to 10,000" which would result in
BUS: 9345.55
SAV: 1855.76
Which is completely wrong when I ran the query as above. Any explanations as to what is going on would help.
instead of MIN(avail_balance) and MIN(avail_balance), try
HAVING MIN(SUM(avail_balance)) >=1000
and MAX(SUM(avail_balance)) <=10000
You are getting CD and MM in the result beacause all of their values are in between 1000 to 10000
Do you want the total or the minimum or maximum avail_balance match a certain range? They are different things.
The product CD for instance has a total of 19500, a minimum of 1500 and a maximum of 10000. You are showing the total (SUM), but want to see results where the product's minimum (MIN) is >= 1000 and the product's maximum (MAX) is <= 10000. This is true for CD.
So your query shows the correct results.
Maybe you want these, or maybe you want
SELECT
product_cd,
SUM(avail_balance) AS prod_balance
FROM account
WHERE status = 'ACTIVE'
GROUP BY product_cd
HAVING SUM(avail_balance) >= 1000
AND SUM(avail_balance) <= 10000;
instead.

listing corresponding data of two tables

i'm pretty new to sql and i have a problem that i coundn't really describe to google
SELECT name AS state
FROM state
WHERE id IN
(
SELECT state_id
FROM city
WHERE id=(SELECT city_id FROM zipcode)
)
;
This lists the states of all zipcodes I have in my database, I also want to list the zipcodes (zipcode.zipcode) in a additional column corresponding with the state
Thank you very much in advance for your help
my tables look like this:
city
+----+----------+-----------+---------------------+---------+---------+
| id | state_id | county_id | name | lat | lng |
+----+----------+-----------+---------------------+---------+---------+
| 1 | 1 | 1 | Prem, Oberbayern | 47.6833 | 10.8 |
| 2 | 2 | 2 | Pfullendorf (Baden) | 47.9249 | 9.25718 |
| 3 | 3 | 3 | Wissen, Sieg | 50.7833 | 7.75 |
| 4 | 1 | 4 | Miltenberg | 49.7039 | 9.26444 |
| 5 | 1 | 5 | Moosthenning | 48.6833 | 12.5 |
| 6 | 1 | 1 | Bernbeuren | 47.7333 | 10.7833 |
| 7 | 4 | 6 | Demmin, Hansestadt | 53.9 | 13.0333 |
| 8 | 2 | 7 | Konstanz, Universit | 47.6667 | 9.18333 |
| 9 | 5 | 8 | Teutschenthal | 51.45 | 11.8 |
| 10 | 6 | 9 | Vierlinden | 52.515 | 14.3141 |
+----+----------+-----------+---------------------+---------+---------+
zipcode
+----+---------+-------------+---------+
| id | city_id | district_id | zipcode |
+----+---------+-------------+---------+
| 1 | 1 | NULL | 86984 |
| 2 | 2 | NULL | 88630 |
| 3 | 3 | NULL | 57537 |
| 4 | 4 | NULL | 63897 |
| 5 | 4312 | 502 | 84164 |
| 6 | 6 | NULL | 86975 |
| 7 | 7 | 778 | 17109 |
| 8 | 8 | NULL | 78462 |
| 9 | 8 | NULL | 78464 |
| 10 | 8 | NULL | 78465 |
+----+---------+-------------+---------+
state
+----+------------------------+
| id | name |
+----+------------------------+
| 1 | Bayern |
| 2 | Baden-W?rttemberg |
| 3 | Rheinland-Pfalz |
| 4 | Mecklenburg-Vorpommern |
| 5 | Sachsen-Anhalt |
| 6 | Brandenburg |
| 7 | Niedersachsen |
| 8 | Schleswig-Holstein |
| 9 | Nordrhein-Westfalen |
| 10 | Th?ringen |
+----+------------------------+
Use explicit JOINs:
SELECT z.*, s.name AS state
FROM zipcode z JOIN
city c
ON z.city_id = c.id JOIN
state s
ON c.state_id = s.id;
If you are learning SQL, focus on learning JOIN rather than IN.