SQL Query check if ID is part of another table - sql

I have 2 tables:
tblBook:
BookID, Title
tblFavorite:
FavoriteID, UserID, BookID
I would like to develop a SQL query to Select BookID, Title, IsFavorite (true|false) while given the UserID as parameter.
Foreach BookID there should be checked if there is a row with this BookID and the given UserID in tblFavorite. -> true/false

You can use a correlated subquery:
select b.*,
case when exists (select 1 from tblfavorite f where f.bookid = b.bookid and f.userid = ?)
then 1
else 0
end as isfavorite
from tblbook b
The question mark represents the id of the user for who you are generating the report. In databases that support evaluating conditions as booleans or integers (such as MySQL or Postgres for example), you can dispense the case expression:
select b.*,
exists (select 1 from tblfavorite f where f.bookid = b.bookid and f.userid = ?) as isfavorite
from tblbook b

Use a LEFT JOIN and a CASE expression so that if there is no record in tblFavorite (NULL), it shows False, otherwise it's True.
SELECT B.BookID, B.Title, CASE WHEN FavoriteID IS NULL THEN 'False' ELSE 'True' END AS IsFavorite
FROM tblBook B
LEFT JOIN tblFavorite F on B.BookID = F.BookID

Related

How to do left join to get all the rows with param?

I have articles and users tables. I also have another table articles_users with FK columns: userId articleId.
I also have userId=1
How to get get all the rows also with extra column that tell me if the userid is linked to this row?
I have try to do this with left join but the problem is articles_users have duplicate entries like:
articleId: 1, userId: 1
articleId: 2, userId: 1
articleId: 3, userId: 2
And it get duplicate articles rows or none.
SELECT * FROM articles LEFT JOIN articles_users ON articles_users.articleid = articles.id
WHERE articles_users.userid = 1
I would recommend case and exists:
SELECT a.*,
(CASE WHEN EXISTS (SELECT 1
FROM articles_users au
WHERE au.articleid = a.id AND
au.userid = 1
)
THEN 1 ELSE 0
END) as flag_1
FROM articles a;
Although you can use JOIN, I wouldn't recommend it. If you followed the same pattern for multiple users, you might end up with multiple rows.
Many databases support boolean types explicitly. In those databases, you can eliminate the CASE:
SELECT a.*,
(SELECT 1
FROM articles_users au
WHERE au.articleid = a.id AND
au.userid = 1
) as flag_1
FROM articles a;

Select Count take too long to be executed

I'm executing two queries. One that return the number of records and one that display the results. But how come the query that return the total of records takes 11 sec to be excecuted while the one displaying the result take less than 1 sec to be executed ? It should be the opposite, no ?
SQL that return the total of records is executed after 11 sec
(SELECT count(*) as id
FROM (
SELECT DISTINCT title, version
FROM book AS b
WHERE b.title IS NOT NULL AND NOT EXISTS (SELECT * FROM user AS u WHERE u.column1 = b.column1)
UNION ALL
SELECT DISTINCT title, version
FROM book2 AS b2
WHERE b.title IS NOT NULL AND EXISTS (SELECT * FROM user AS u WHERE u.column2 = b.column1)
) c )
SQL that display the result is executed in less than 1 sec
SELECT DISTINCT title, version
FROM book AS b
WHERE b.title IS NOT NULL AND NOT EXISTS (SELECT * FROM user AS u WHERE u.column1 = b.column1)
UNION ALL
SELECT DISTINCT title, version
FROM book2 AS b2
WHERE b.title IS NOT NULL AND EXISTS (SELECT * FROM user AS u WHERE u.column2 = b.column1)
You could try this:
SELECT COUNT(1)
FROM
(
SELECT DISTINCT title, version
FROM book b
LEFT JOIN u ON b.column1 = u.column2
LEFT JOIN u2 ON b.column1 = u2.column1
WHERE u2.column1 IS NULL
AND b.title IS NOT NULL
) sub
There are chances that you can improve your query here is one of the example and you can check other as well shared by friends
SELECT COUNT(1)
FROM book AS b
LEFT OUTER JOIN User U ON u.Column1 = b.column1
LEFT OUTER JOIN user u1 ON u1.Column2 = b.column1
WHERE b.title IS NOT NULL
AND u.Id IS NULL -- with assumption u might have another column id
AND u1.Id IS NULL -- with assumption u1 might have aother column or
GROUP BY title,Version
You are comparing apples and oranges. The count(*) version has to process all the data before it can return anything.
The more detailed version can start returning rows as they become available -- which is presumably when the first subquery starts returning rows.
I don't think either of these queries are what you really need, but this question does not provide that information.
Also, are book and version not unique? I wonder if this does what you want:
SELECT COUNT(*)
FROM book b
WHERE b.title IS NOT NULL AND
( NOT EXISTS (SELECT 1 FROM user u WHERE u.column1 = b.column1) OR
EXISTS (SELECT 1 FROM user u WHERE u.column2 = b.column1)
);
You can also use COUNT(DISTINCT):
SELECT COUNT(DISTINCT b.title + ':' + b.version)
. . .
(SELECT **count(title)** as id
FROM (
SELECT DISTINCT title, version
FROM book AS b
WHERE b.title IS NOT NULL AND NOT EXISTS (SELECT * FROM user AS u WHERE u.column1 = b.column1)
UNION ALL
SELECT DISTINCT title, version
FROM book2 AS b2
WHERE b.title IS NOT NULL AND EXISTS (SELECT * FROM user AS u WHERE u.column2 = b.column1)
) c )
"*" is never advisable as it accounts for all unnecessary details too.

In a left join, select row with value A, if not select row with value B

