ALL sql with subquery, and NOT exist - mysql

Im doing a sql problem and the question is this:
Get all the ship's classes of Russia. If there are no classes of Russia in the database, get all the classes in the database.
Result set: country, class
3 answers (#3 is wrong):
select country, class from Classes
where country = ALL(select country from Classes
where country='Russia')
select country, class
from classes
where not exists (select country
from classes
where country='Russia')
or country='Russia'
select distinct country, class
from classes
where country not in(select country
from classes
where country='Russia')
or country='Russia'
Can anyone explain how the "ALL example works", I dont fully understand how this covers all the cases above: finding only russian classes and if none all the others.
Can anoyone also explain how ans2 and wrong ans3 is different, I think it might have something to do with null values but im not too sure..im quite new to sql

The all is a comparison to all values in the subquery and I don't think the way you are using it is very useful.
It would be much more useful for a numerical comparison like greater than, less than, etc.
From the MySQL site:
SELECT s1 FROM t1 WHERE s1 > ALL (SELECT s1 FROM t2);
This would select all the s1's from t1 that are greater than all of the s1's from t2.
Your example
Your example: select country, class from Classes where country = ALL(select country from Classes where country='Russia') this subquery is only returning a bunch of rows of 'Russia' as you're only selecting country where country equals Russia.
However, ALL, as documented in Oracle (not documented in MySQL) will return a true condition if no values are present allowing you to select all from Russia unless no Russia rows exist.

Related

SQL - IIF clause outside of select statement?

I'm working in MS Access 2010 doing a series of UNIONs inside of a SELECT statement. After all of these UNIONs are complete, I need to add a couple of new columns using IIF statements (i.e., based on the value of a ch column). However, I can't seem to find out how or where to properly squeeze in this syntax so that the IIFs check against an entire column in the final 'unioned' table. Simply put, after the below syntax (which is trimmed and simplified for this question) runs, I want to then append a new variable column (e.g., 'asterisk') in this final table based on whether an existing column cell (e.g., 'grades') contains an asterisk. Help and patience is greatly appreciated -- I am just becoming familiar with the syntax principles of SQL.
SELECT * FROM(
SELECT class, teacher, student
grades2010 AS grades
WHERE NOT(grades2010 IS NULL OR grades2010="")
UNION
SELECT class, teacher, student
grades2011 AS grades
WHERE NOT(grades2011 IS NULL OR grades2011="")
UNION
SELECT class, teacher, student
grades2012 AS grades
WHERE NOT(grades2012 IS NULL OR grades2010="")
)
Here's an example of the type of IIF I'd want to run -- see if 'grades' contains an asterisk and create an indicator:
IIF(InStr([grades],"*")>0,"YES","NO") AS asterisk
So... You are on the right track. It would look something like:
SELECT
IIF(InStr([grades],"*")>0,"YES","NO") AS asterisk,
class,
teacher,
student
FROM(
SELECT class, teacher, student
grades2010 AS grades
WHERE NOT(grades2010 IS NULL OR grades2010="")
UNION
SELECT class, teacher, student
grades2011 AS grades
WHERE NOT(grades2011 IS NULL OR grades2011="")
UNION
SELECT class, teacher, student
grades2012 AS grades
WHERE NOT(grades2012 IS NULL OR grades2010="")
) as mysubquery
But... grades is not a column in your UNION subquery, so this won't work. You'll need to make sure that grade column is added to each SELECT statement in your subquery to do anything with it in your main SELECT.
Also worth mentioning is that your schema isn't the best. Instead of having a table for each year, you should really just have a single table with year as a column. This will get you out of having to do these nasty, and often times slow Union queries. You could fix that up pretty quick by making a table and using that UNION query there to do an INSERT from each of your year based tables.

Why would a SQL query need to be so complicated like this feature allows?

I am studying for SQL exam, and I came across this fact, regarding subqueries:
2. Main query and subquery can get data from different tables
When is a case when this feature would be useful? I find it difficult to imagine such a case.
Millions of situations call for finding information in different tables, it's the basis of relational data. Here's an example:
Find the emergency contact information for all students who are in a chemistry class:
SELECT Emergency_Name, Emergency_Phone
FROM tbl_StudentInfo
WHERE StudentID IN (SELECT b.StudentID
FROM tbl_ClassEnroll b
WHERE Subject = 'Chemistry')
SELECT * FROM tableA
WHERE id IN (SELECT id FROM tableB)
There is plenty of reasons why you have to get data from different tables, such as select sth from main query, which is based on subquery/subqueries from another tables. The usage is really huge.
choose customers from main query which is based on regions and their values
SELECT * FROM customers
WHERE country IN(SELECT name FROM country WHERE name LIKE '%land%')
choose products from main query which is greater or lower than average incoming salary of customers and so on...
You could do something like,
SELECT SUM(trans) as 'Transactions', branch.city as 'city'
FROM account
INNER JOIN branch
ON branch.bID = account.bID
GROUP BY branch.city
HAVING SUM(account.trans) < 0;
This would for a company to identify which branch makes the most profit and which branch is making a loss, it would help identify if the company had to make changes to their marketing approach in certain regions, in theory allowing for the company to become more dynamic and reactive to changes in the economy at any give time.

Search MySql db with multiple "WHERE IN" and "OR" not working

Suppose I have a table like this:
Suppose my user inputs that he wants to see all records where gender is male AND eyecolor = grey.
I already have the following SQL for that:
SELECT User, question, answer FROM [Table] WHERE User IN (
SELECT User FROM [table] WHERE (question, answer) IN (
('gender', 'male'),
('eyecolor', 'grey')
)
)
GROUP BY User
HAVING count(distinct question, answer) = 2)
However, what if my user wants to see all records for (gender = male OR gender = female) AND eyecolor = grey ? How would I format the above sql query to get it to be able to find that?
(Keep in mind, this is a searchform, so eyecolor and gender are only a few fields used for searching; I need to be able to search with and/or combo's)
I'm thinking the only way I can get this to work is something like:
SELECT User
FROM [table]
WHERE (gender = male OR gender = female) AND eyecolor = blue
And my php would have to build the query so that if the user enters more fields, the query expands with more WHERE's etc.?
I have been searching all over but have not been able to get it to work.. Admittedly I'm not the world's greatest with this.
http://sqlfiddle.com/#!2/2e112/1/0
select *
from stuff
where ID in (
select ID
from stuff
where (question='gender' and answer in ('male','female')) or
(question='eyecolor' and answer='grey')
group by ID
having count(ID)=2
)
where 2 is the number of conditions in the nested where statement. If you run that nested select on its own, it will give you just a distinct list of ID's that fit the conditions. The outer statement allows the query to return all records for the ID's that fit those conditions.
i edited this because.... i was wrong before
k... http://sqlfiddle.com/#!2/2f526/1/0
select *
from stuff
where (question='gender' and answer in ('male','female')) or
(question='eyecolor' and answer='grey') or
(question='city' and answer in ('madrid','amsterdam'))
for this query, we return one row that matches any of those conditions for any ID. only ID's that satisfy at least one of those conditions will appear in the results.
select ID, count(*) as matches
from stuff
where (question='gender' and answer in ('male','female')) or
(question='eyecolor' and answer='grey') or
(question='city' and answer in ('madrid','amsterdam'))
group by ID;
then we add the group by, so we can see how many rows are returned for each user and how many conditions they met (count(*)).
select ID
from stuff
where (question='gender' and answer in ('male','female')) or
(question='eyecolor' and answer='grey') or
(question='city' and answer in ('madrid','amsterdam'))
group by ID
having count(ID)=3;
the having count(ID)=3; is what makes this query work. we only want ID's that had 3 rows returned because we have 3 conditions.
and.... we can't use and because no row in that table will ever meet more than one of those conditions at a single time. question cannot be gender, eyecolor and city all at the same time. it has to do with your table layout. city will never be both madrid and amsterdam at the same time.... and will give us nothing. so... by using the having and an or... we can do stuff that's happy...?
and to go on a tangent.... if your table looked like this:
ID gender eyecolor city
---------------------------------------------
100 male blue madrid
200 female grey amsterdam
300 male brown somewhere
you would use and because....
select *
from table
where gender in ('male','female') and
city in ('madrid','amsterdam') and
eyecolor = 'grey'
but your table is a special one and didn't want to go that way because you really shouldn't have a column for every question... what if they change or what if you add 20? that'd be hard to maintain.
and....
select ID
from stuff
where question in ('gender','eyecolor','city') and
answer in ('male','female','grey','madrid','amsterdam')
group by ID
having count(ID)=3;
does also work but i would really be cautious with that because.. the questions and answers should stay together and be explicit because.... what if it was a dating service? and male could be an answer for a person's own gender or the gender they want to date and by doing question='gender' and answer in ('male','female') you are specifying exactly what you mean and not assuming that certain information is only a valid answer for one question.

Query using two tables with DISTINCT

I have two tables - clients and - group
I need to get county and zip from clients and group-assigned from group
When I search, I cannot get distinct results, that is, instead of the output showing 100 clients with zipcode 12345 in jones county in main st group.
I need to have each zip and county listed once by group. I have googled and attempted many ways but it is just beyond me.
Can anyone assist in steering me to the correct way
Adding GROUP BY group, city, zip to the end of your query should get you what you need. It will only return unique combinations of the three.
Presumably you have something like:
select g.*, c.county, c.zip
from clients c join groups g on <some join condition>
You want one result per group. So, add a group by clause such as:
group by g.id -- assuming id uniquely identifies each group
This will give an arbitrary value for the other fields, which may be sufficient for what you are doing. (This uses a MySQL features called Hidden Columns.)

MYSQL Tuple in IN CLause with wildcard matching

I have the following problem. suppose I have a table containing an inventory of cars:
VIN, MAKE, MODEL, PRICE
AND I have another table containing various car classes( eg, compact, mid-sized, suv, etc)
MAKE, MODEL, CLASS
JEEP, NULL , SUV
FORD, EXPLORER, SUV
TOYOTA, YARIS, COMPACT
NULL, CUBE, COMPACT
...
I am wondering how can I select all cars in the database of a certain class? Perhaps, I want to know how many cars of each class exists?
I can write a query like this.
SELECT COUNT(*) FROM CARS WHERE (MAKE, MODEL) IN (SELECT MAKE, MODEL FROM CLASSES WHERE CLASS = 'SUV')
The problem here, I wont actually be able to deal with NULLs in my data. I want to say that all models of JEEP are SUVs, or any MAKE car that's called CUBE would be a compact car.
Could this be done assuming there are no conflicts? Can I have a priority set up, like All Porches are CARS except the Cayenne which is an SUV by doing something like this:
MAKE, MODEL, CLASS
PORCHE, NULL , CAR
PORCHE, CAYENNE, SUV
If this isn't possible with MySQL, is there a better DB technology out there that would be good at this. Lets assume that The CLASSES Table would Contain 50K+ Rows and The CARS Table would contain 5M+ Rows. I am looking for a fast way of performing such a query in the database, and not needing to fetch millions of rows to process in a script? Also What if its not just Make and Model, but also sub-model, engine, etc..
Also, I simplified the data quite a bit, there are 4 levels of hierarchy.
Assuming that make and model cannot be both null for a given class. You can use the ifnull() function in MySQL:
select cl.class, count(*)
from cars c inner join class cl
on c.make = ifnull(cl.make,c.make)
and c.model=ifnull(cl.model,c.model)
group by cl.class
You may want to add an index on columns makes and model for faster access. Since classes have fewer rows using an inner join (as above) will restrict the number of rows returned.
You can write your query like this:
SELECT COUNT(*)
FROM CARS c join
classes cl
on (c.make = cl.make or cl.make is null) and
(c.model = cl.model or cl.model is null) and
cl.class = 'SUV'
The problem is that you might get duplicates. So the better count starts with:
select count(distinct c.vin)
. . .
This should work for the two cases you gave, for JEEP and CUBE.
SELECT s.class, COUNT(*)
FROM car c, car_class s
WHERE c.make = s.make
AND c.model = s.model
GROUP BY s.class
should give you something like
SUV 14
COMPACT 32
TRUCK 11
etc.