SQL query to select all tuples that do not have a specific attribute at all - sql

I have a table (shown below) that maps users to the fruits that they like. This table is a result of a a complicated SELECT statement, and now I am left with specifying the WHERE condition.
I would like to select all users that do not like the fruit "Orange" at all.
U.id
F.fruit
1
Apple
1
Orange
1
Orange
2
Mango
3
Mango
4
Mango
4
Grapes
5
Apple
5
Orange
6
NULL
The resulting table should consist of users 2, 3, 4, 6, because users 1 and 5 have tuples that map them to "Oranges".
I am not allowed to use any sub-queries (make another SELECT statement). I am not sure how to do this given these restrictions, and I was not sure of how to google search for SQL queries for this specific situation.

I would like to select all users that do not like the fruit "Orange" at all.
Assuming you have a table of users, I would suggest not exists:
select u.*
from users u
where not exists (select 1
from <your query here> q
where q.user_id = u.user_id and q.fruit = 'orange'
);
Alternatively, you could aggregate, but this would only return users in your query:
select user_id
from <your query here>
group by user_id
having count(*) filter (where fruit = 'orange') = 0;
Or, if you showed the query, there might be other solutions as well.

Related

How to show data that's not in a table. SQL ORACLE

I've a data base with two tables.
Table Players Table Wins
ID Name ID Player_won
1 Mick 1 2
2 Frank 2 1
3 Sarah 3 4
4 Eva 4 5
5 Joe 5 1
I need a SQL query which show "The players who have not won any game".
I tried but I don't know even how to begin.
Thank you
You need all the rows from players that don't have corresponding rows in wins. For this you need a left join, filtering for rows that don't join:
select
p.id,
p.name
from Players p
left join Wins w on w.Player_won = p.id
where w.Player_won is null
You can also use not in:
select
id,
name
from Players
where id not in (select Player_won from Wins)
How about the MINUS set operator?
Sample data:
SQL> with players (id, name) as
2 (select 1, 'Mick' from dual union all
3 select 2, 'Ffrank' from dual union all
4 select 3, 'Sarah' from dual union all
5 select 4, 'Eva' from dual union all
6 select 5, 'Joe' from dual
7 ),
8 wins (id, player_won) as
9 (select 1, 2 from dual union all
10 select 2, 1 from dual union all
11 select 3, 4 from dual union all
12 select 4, 5 from dual union all
13 select 5, 1 from dual
14 )
Query begins here:
15 select id from players
16 minus
17 select player_won from wins;
ID
----------
3
SQL>
So, yes ... player 3 didn't win any game so far.
I think you should provide your attempts next time, but here you go:
select p.name
from players p
where not exists (select * from wins w where p.id = w.player_won);
MINUS is not the best option here because of not using indexes and instead performing a full-scan of both tables.
I've a data base with two tables.
You don't show the names or any definition of the tables, leaving me to make an educated guess about their structure.
I tried but I don't know even how to begin.
What exactly did you try? Possibly what you are missing here is the concept of a LEFT OUTER JOIN.
Assuming the tables are named player_table and wins_table, and have column names exactly as you showed, and that the player_won column is intended to express the number of games won by the player of that row's ID, and without knowing whether or not wins_table will have rows for players with zero wins… this should cover it:
select Name
from players_table pt
left join wins_table wt on (pt.ID = wt.ID)
-- Either this player is explicitly specified to have Player_won=0
-- or there is no row for this player ID in the wins table
-- (but excluding the possibility of an explicit NULL value, since its meaning would be unclear)
where Player_won = 0 or wt.ID is null;
As you can see from the variety of answers you've gotten, there are many ways to accomplish this.
One additional way to do this is to use COUNT in a correlated subquery, as in:
SELECT *
FROM PLAYERS p
WHERE 0 = (SELECT COUNT(*)
FROM WINS w
WHERE w.PLAYER_WON = p.ID)
db<>fiddle here
SELECT *
FROM Players p
INNER JOIN Wins w
ON p.ID = w.ID
WHERE w.players_won = 0
I have not done SQL in awhile but I think this might be right if you are looking for players with 0 wins

How can I select records, based on if another record doesn't exist?

