Select Count take too long to be executed - sql

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.

Related

SQL Query check if ID is part of another table

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

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 joining two tables with common row

I have 2 tables in sybase
Account_table
Id account_code
1 A
2 B
3 C
Associate_table
id account_code
1 A
1 B
1 C
2 A
2 B
3 A
3 C
I have this sql query
SELECT * FROM account_table account, associate_table assoc
WHERE account.account_code = assoc.account_code
This query will return 7 rows. What I want is to return the rows from associate_table that is only common to the 3 accounts like this:
account id account_code Assoc Id
1 A 1
2 B 1
3 C 1
Can anyone help what kind of join should I do?
SELECT b.id account_id,a.code account_code,a.id assoc_id
FROM associate a,
account b
WHERE a.code = b.code
AND a.id IN (SELECT a.id
FROM associate a,
account b
WHERE a.code = b.code
GROUP BY a.id
HAVING Count(*) = (SELECT Count(*)
FROM account));
NOTE: this query works only if you have unique values in Id and account_code columns in account table. And also, your associate_table should contain unique combination of (id, account,code). i.e., associate table should not contain (1,A) or any pair twice.
Try this
SELECT AC.ID,AC.account_code,ASS.ID
FROM account_table AC INNER JOIN associate_table AS ASS ON AC.account_code = ASS.account_code
OK so far answer is accepted I'll post simpler one:
SELECT *
FROM account_table AS account,
associate_table AS assoc
WHERE account.account_code = assoc.account_code
HAVING (
SELECT
COUNT(*)
FROM associate_table assoc_2
WHERE assoc_2.id = assoc.id
) = 3
here 3 is the number of codes account table has, if it's gonna be dynamic (changing over time),
you can use (SELECT COUNT(*) FROM account_table) instead of exact number. Also I'm sure it will be cached by database engine, so requires less resources

how use distinct in second join table in sql server

I have a SQL table consists of id, name, email,.... I have another SQL table that has id, email, emailstatus but these 2 id are different they are not related. The only thing that is common between these 2 tables are emails.
I would like to join these 2 tables bring all the info from table1 and if the email address from table 1 and table 2 are same and emailstatus is 'Bounced'. But the query that I am writing gives me more record than I expected because there are multiple rows in tbl_webhook(second table) for each row in Applicant(first table) .I want to know if applicant has EVER had an email bounce.
Query without join shows 23000 record but after join shows 42000 record that is because of duplicate how I can keep same 23000 record only add info from second table?
This is my query:
SELECT
A.[Id]
,A.[Application]
,A.[Loan]
,A.[Firstname]
,A.[Lastname]
,A.[Email],
,H.[Email], H.[EmailStatus] as BouncedEmail
FROM Applicant A (NOLOCK)
left outer join [tbl_Webhook] [H] (NOLOCK)
on A.Email = H.Email
and H.[event]='bounced'
this is sample of desired data:
id email name emailFromTable2 emailstatus
1 test2#yahoo.com lili test2#yahoo.com bounced
2 tesere#yahoo.com mike Null Null
3 tedfd2#yahoo.com nik tedfd2#yahoo.com bounced
4 tdfdft2#yahoo.com sam Null Null
5 tedft2#yahoo.com james tedft2#yahoo.com bounced
6 tedft2#yahoo.com San Null
Use a nested select for this type of query. I would write this as:
select id, application, load, firstname, lastname, email,
(case when BouncedEmail is not null then email end) as EmailFromTable2,
BouncedEmail
from (SELECT A.[Id], A.[Application], A.[Loan], A.[Firstname], A.[Lastname], A.[Email],
(case when exists (select 1
from tbl_WebHook h
where A.Email = H.Email and H.[event] = 'bounced'
)
then 'bounced
end) as BouncedEmail
FROM Applicant A (NOLOCK)
) a
You can also do this with cross apply, but because you only really need one column, a correlated subquery also works.
;WITH DistinctEmails
AS
(
SELECT * , rn = ROW_NUMBER() OVER (PARTITION BY [Email] ORDER BY [Email])
FROM [tbl_Webhook]
)
SELECT
A.[Id]
,A.[Application]
,A.[Loan]
,A.[Firstname]
,A.[Lastname]
,A.[Email],
,H.[Email], H.[EmailStatus] as BouncedEmail
FROM Applicant A (NOLOCK) left outer join DistinctEmails [H] (NOLOCK)
on A.Email = H.Email
WHERE H.rn = 1
and H.[event]='bounced'
i believe query below should be enough to select distinct bounced email for you, cheer :)
SELECT
A.[Id]
,A.[Application]
,A.[Loan]
,A.[Firstname]
,A.[Lastname]
,A.[Email],
,H.[Email], H.[EmailStatus] as BouncedEmail
FROM Applicant A (NOLOCK)
Inner join [tbl_Webhook] [H] (NOLOCK)
on A.Email = H.Email
and H.[EmailStatus]='bounced'
basically i just change the joining to inner join and change the 2nd table condition from event to emailstatus, if u can provide your table structure and sample data i believe i can help you up :)

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