I'm a bit rusty on SQL and just need a little help thinking this through.
Let's say I have tables for Applications, Ratings and Admins. The idea is that each of the Admins can mark down their Rating for each Application. A Rating has foreign keys for admin_id and application_id.
For the query, I'd like to select all Applications that any particular Admin has not yet rated. Thoughts?
A simple LEFT JOIN perhaps? It basically just returns all rows where there exists no rating from the admin with the particular id.
SELECT a.*
FROM applications a
LEFT JOIN ratings r
ON a.application_id = r.application_id
AND r.admin_id = ?
WHERE r.admin_id IS NULL
I'd write a fiddle, but SQLfiddle is tired again.
SELECT ap.application_id FROM application ap,rating r,admin ad WHERE ad.admin_id=r.admin_id AND ap.application_id NOT IN (SELECT DISTINCT application_id FROM rating) AND ad.admin_id=5;
Does this give the answer?
Haven't tried it myself though, but i think it will..
Related
I have two tables.
drivers
name number email
requests
id driverassigned ....
I want to get everything from drivers table that may or may not be mentioned in requests.driverassigned.
I have tried using join but it returns rows that have a match. Here is what I have so far.
select drivers.email
, drivers.`number`
, drivers.name
, requests.id
from drivers join requests on drivers.`number` like requests.driverassigned
I am sure there is a common solution but I don't have enough sql knowledge to fish it out.
Any Suggestions?
use left join
select drivers.email, drivers.`number`, drivers.name,
coalesce(requests.id,'none') as request_id
from drivers left join requests
on drivers.`number` like '%'+requests.driverassigned+'%'
select drivers.email, drivers.`number`, drivers.name, requests.id
from drivers left join requests on drivers.`number` = requests.driverassigned
I'm practicing some SQL (new to this),
I have the next tables:
screening_occapancy(idscreening,row,col,idclient)
screening(screeningid,idmovie,idtheater,screening_time)
Im trying to creating a query to search which clients watched all the movies in the "screening" table and show their ID(idclient).
this is what I written(which doesn't work):
select idclient from screening_occapancy p where not exists
(select screeningid from screening where screeningid=p.idscreening)
I know it's probably not that good so please try to explain also what am I doing wrong.
P.S My mission is to use not/exists while doing it...
Thanks!
Your query is basically fine, although the select distinct is unnecessary in the subquery:
select p.idclient
from screening_occapancy p
where not exists (select 1
from screening s
where s.screeningid = p.idscreening
);
Notes:
You can select anything in the exists subquery. Selecting a column is misleading.
Use table aliases and use them for all column references, particularly in a correlated subquery.
If you are designing the tables, I would advise you to give the primary key and foreign key the same name (screeningid or idscreening, but not both).
EDIT:
If you want clients who watched all movies, then I would approach this as:
select p.idclient
from screening_occapancy p
group by p.idclient
having count(distinct p.screening_occapancy p) = (select count(*) from screening);
Why don't you count the number of movies in the screening_table, load it into a variable and check the results of your query results against the variable?
load number of movies into variable (identified by idmovie):
SELECT count(DISTINCT(idmovie)) FROM screening INTO #number_of_movies;
check the results of your query against the variable:
SELECT A.idclient,
count(DISTINCT(idmovie)) AS number_of_movies_watched,
FROM screening_occapancy A
INNER JOIN screening B
ON(A.idscreening = B.screeningid)
GROUP BY A.idclient
HAVING number_of_movies_watched = #number_of_movies ;
If you want to find all clients, that attended all screenings, replace idmovie with screeningid.
Even someone relatively new to MySQL can get his head around this query. The "not exists"-approach is more difficult to understand.
I'm writing what is a pretty simple 2-step SQL Query.
I have one table called Users and another called ProfileCharacteristics.
**Users Table:**
UserId [PK]
UserName
**ProfileCharacteristics Table:**
UserId [FK]
.....(other data)
I'm trying to get access to (other data), but I only have the UserName available. So what I'm presently doing is running one SQL Query that matches the UserName to the UserId and stores the UserId value.
Then, I'm pulling all values that match to UserId in ProfileCharacteristics in a separate query. I have a gut feeling that I could combine these two queries into one, but I'm not sure how.
Any pointers?
EDIT: The start of a JOIN?
SELECT * FROM ProfileCharacteristics
INNER JOIN Users
ON ....
What you're looking for is an INNER JOIN:
SELECT pc.*
FROM ProfileCharacteristics pc
JOIN Users u ON pc.UserId = u.UserId
WHERE U.UserName = 'someuser'
A Visual Explanation of SQL Joins
In the article Why Arel?, the author poses the problem:
Suppose we have a users table and a photos table and we want to select all user data and a *count* of the photos they have created.
His proposed solution (with a line break added) is
SELECT users.*, photos_aggregation.cnt
FROM users
LEFT OUTER JOIN (SELECT user_id, count(*) as cnt FROM photos GROUP BY user_id)
AS photos_aggregation
ON photos_aggregation.user_id = users.id
When I attempted to write such a query, I came up with
select users.*, if(count(photos.id) = 0, null, count(photos.id)) as cnt
from users
left join photos on photos.user_id = users.id
group by users.id
(The if() in the column list is just to get it to behave the same when a user has no photos.)
The author of the article goes on to say
Only advanced SQL programmers know how to write this (I’ve often asked this question in job interviews I’ve never once seen anybody get it right). And it shouldn’t be hard!
I don't consider myself an "advanced SQL programmer", so I assume I'm missing something subtle. What am I missing?
I believe your version would produce an error, at least in some database engines. In MSSQL your select would generate [Column Name] is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.. This is because you select can only contain values in the group by or the count.
You could modify your version to select users.id, count(photo.id) and it would work, but it would not be the same result as his query.
I would not say you have to be particularly advanced to come up with a working solution (or the specific solution he came up with) but it is necessary to do the group in a separate query either in the join or as #ron tornambe suggests.
In most DBMSs (MySQL and Postgres are exceptions) the version in your question would be invalid.
You would need to write the query which does not use the derived table as
select users.*, CASE WHEN count(photos.id) > 0 THEN count(photos.id) END as cnt
from users
left join photos on photos.user_id = users.id
group by users.id, users.name, users.email /* and so on*/
MySQL allows you to select non aggregated items that are not in the group by list but this is only safe if they are functionally dependant on the column(s) in the group by.
Whilst the group by list is more verbose without the derived table I would expect most optimisers to be able to transform one to the other anyway. Certainly in SQL Server if it sees you are grouping by the PK and some other columns it doesn't actually do group by comparisons on those other columns.
Some discussion about this MySQL behaviour vs standard SQL is in Debunking GROUP BY myths
Maybe the author of the article is wrong. Your solution works as well, and it may very well be faster.
Personally, I would drop the if alltogether. If you want to count the number of pictures, it makes sense that 'no pictures' results in 0 rather than null.
As an alternative, you can also write a correlated sub-query:
SELECT u.*, (SELECT Count(*) FROM photos p WHERE p.userid=u.id) as cnt
FROM users u
We changed database schema and moved a relationship between users/accounts from a 1-1 to a many to many using a join table accounts_users.
So we have
accounts,
users,
accounts_users (user_id and account_id)
Our data is still 1-1, and we have decided to move back. So I need sql to move back:
To Migrate I used:
INSERT INTO accounts_users (account_id,user_id) SELECT id AS account_id, user_id AS user_id FROM accounts
To move back I have tried:
UPDATE
accounts
SET
user_id = ru.user_id
FROM
accounts r, accounts_users ru
ON
r.id = ru.account_id
Update accounts
Set r.user_id = ru.user_id
FROM accounts r, accounts_users ru
WHERE r.id = ru.account_id
SELECT accounts_users.user_id
INTO accounts
FROM accounts_users
INNER JOIN accounts
ON accounts.id = accounts_users.account_id
All of these give a sql error of some sort. Im guessing its because my sql is ambiguous, and I need some sort of select first or min or something like that.
** To be clear, Im sure still have the 1-1 relationship in the data, but I cant figure out the sql to bring the data from the existing tables back into the original tables. What im looking for is some working sql that will take the data from accounts_users and put the user_id into the account table. Thanks, Joel
You could try...
UPDATE accounts
SET user_id = (SELECT user_id
FROM accounts_users
WHERE accounts_users.accounts_id = accounts.accounts_id);
That'll get pretty tedious if you have a lot of columns in accounts_users that have to go back in accounts, though, and won't work if there is any problems with the ids (hence my previous answer). How many columns are there?
If your mapping is 1-1 then just select the first result (you know there is only one)