I'm trying to select certain records, based on if records matching a field don't exist. I have the following table:
ID Name Fruit
--------------------
1 Steve Apple
2 Steve Orange
3 Bob Apple
4 Gary Apple
5 Gary Orange
6 Paul Apple
7 Jeff Orange
Expected results are to only show records where someone has an orange, but they don't have an apple - in this scenario, just Jeff's record should be shown.
Struggling to figure it out. Thanks.
You could do a WHERE clause like this:
SELECT t1.Name
FROM your_table t1
WHERE fruit = 'Orange'
AND NOT EXISTS (
SELECT 1
FROM your_table t2
WHERE t1.Name = t2.Name
AND fruit = 'Apple'
)
This is looking for orange records first, then excluding any records for the same person who also has apple.
If using SQL Server, you can use EXCEPT
SELECT name
FROM #your_table t1
WHERE fruit = 'Orange'
EXCEPT
SELECT name
FROM #your_table t1
WHERE fruit = 'apple'
This finds all the orange people, and then removes anyone who also has apple from the data set.
You can count fruits per user and select users with just 1 orange fruit. If there is no warranty, that every user can have one fruit per type, use count(distinct fruit) instead of count(fruit)
Select Name
From tbl
Group by Name
Having Count(Fruit)=1
and max(Fruit)='Orange'
I tend to like aggregation for this purpose. In this case:
select Name
from tbl
where fruit in ('Orange', 'Apple')
group by Name
having min(Fruit) = 'Orange' and min(fruit) = max(fruit);
enter code hereYou can try the below query to meet your expectation.
select Name
from tbl
group by Name
having Min(Fruit) = 'Orange'

Is it possible to return a default value if one of the record return null

I am new in SQL. Now I want to handle the case that if I am selecting for the Name and Unit in table of fruit where Name in ('apple','orange','banana').
However, there is no item called banana in database yet and I want to have a default value for banana like
Name Unit
apple 10
orange 20
banana 0
How can I do this instead of just getting
Name Unit
apple 10
orange 20
Can I do this by using Union?
Similar to Gordon's solution above with the addition to avoid duplicate rows for banana.
select t.name, unit
from table t
union all
select 'banana', 0
where not exists
(select name from table where name = 'banana');
You can do this with a union:
select t.name, unit
from table t
union all
select 'banana', 0;
Note that if banana is in the table, then you will get a duplicate row.
EDIT:
If you don't want duplicate records, I would suggest a full join approach.
select coalesce(t.name, mine.name) as name, coalesce(t.unit, 0) as unit
from (select 'banana' as name
) mine full outer join
table t;

Alternative to INTERSECT Given Arbitrary Number of conditions

If I have a table similar to the following:
MyIds MyValues
----- --------
1 Meat
1 Fruit
1 Veggies
2 Fruit
2 Meat
3 Meat
How do I create a query such that if I am given an arbitrary list of distinct MyValues, it will give me all the MyIds that match all of MyValues.
Example: If list of MyValues contained [Meat, Fruit, Veggies], I'd like to get MyIds of 1 back because 1 has an entry in the table for each value in MyValues.
I know that this can be done with an INTERSECT if I'm given a specific list of MyValues. But I don't know how it can be done with an arbitrary number of MyValues
You need to count the total number of instances of each MyID which satisfies the condition and that it matches to the number of value supplied in the IN clause.
SELECT MyID
FROM tableName
WHERE MyValues IN ('Meat', 'Fruit', 'Veggies')
GROUP BY MyID
HAVING COUNT(DISTINCT myVAlues) = 3
SQLFiddle Demo
A big question is how the list is being represented. The following gives one approach, representing the list in a table:
with l as (
select 'Meat' as el union all
select 'Fruit' union all
select 'Veggies'
)
select MyId
from t join
l
on t.MyValues = l.el
group by MyId
having count(distinct t.myvalues) = (select count(*) from l)

How to get a proper count in sql server when retrieving a lot of fields?

Here is my scenario,
I have query that returns a lot of fields. One of the fields is called ID and I want to group by ID and show a count in descending order. However, since I am bringing back more fields, it becomes harder to show a true count because I have to group by those other fields. Here is an example of what I am trying to do. If I just have 2 fields (ID, color) and I group by color, I may end up with something like this:
ID COLOR COUNT
== ===== =====
2 red 10
3 blue 5
4 green 24
Lets say I add another field which is actually the same person, but they have a different spelling of their name which throws the count off, so I might have something like this:
ID COLOR NAME COUNT
== ===== ====== =====
2 Red Jim 5
2 Red Jimmy 5
3 Red Bob 3
3 Red Robert 2
4 Red Johnny 12
4 Red John 12
I want to be able to bring back ID, Color, Name, and Count, but display the counts like in the first table. Is there a way to do this using the ID?
If you want a single result set, you would have to omit the name, as in your first post
SELECT Id, Color, COUNT(*)
FROM YourTable
GROUP By Id, Color
Now, you could get your desired functionality with a subquery, although not elegant
SELECT Id, Color Name, (SELECT COUNT(*)
FROM YourTable
Where Id = O.Id
AND Color = O.Color
) AS "Count"
FROM YourTable O
GROUP BY Id, Color, Name
This should work as you desire
Try this:-
SELECT DISTINCT a.ID, a.Color, a.Name, b.Count
FROM yourTable
INNER JOIN (
SELECT ID, Color, Count(1) [Count] FROM yourTable
GROUP BY ID, Color
) b ON a.ID = b.ID, a.Color = b.Color
ORDER BY [Count] DESC
Try doing a sub query to get the count.
-- MarkusQ