This must be simple, but I think I'm lost. I have a table A:
name id
Tom 1
Barbara 2
Gregory 3
...and table B:
id nickname preferred
1 Spiderman 0
1 Batman 1
2 Powerpuff 0
3 Donald Duck 0
3 Hulk 1
How do I query the table to get a nickname when it is preferred (1), or any other nickname if preferred is not available.
So the result for Tom would be "Batman", while the result for Barbara would be "Powerpuff".
Just an immediate solution:
select a.id,
b.nickname
from a
join b on a.id = b.id and b.prefered = 1
union all
select a.id,
b.nickname
from a
join b on a.id = b.id and b.prefered = 0
where a.id not in(
select a.id
from a
join b on a.id = b.id and b.prefered = 1
)
Fiddle http://sqlfiddle.com/#!7/0b7db/1
Try below Query:
Which 1. selects row with value A, otherwise, 2. select row with value B
using LEFT JOIN,
SELECT A.name, B.nickname
FROM A
LEFT JOIN
(
SELECT MAX(preferred) AS preferred, id
FROM B
GROUP BY id
)AS B1
ON A.id = B1.id
LEFT JOIN B ON B.preferred = B1.preferred AND B.id = B1.id
If SQLite supported analytic functions then that would provide a fairly clean and convenient solution. No such luck, though. It does simplify the problem that you want either all the preferred nicknames for a given person (of which there will be at most one) or all the non-preferred ones. It is then fairly straightforward to use an inline view to distinguish between those cases and apply a suitable filter:
SELECT p.name, pn.nickname
FROM
person p
JOIN (
SELECT id, MAX(preferred) AS preferred
FROM person_nickname
GROUP BY id
) flag
ON p.id = flag.id
JOIN person_nickname pn
ON pn.id = flag.id AND pn.preferred = flag.preferred

SQL Query, how to return elements not in other 2 tables

here is my data
movies table:
id title
10 Promise Land
13 Alive
14 Bruce Almighty
15 Decay
19 Malcom X
users table:
id username
1 Franck
2 Matt
archive table:
userid movieid
1 13
2 14
1 14
I'd like to get all the movies.id, movies.title that are not in the archive table for user id = 1.
I want to use JOINS (I don't want a select of select)
result should be:
id title
10 Promise Land
15 Decay
19 Malcom X
the following SQL fails:
SELECT a.id,a.title
FROM db.movies AS a
LEFT JOIN db.archive AS b ON a.id = b.movieid
LEFT JOIN db.users AS c ON c.id = b.userid
WHERE b.movieid IS NULL OR b.userid !=1;
Thanks
Using JOINS. You put the userid filter into the JOIN
SELECT
a.id,a.title
FROM
binews.movies AS a
LEFT JOIN
binews.archive AS b ON a.id = b.movieid AND b.userid <> 1
WHERE
b.movieid IS NULL;
However, you are actually asking "give my movies where they don't exists for this user in the archive table)
SELECT
a.id,a.title
FROM
binews.movies AS a
WHERE
NOT EXISTS (SELECT *
FROM
binews.archive AS b
WHERE
a.id = b.movieid AND b.userid <> 1);
This is more correct generally. In some cases you'll get multiple rows from a LEFT JOIN where a userid has used the same more than once. To correct this, you'll need DISTINCT which adds processing.
However, EXISTS removes this multiple row output.
See this for more: http://explainextended.com/2009/09/15/not-in-vs-not-exists-vs-left-join-is-null-sql-server/
In SQLServer2005+ you can use option with EXISTS and EXCEPT operators
SELECT *
FROM dbo.movies
WHERE EXISTS (
SELECT id
EXCEPT
SELECT movieid
FROM archive
WHERE userid = 1
)
Demo on SQLFiddle
OR option with NOT EXISTS AND INTERSECT operators
SELECT *
FROM dbo.movies
WHERE NOT EXISTS (
SELECT movieid
FROM archive
WHERE userid = 1
INTERSECT
SELECT id
)
Demo on SQLFiddle
select * from binews.movies
where id not in(select movieid from binews.archive where userid<>1 )
thanks to gbn. here is the solution with a correction "AND b.userid=1"
SELECT
a.id,a.title
FROM
binews.movies AS a
LEFT JOIN
binews.archive AS b ON a.id = b.movieid AND b.userid=1
WHERE
b.movieid IS NULL

selecting qualified records from a group

There are 2 tables. 1 is the primary table and the other has a 1 to many relationship with the primary table. The table with the many relationship has a field that is being used as a flag. So it usually have a value of Y or null.
So I'd like to select rows from the primary table that has records in the 2nd table only if all the rows on the 2nd table has a Y in its field. In other wards, if the Y field has a null or some other value, they don't qualify.
So the logic is if all rows have a Y than, OK, if some rows have yes and some do not have Y, than they don't qualify in the selection.
Hope that's clear.
Thank you.
Something like this should do the trick...
SELECT p.Field
FROM PrimaryTable p
WHERE NOT EXISTS(SELECT * FROM SecondaryTable s WHERE p.ID = s.ID AND (s.Flag <> 'Y' OR s.Flag IS NULL))
I've assumed that either there will always be a record in SecondaryTable for a given PrimaryTable record....OR, if not, then you still want the primary record returned.
SELECT
p.*
FROM
PrimaryTable p,
( select s.ID,
count(*) AllRecs,
sum( case when S.Flag = 'Y' then 1 else 0 end ) as YesRecCount
from
SecondaryTable s
group by
s.ID
having
AllRecs = YesRecCount ) squalified
WHERE
p.ID = squalified.ID
select p.*
from primary_table p
inner join secondary_table s
on p.join_key = s.join_key
and s.flag = 'Y'
where not exists(select null from secondary_table s2 where s2.join_key = p.join_key and (s2.flag is null or s2.flag <> 'Y'))