Where clause applied to only one column in join - sql

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.

Related

SQL query returning more than one result

This is my SQL query
SELECT
room.*, reservation.rn, reservation.cin
FROM
room, reservation
But it is returning 4 instances of each row.
I just want to get the corresponding reservation from another table where they have same room number and at the same time display the remaining rooms
Room Table
Id,r_num,r_price,in_date,out_date
reservation_table
id,r_num,cIn,cOut
You have a cross join between the two tables as there is no join condition.
Assuming the reservation table has room_id FK which references id from room table, you can join like this:
select r.*,
s.rn,
s.cin
from room r
join reservation s on r.id = s.room_id
Always use proper explicit join syntax instead of comma based joins.
Your select statement results in a cross join / cartesian product.
Use a WHERE-clause!
SELECT room.*,reservation.rn,reservation.cin FROM room,reservation WHERE room.room_no = reservation.room_no
For more complicated joins I recommend using an explicit syntax with the appropriate keywords, although your implicit join is perfectly fine for this case (and performance wise implicit and explicit joins are the same).
To display unreserved rooms as well (so to keep results that do not satisfy the where-clause) you'll have to use an OUTER JOIN (LEFT or RIGHT depending on what you want to keep) like this:
SELECT room.*,reservation.rn,reservation.cin
FROM room LEFT OUTER JOIN reservation
ON room.room_no = reservation.room_no
For the first part you need a join and for second condition you need union :
select r.Id,r.r_num,r.r_price,r.in_date,r.out_date,s.id as resId,s.r_num,s.cIn,s.cOut
from room r
join reservation s on r. r_num = s. r_num
union
select r.Id,r.r_num,r.r_price,r.in_date,r.out_date,null as resId, null as r_num, null as cIn,null as cOut
from room r
where r.in_date is null
union by default distinct the result if you need repeated rows just use UNION ALL

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.

sql multiple count

