SQL IN query from multiple tables - sql

SELECT DISTINCT addresses.email FROM addresses
WHERE addresses.user_id IN (SELECT user_group.id_user_groups FROM user_group
WHERE id_group_groups IN (SELECT news_group.groupid_newsg FROM news_group
WHERE newsid_news_good=1))
The above mentioned SQL query is not executing! It gets hanged until I stop the query. I have tried SQL operator "UNION" after first SELECT statement, but it displays all the email addresses which does not belong to a group. I want to select only those email addresses of the users who belong to "id_group_groups =5" (pls see the query below ) and are subscribed to "newsid_news_good=1".
The following query runs perfectly fine:
SELECT DISTINCT addresses.email FROM addresses
WHERE addresses.user_id IN (SELECT user_group.id_user_groups FROM user_group
WHERE id_group_groups =5 )
Does anybody have an idea what is the problem with the first query? Help will be strongly appreciated!

I think the sub selects complicate your problem. If I understand it right, it would be easier to solver your problem using joins instead of sub selects.
Try out something like this:
SELECT DISTINCT addresses.email
FROM addresses
JOIN user_group
ON user_group.id_user_groups = adresses.USER_ID
JOIN news_group
ON news_group.groupid_newsg = user_group.id_group_groups
WHERE newsid_news_good = 1

SELECT DISTINCT addresses.email FROM addresses
INNER JOIN (
SELECT user_group.id_user_groups FROM user_group
INNER JOIN news_group
ON news_group.groupid_newsg = id_group_groups
WHERE newsid_news_good=1
)
ON user_group.id_user_groups = addresses.user_id

You want to use joins. The subqueries you are using are most likely the cause of your performance woes.
SELECT DISTINCT a.email
FROM addresses a
INNER JOIN user_group u ON u.id_user_groups AND u.id_group_groups = 5
INNER JOIN news_group n ON n.groupid_newsg = u.id_group_groups AND n.newsid_news_good = 1

I'm going to guess that you are using MySQL, because it does a really poor job of executing subqueries in unions. The canonical way to fix this is to change them to exists with correlated subqueries:
SELECT DISTINCT a.email
FROM addresses a
where exists (select 1
from user_group ug
where ug.id_user_groups = a.user_id and
exists (select 1
from news_group ng
where ng.newsid_news_good = 1 and
ng.groupid_news = ug.id_group_groups
)
)
This solution works in all databases, of course; it is much more efficient in MySQL. Assuming email is not repeated in the addresses table, then you can drop the outer distinct.
The alternatives with join are also feasible. However they require the distinct.

Related

SQL join count and select query

I have two tables, one is a list of 'gangs' and one is a list of 'gang_members' the gang_members.gang_id refers to the gang.id they are in, I know how to count all the members in one gang, but I need to join the following queries into one:
SELECT * FROM gangs LIMIT 8
SELECT count(gang_id) FROM gangs_members WHERE gang_id = <GANG ID>
I think this is possible, I could do it in a loop while it's going through the gangs but that would be inefficient
SELECT A.*, B.RC
FROM gangs A
LEFT JOIN (SELECT gang_id, COUNT(*) AS RC FROM gangs_members GROUP BY gang_id) B ON A.gang_id=B.gang_id
Probably something like this
SELECT count(gang_id)
FROM gangs_members
WHERE gang_id IN (SELECT gang_id FROM gangs LIMIT 8)

SQL: Issue with WHERE Clause

SELECT DISTINCT Interests.Interest_name, Impressions.Count
FROM Interests
WHERE Vertical_name = 'Retail'
INNER JOIN Impressions ON Interests.Interest_Name = Impressions.Interest_Name;
The above query generates the error
Lookup Error - SQL Server Database Error: Incorrect syntax near the keyword 'Inner'.
If I remove the WHERE clause it works perfectly OK. I am not sure if there is an issue with the syntax?
WHERE condition needs to go after joins, try to move it to the end:
SELECT DISTINCT Interests.Interest_name,Impressions.Count FROM Interests
Inner Join Impressions ON Interests.Interest_Name = Impressions.Interest_Name
WHERE Vertical_name = 'Retail';
Well the Syntax is just wrong. You have to move the WHERE after your JOIN
For example:
SELECT DISTINCT Interests.Interest_name,Impressions.Count
FROM Interests
INNER JOIN Impressions
ON Interests.Interest_Name = Impressions.Interest_Name
WHERE Vertical_name = 'Retail';
If you tried to pre-filter your table Interests you can do that this way:
SELECT DISTINCT Interests.Interest_name,Impressions.Count
FROM (
SELECT *
FROM Interests
WHERE Vertical_name = 'Retail'
) as Interests
INNER JOIN Impressions
ON Interests.Interest_Name = Impressions.Interest_Name;
Just a hint after all. I would suggest you, to use aliases for every table. It will improve the reading and will save you if you need to rename a table.
The where goes after the from clause. And join is part of the from clause.
Your query would be easier to write and to read with aliases:
SELECT DISTINCT i.Interest_name, i.Count
FROM Interests i Inner Join
Impressions im
ON i.Interest_Name = im.Interest_Name;
WHERE Vertical_name = 'Retail';
If you don't need the DISTINCT, then you should remove it. It only hurts performance.
In fact, a better way to write this query is to use a correlated subquery:
SELECT DISTINCT i.Interest_name, i.Count
FROM Interests i
WHERE EXISTS (SELECT 1
FROM Impressions im
WHERE i.Interest_Name = im.Interest_Name
)
WHERE i.Vertical_name = 'Retail';
This assumes that Vertical_Name is in Interests. Otherwise, it would go in the subquery.

