SQL: Issue with WHERE Clause - sql

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.

Related

Where clause applied to only one column in join

I'm having some trouble with writing a certain SQL query. I have a wallet and a balance which I do join. The query now looks like that:
SELECT
`balances`.`id` AS `id`,
FROM
`wallet`
LEFT JOIN `balances` ON
( `wallet`.`currency` = `balances`.`currency` )
WHERE
`balances`.`user_id` = '181'
Because of the where clause, the query returns just matching records. I want to get all records from wallets table and only those from balances which do match where clause... hope I explained it well enough!
Cheers!
use subquery
SELECT w.*,t.*
FROM
wallet w
LEFT JOIN ( select * from balances where user_id = 181
) t ON w.currency =t.currency
Issue is you are applying filter on left join table wallets.
use below query.
SELECT
`balances`.`id` AS `id`,
FROM
`wallet`
LEFT JOIN (select * from `balances` `user_id` = '181') ON
( `wallet`.`currency` = `balances`.`currency` );
The question is not fully clear, but you almost definitely need an extra join clause on some sort of ID. Now there is no way to match a wallet with its balance(s). Assuming that balance have eg. a wallet_id, you'll want something like:
SELECT
`balances`.`id` AS `id`,
FROM
`wallet`
LEFT JOIN `balances` ON
(`wallet`.`id` = `balance`.`wallet_id` )
WHERE
`balances`.`user_id` = '181'
Move the condition to the ON clause. Don't use subqueries!
SELECT w.*, b.id
FROM wallet w LEFT JOIN
balances b
ON w.currency = b.currency AND
b.user_id = 181;
Notes:
The subquery in the FROM can impede the optimizer.
If you are using a LEFT JOIN, you should be selecting columns from the first table.
I am guessing that user_id is a number, so I removed the quotes around the comparison value.
Table aliases make the query easier to write and to read.
Backticks make the query harder to write and harder to read.

AS being ignored in a subquery

Still learning SQL here... I have part of a subquery:
(Select MAX(cost) AS Cost_of_Car FROM Car_Purchase)
But it does not take my label just uses the one from the table, in this case "cost"
Any ideas?
EDIT: Just realized I could in my SELECT statement call out AS "NAME OF COLUMN", but why does it not accept AS in the subquery?
POSTING FULL QUERY
SELECT CAR.name, Car_Purchase.cost_per_night, Car_Purchase.description
FROM Car_Purchase
JOIN CAR ON Car_Purchase.purchase_id = CAR.purchase_id
GROUP BY CAR.name, Car_Purchase.cost_per_night, Car_Purchase.description
HAVING Car_Purchase.cost = (SELECT MAX(cost) AS Cost_of_Car FROM Car_Purchase)
The AS keyword is not being ignored.
You're using subquery in where clause. Remember, where clause is used for filtering the query result, not for displaying the data.
If you want to see how AS work in subquery, try this:
SELECT CAR.name, Car_Purchase.cost_per_night, Car_Purchase.description, Cost_of_Car
FROM Car_Purchase
JOIN CAR ON Car_Purchase.purchase_id = CAR.purchase_id
join (SELECT MAX(cost) AS Cost_of_Car FROM Car_Purchase) subquery
ON Car_Purchase.cost = subquery.Cost_of_Car
GROUP BY CAR.name, Car_Purchase.cost_per_night, Car_Purchase.description
In this query, I put the subquery in from clause. So your query result now have Cost_of_Car column and you can display it in select clause.
In fact, since, as noted by others the Max(Cost) is not being used elsewhere in the query, you don't need to alias it at all. And since you don't have a aggregate function anywhere in the sql it does not need to be a group By query
Select cp.name, cp.Cost CostOfCar,
cp.cost_per_night, cp.description
From Car_Purchase cp Join Car c
On c.purchase_id = cp.purchase_id
Where cp.cost = (SELECT MAX(cost) FROM Car_Purchase)
Is sufficient and should work

SQL IN query from multiple tables

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.

Is this a valid SQL query?

This is just an example, I'm doing something similar that is going to grab thousands of records.
SELECT * FROM
(SELECT * FROM zoodb) As TblA
INNER JOIN
(SELECT animal_ID, Max(checkup_year) AS latest_checkup FROM TblA GROUP BY animal_ID) as TblB
ON (TblA.animal_ID = TblB.animal_ID) AND (TblA.checkup_year = TblB.latest_checkup)
Basically in this, I want to grab the records only for the latest checkup year
Your query is not valid.
But you can do it this way:
SELECT * FROM zoodb z
INNER JOIN (SELECT animal_ID, Max(checkup_year) AS latest_checkup
FROM zoodb
GROUP BY animal_ID) aux ON aux.animal_ID = z.animal_ID AND aux.latest_checkup = z.checkup_year
SELECT * FROM
(SELECT * FROM zoodb) As TblA
....
There is no need for this sub query. The FROM in the outer query can handle it!
SELECT *
FROM zoodb AS TblA
...
The rest looks fine!
Edit:
As aF pointed out you cannot reference TblA from the inner join subquery (See aF's answer).
aF.'s answer is correct, but I thought I'd propose a solution that expresses your intention a little more clearly:
select *
from zoodb as TblA
where latest_checkup = (
select max(latest_checkup)
from zoodb
where animal_id = TblA.animal_id);
The lack of the [inner join (subselect)] also means that it won't get too messy if you need to add additional constraints in the future.
Also the query optimizer prefers inner joins to nested select statements, so you'll get a more optional execution plan

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".