I have 3 tables, where the first one's primary key, is the foreign key in the other 2.
I want to extract one field from the first table, and then a count from the other 2, all joined using the pk and fk. This is what I have so far:
SELECT MBDDX_STUDY.STUDY_NAME, COUNT(MBDDX_EXPERIMENT.STUDY_ID) AS NUMBER_OF_EXPERIMENTS
FROM MBDDX_STUDY
INNER JOIN MBDDX_EXPERIMENT
ON MBDDX_STUDY.ID=MBDDX_EXPERIMENT.STUDY_ID
INNER JOIN (SELECT COUNT(MBDDX_TREATMENT_GROUP.GROUP_NO) AS NUMBER_OF_GROUPS
FROM MBDDX_TREATMENT_GROUP)
ON MBDDX_TREATMENT_GROUP.STUDY_ID = MBDDX_STUDY.ID
group by MBDDX_STUDY.STUDY_NAME, MBDDX_TREATMENT_GROUP.STUDY_ID
But, i get an error saying that the MBDDX_TREATMENT_GROUP.STUDY_ID , in the penultimate line is an invalid indentifier. It is a correct table.
Any advise please.
Thanks.
You're getting the error because that column is not in your SELECT, so it can't GROUP BY a field it doesn't have.
The subquery syntax doesn't seem to make any sense to me. You've made a query that counts all rows of MBDDX_TREATMENT_GROUP, independently of the STUDY_ID, and then tries to join it into the table with a join condition that doesn't refer to anything in the subquery's results (and can't, without an alias).
Why not use a simple join? Assuming MBDDX_EXPERIMENT also has a primary key ID, you can do it with a COUNT-DISTINCT:
SELECT
MBDDX_STUDY.ID, MBDDX_STUDY.STUDY_NAME,
COUNT(DISTINCT MBDDX_EXPERIMENT.ID) AS NUMBER_OF_EXPERIMENTS
COUNT(DISTINCT MBDDX_TREATMENT_GROUP.GROUP_NO) AS NUMBER_OF_GROUPS
FROM
MBDDX_STUDY
INNER JOIN MBDDX_EXPERIMENT ON MBDDX_EXPERIMENT.STUDY_ID=MBDDX_STUDY.ID
INNER JOIN MBDDX_TREATMENT_GROUP ON MBDDX_TREATMENT_GROUP.STUDY_ID=MBDDX_STUDY.ID
GROUP BY
MBDDX_STUDY.ID, MBDDX_STUDY.STUDY_NAME
(MBDDX_STUDY.STUDY_NAME technically shouldn't be necessary to include in the GROUP BY expression according to ANSI SQL as it has a functional dependency on STUDY_ID. However it is necessary on Oracle, which can't spot the dependency.)
You don't need to group by this field (MBDDX_TREATMENT_GROUP.STUDY_ID). It should be just group by MBDDX_STUDY.STUDY_NAME
If my understanding is correct,You need a record from first table and have the count of related records in the other two tables.Here is the answer
SQL:Getting count from many tables for a user record in USER table.Whats the best approach?
It looks like you need to alias the second subquery and need to include something to join on.
It also looks like you aren't using the count you have in the subquery as well.
Try this out:
SELECT MBDDX_STUDY.STUDY_NAME
, COUNT(MBDDX_EXPERIMENT.STUDY_ID) AS NUMBER_OF_EXPERIMENTS
FROM MBDDX_STUDY
INNER JOIN MBDDX_EXPERIMENT
ON MBDDX_STUDY.ID=MBDDX_EXPERIMENT.STUDY_ID
INNER JOIN (SELECT STUDY_ID, COUNT(MBDDX_TREATMENT_GROUP.GROUP_NO) AS NUMBER_OF_GROUPS
FROM MBDDX_TREATMENT_GROUP GROUP BY MBDDX_TREATMENT_GROUP.STUDY_ID) xx
ON xx.STUDY_ID = MBDDX_STUDY.ID
GROUP BY MBDDX_STUDY.STUDY_NAME, xx.STUDY_ID
For what you really want to do, you want OUTER JOINs.
WITH number_of_experiments
AS ( SELECT study_id
, count ( * ) CNT
FROM MBDDX_EXPERIMENT
group by study_id )
, number_of_groups
as ( select study_id
, count ( * ) CNT
FROM mbddx_treatment_group
group by study_id )
select study_name
, coalesce(noex.cnt,0)
, coalesce(notr.cnt,0)
from mbddx_study
outer join number_of_experiments
as noex
using ( study_id )
outer join number_of_groups
as nogr
using ( study_id )

MYSQL join - reference external field from nested select?

Is it allowed to reference external field from nested select?
E.g.
SELECT
FROM ext1
LEFT JOIN (SELECT * FROM int2 WHERE int2.id = ext1.some_id ) as x ON 1=1
in this case, this is referencing ext1.some_id in nested select.
I am getting errors in this case that field ext1.some_id is unknow.
Is it possible? Is there some other way?
UPDATE:
Unfortunately, I have to use nested select, since I am going to add more conditions to it, such as LIMIT 0,1
and then I need to use a second join on the same table with LIMIT 1,1 (to join another row)
The ultimate goal is to join 2 rows from the same table as if these were two tables
So I am kind of going to "spread" a few related rows into one long row.
The answer to your initial question is: No, remove your sub-query and put the condition into the ON-clause:
SELECT *
FROM ext1
LEFT JOIN int2 ON ( int2.id = ext1.some_id )
One solution could be to use variables to find the first (or second) row, but this solution would not work efficiently with indexes, so you might end up with performance problems.
SELECT ext1.some_id, int2x.order_col, int2x.something_else
FROM ext1
LEFT JOIN (SELECT `int2`.*, #i:=IF(#id=(#id:=id), #i+1, 0) As rank
FROM `int2`,
( SELECT #i:=0, #id:=-1 ) v
ORDER BY id, order_col ) AS int2x ON ( int2x.id = ext1.some_id
AND int2x.rank = 0 )
;
This assumes that you have a column that you want to order by (order_col) and Left Joins the first row per some_id.
Do you mean this?
SELECT ...
FROM ext1
LEFT JOIN int2 ON int2.id=ext1.some_id
That's what the ON clause is for:
SELECT
FROM ext1
LEFT JOIN int2 AS x ON x.id = ext1.some_id

How do I use T-SQL's Exists keyword?

I have a query I want to run as a subquery that will return a set of FK's. With them I want to return only rows that has a matching key.
Subquery:
SELECT ID
FROM tblTenantTransCode
WHERE
tblTenantTransCode.CheckbookCode =
(SELECT ID FROM tblCheckbookCode WHERE Description = 'Rent Income')
That will return all the transaction codes that have a checkbook code that matches Rent Income
Now I want to select All Transactions where their transactioncode matches an ID returned in the subquery. I've gotten this far, but SQL Server complains of a syntax error. How can I do this?
Full Query:
SELECT *
FROM tblTransaction
WHERE
tblTransaction.TransactionCode IN
(SELECT ID FROM tblTenantTransCode
WHERE tblTenantTransCode.CheckbookCode =
(SELECT ID FROM tblCheckbookCode WHERE Description = 'Rent Income'))
Tables:
tblCheckbookCode
ID
Description
Other Info
tblTenantTransCode
ID
CheckbookCode <-- fk we're looking for
in the tblCheckbookCode.
We're selecting only checkbook codes
that have the Description 'Rent Income'
Other Info
tblTransactions
ID
TransactionCode <-- fk to tenant transaction code.
We're looking for an ID that is returned
in the above query/join
To answer your question about using the EXISTS keyword, here is an example query that uses an EXISTS predicate, based on the query as currently given in your question.
SELECT t.*
FROM tblTransaction t
WHERE EXISTS
(
SELECT 1
FROM tblTenantTransCode ttc
JOIN tblCheckbookCode cc
ON (cc.ID = ttc.CheckbookCode AND cc.Description='Rent Income')
WHERE ttc.ID = t.TransactionCode
)
Additional Details:
We all recognize that there are a variety of SQL statements that will return the result set that meets the specified requirements. And there are likely going to be differences in the observed performance of those queries. Performance is particularly dependent on the DBMS, the optimizer mode, the query plan, and the statistics (number of rows and data value distribution).
One advantage of the EXISTS is that it makes clear that we aren't interested returning any expressions from tables in the subquery. It serves to logically separate the subquery from the outer query, in a way that a JOIN does not.
Another advantage of using EXISTS is that avoids returning duplicate rows that would be (might be) returned if we were to instead use a JOIN.
An EXISTS predicate can be used to test for the existence of any related row in a child table, without requiring a join. As an example, the following query returns a set of all orders that have at least one associated line_item:
SELECT o.*
FROM order o
WHERE EXISTS
( SELECT 1
FROM line_item li
WHERE li.order_id = o.id
)
Note that the subquery doesn't need to find ALL matching line items, it only needs to find one row in order to satisfy the condition. (If we were to write this query as a JOIN, then we would return duplicate rows whenever an order had more than one line item.)
A NOT EXISTS predicate is also useful, for example, to return a set of orders that do not have any associated line_items.
SELECT o.*
FROM order o
WHERE NOT EXISTS
( SELECT 1
FROM line_item li
WHERE li.order_id = o.id
)
Of course, NOT EXISTS is just one alternative. An equivalent result set could be obtained using an OUTER join and an IS NULL test (assuming we have at least one expression available from the line_item table that is NOT NULL)
SELECT o.*
FROM order o
LEFT
JOIN line_item li ON (li.order_id = o.id)
WHERE li.id IS NULL
There seems to be a lot of discussion (relating to answers to the original question) about needing to use an IN predicate, or needing to use a JOIN.
Those constructs are alternatives, but aren't necessary. The required result set can be returned by a query without using an IN and without using a JOIN. The result set can be returned with a query that uses an EXISTS predicate. (Note that the title of the OP question did ask about how to use the EXISTS keyword.)
Here is another alternative query (this is not my first choice), but the result set returned does satisfy the specified requirements:
SELECT t.*
FROM tblTransaction t
WHERE EXISTS
(
SELECT 1
FROM tblTenantTransCode ttc
WHERE ttc.ID = t.TransactionCode
AND EXISTS
(
SELECT 1
FROM tblCheckbookCode cc
WHERE cc.ID = ttc.CheckbookCode
AND cc.Description = 'Rent Income'
)
)
Of primary importance, the query should return a correct result set, one that satisfies the specified requirements, given all possible sets of conditions.
Some of the queries presented as answers here do NOT return the requested result set, or if they do, they happen to do so by accident. Some of the queries will work if we pre-assume something about the data, such that some columns are UNIQUE and NOT NULL.
Performance differences
Sometimes a query with an EXISTS predicate will not perform as well as a query with a JOIN or an IN predicate. In some cases, it may perform better. (With the EXISTS predicate, the subquery only has to find one row that satisfies the condition, rather than finding ALL matching rows, as would be required by a JOIN.)
Performance of various query options is best gauged by observation.
You are describing an inner join.
select tc.id
from tblTenantTransCode tc
inner join tblCheckbookCode cc on tc.CheckbookCode = cc.CheckbookCode
EDIT: It's still an inner join. I don't see any reason yet to use the IN clause.
select *
from tblTransaction t
inner join tblTenantTransCode tc on tc.id = t.TransactionCode
inner join tblCheckbookCode cc on cc.id = tc.CheckbookCode
where cc.description = 'Rent Income'
EDIT: If you must use the EXISTS predicate to solve this problem, see #spencer7953's answer. However, from what I'm seeing, the solution above is simpler and there are assumptions of uniqueness based on the fact that "Subquery" works for you (it wouldn't 100% of the time if there wasn't uniqueness in that table). I'm also addressing
Now I want to select All Transactions
where their transactioncode
matches an ID returned in the subquery
in my answer. If the request were something on the lines of this:
Now I want to select All Transcations
when any transactioncode matches an ID returned in the subquery.
I would use EXISTS to see if any transactioncode existed in the child table and return every row or none as appropriate.
Given your full query, this query will get you where you need to go using a single join.
The join filters out any transaction that doesn't have a transaction code of 'Rent Income.' It will take all record from the first table, build out the subset of the second table (that WHERE clause limits the records), and then filters the first table where those table math the join condition.
SELECT
t.*
FROM
tblTransaction t
INNER JOIN tblTenantTransCode c ON
t.TransactionCode = c.ID
INNER JOIN tblCheckbookCode chk ON
c.CheckbookCode = chk.ID
WHERE
chk.Description = 'Rent Income'
Edit: One other note: Avoid using SELECT * -- always specify the columns.
Edit Dos: I missed that there were three tables. Corrected! Thanks, spencer!
You need to use the 'IN' clause:
select id from tblTenantTransCode
where tblTenantTransCode.CheckbookCode in
(select id from tblCheckbookCode
where description = 'rent income')
an inner join would probably be a better solution though...
select ttc.id from tblTenantTransCode as ttc
inner join tblCheckbookCode as tcc
on ttc.CheckBookId = tcc.id
where tcc.description = 'rent income'
Try this:
SELECT
tblTenantTransCode.ID
FROM tblCheckbookCode
INNER JOIN tblTenantTransCode ON tblCheckbookCode.ID=tblTenantTransCode.CheckbookCode
WHERE tblCheckbookCode.Description = 'Rent Income'
Make sure you index tblCheckbookCode.Description.