Opposite of UNION SQL Query

I have 2 tables :
interests (storing the interest ID and name)
person_interests(storing the person_id and interest_id)
How do I select all the interests that a particular person has not selected?
I have tried the following SQL Query and am still not getting the desired result
SELECT *
FROM interests LEFT JOIN person_interests
ON interests.id=person_interests.person_id
WHERE person_interests.id IS NULL
AND person_id=66;
Use NOT EXISTS
SELECT *
FROM interests
WHERE NOT EXISTS (
SELECT person_interests.interest_id
FROM person_interests
WHERE person_id = 66
AND interests.id = person_interests.interest_id
)
SELECT * from interests
WHERE interest_id NOT IN
(SELECT interest_id FROM person_interests WHERE person_id=66)
There are a couple things going on.
First, I think you have an error in your join. Shouldn't it be interests.id=person_interests.interest_id instead of interests.id=person_interests.person_id?
That aside, I still don't think you would be getting the desired result because your person_id filter is on the RIGHT side of your LEFT OUTER join, thus turning it back into an inner join. There are several ways to solve this. Here's what I would probably do:
SELECT *
FROM
(SELECT interests.*, person_id
FROM interests LEFT JOIN person_interests
ON interests.id=person_interests.interest_id
WHERE person_interests.id IS NULL )
WHERE person_id=66;

SQL join two queries

I am a bit lost here. I would like to join these two queries into one to avoid two connections and simplify the code.
"SELECT uname FROM Projects WHERE id IN (SELECT MAX(id) FROM Projects)"
"SELECT name FROM Users WHERE username like"+"'"+ uname +"'"
Right now I am using two queries and taking the result of the first into the second one.
I am sure the two queries can become one but I do not know how to do it.
You can simply use = rather than LIKE since I you are not using pattern symbol such as %.
SELECT a.name
FROM Users a
INNER JOIN Projects b
ON a.username = b.uname
WHERE b.ID = (SELECT MAX(id) FROM Projects)
i think the following query will work:
SELECT name FROM Users WHERE username in
(SELECT uname FROM Projects WHERE id IN
(SELECT MAX(id) FROM Projects))
You may try like this using the INNER JOIN considering that both of your tables are linked through User_ID
SELECT u.name
FROM Users u INNER JOIN Projects p ON u.username = p.uname
WHERE p.ID = (SELECT MAX(id) FROM Projects)

Update using Distinct SUM

I have found a few good resources that show I should be able to merge a select query with an update, but I just can't get my head around of the correct formatting.
I have a select statement that is getting info for me, and I want to pretty much use those results to Update an account table that matches the accountID in the select query.
Here is the select statement:
SELECT DISTINCT SUM(b.workers)*tt.mealTax as MealCost,b.townID,b.accountID
FROM buildings AS b
INNER JOIN town_tax AS tt ON tt.townID = b.townID
GROUP BY b.townID,b.accountID
So in short I want the above query to be merged with:
UPDATE accounts AS a
SET a.wealth = a.wealth - MealCost
Where MealCost is the result from the select query. I am sure there is a way to put this into one, I just haven't quite been able to connect the dots to get it to run consistently without separating into two queries.
First, you don't need the distinct when you have a group by.
Second, how do you intend to link the two results? The SELECT query is returning multiple rows per account (one for each town). Presumably, the accounts table has only one row. Let's say that you wanted the average MealCost for the update.
The select query to get this is:
SELECT accountID, avg(MealCost) as avg_Mealcost
FROM (SELECT SUM(b.workers)*tt.mealTax as MealCost, b.townID, b.accountID
FROM buildings AS b INNER JOIN
town_tax AS tt
ON tt.townID = b.townID
GROUP BY b.townID,b.accountID
) a
GROUP BY accountID
Now, to put this into an update, you can use syntax like the following:
UPDATE accounts
set accounts.wealth = accounts.wealth + asum.avg_mealcost
from (SELECT accountID, avg(MealCost) as avg_Mealcost
FROM (SELECT SUM(b.workers)*tt.mealTax as MealCost, b.townID, b.accountID
FROM buildings AS b INNER JOIN
town_tax AS tt
ON tt.townID = b.townID
GROUP BY b.townID,b.accountID
) a
GROUP BY accountID
) asum
where accounts.accountid = asum.accountid
This uses SQL Server syntax, which I believe is the same as for Oracle and most other databases. Mysql puts the "from" clause before the "set" and allows an alias on "update accounts".